Add the tap driver.

The tap driver is used to present a virtual Ethernet interface to the
system. Packets presented by the network stack to the interface are
made available to a character device in /dev. With tap and the bridge
code, you can make remote bridge configurations where both sides of
the bridge are separated by userland daemons.

This driver also has a special naming hack to allow it to serve a similar
purpose to the vmware port.

Submitted by:	myevmenkin@att.com, vsilyaev@mindspring.com
This commit is contained in:
Nick Sayer 2000-07-20 17:01:10 +00:00
parent 5f4796c0db
commit a5213f145a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=63670
6 changed files with 1149 additions and 0 deletions

View File

@ -128,6 +128,7 @@
# gsc Genius GS-4500 hand scanner
# joy pc joystick
# tun* Tunneling IP device
# tap* Ethernet Tunneling device
# snp* tty snoop devices
# spigot Video Spigot video acquisition card
# ctx* Cortex-I video acquisition card
@ -256,6 +257,7 @@ all)
sh MAKEDEV urio0 # cdev, USB devices too
sh MAKEDEV bpf0 bpf1 bpf2 bpf3 # cdev, network
sh MAKEDEV ipl tun0 tun1 tun2 tun3 # cdev, network
sh MAKEDEV tap0 tap1 tap2 tap3 # cdev, network
sh MAKEDEV ch0 perfmon tw0 # cdev, miscellaneous
sh MAKEDEV apm apmctl card0 card1 card2 card3 # cdev, laptop
sh MAKEDEV pass4 xpt2 # cdev, CAM
@ -290,6 +292,7 @@ fixit)
sh MAKEDEV smb0 # cdev, SMBus device
sh MAKEDEV ums0 # cdev, USB devices
sh MAKEDEV tun0 # cdev, network
sh MAKEDEV tap0 # cdev, network
sh MAKEDEV ch0 # cdev, miscellaneous
sh MAKEDEV apm apmctl card0 # cdev, laptop
sh MAKEDEV pass1 xpt1 # cdev, CAM
@ -1441,6 +1444,15 @@ tun*)
done
;;
tap*)
ntap=`expr $i : 'tap\(.*\)$'`
unit=0
while [ $unit -le $ntap ]; do
mknod tap$unit c 149 $unit root:network
unit=$(($unit + 1))
done
;;
sysmouse)
mknod sysmouse c 12 128
mknod consolectl c 12 255

217
share/man/man4/tap.4 Normal file
View File

@ -0,0 +1,217 @@
.\" $FreeBSD$
.\" Based on PR#2411
.\"
.Dd July 9, 2000
.Os
.Dt TAP 4
.Sh NAME
.Nm tap
.Nd Ethernet tunnel software network interface
.Sh SYNOPSIS
.Cd pseudo-device tap
.Sh DESCRIPTION
The
.Nm tap
interface is a software loopback mechanism that can be loosely
described as the network interface analog of the
.Xr pty 4 ,
that is,
.Nm tap
does for network interfaces what the
.Nm pty
driver does for terminals.
.Pp
The
.Nm tap
driver, like the
.Nm pty
driver, provides two interfaces: an interface like the usual facility
it is simulating
.Po
an Ethernet network interface in the case of
.Nm tap ,
or a terminal for
.Nm pty
.Pc ,
and a character-special device
.Dq control
interface.
.Pp
The network interfaces are named
.Sy tap Ns Ar 0 ,
.Sy tap Ns Ar 1 ,
etc, as many as were made by
.Xr MAKEDEV 8 .
Each one supports the usual Ethernet network-interface
.Xr ioctl 2 Ns s ,
such as
.Dv SIOCSIFADDR
and
.Dv SIOCSIFNETMASK ,
and thus can be used with
.Xr ifconfig 8
like any other Ethernet interface. When the system chooses to transmit
an Ethernet frame on the network interface, the frame can be read from
the control device
.Po
it appears as
.Dq input
there
.Pc ;
writing an Ethernet frame to the control device generates an input frame on
the network interface, as if the
.Pq non-existent
hardware had just received it.
.Pp
The Ethernet tunnel device, normally
.Pa /dev/tap Ns Sy N ,
is exclusive-open
.Po
it cannot be opened if it is already open
.Pc
and is restricted to the super-user.
A
.Fn read
call will return an error
.Pq Er EHOSTDOWN
if the interface is not
.Dq ready .
Once the interface is ready,
.Fn read
will return an Ethernet frame if one is available; if not, it will
either block until one is or return
.Er EWOULDBLOCK ,
depending on whether non-blocking I/O has been enabled. If the frame
is longer than is allowed for in the buffer passed to
.Fn read ,
the extra data will be silently dropped.
.Pp
A
.Xr write 2
call passes an Ethernet frame in to be
.Dq received
on the pseudo-interface. Each
.Fn write
call supplies exactly one frame; the frame length is taken from the
amount of data provided to
.Fn write .
Writes will not block; if the frame cannot be accepted
for a transient reason
.Pq e.g., no buffer space available ,
it is silently dropped; if the reason is not transient
.Pq e.g., frame too large ,
an error is returned.
The following
.Xr ioctl 2
calls are supported
.Pq defined in Aq Pa net/if_tap.h Ns :
.Bl -tag -width VMIO_SIOCSETMACADDR
.It Dv TAPSDEBUG
The argument should be a pointer to an
.Va int ;
this sets the internal debugging variable to that value. What, if
anything, this variable controls is not documented here; see the source
code.
.It Dv TAPGDEBUG
The argument should be a pointer to an
.Va int ;
this stores the internal debugging variable's value into it.
.It Dv FIONBIO
Turn non-blocking I/O for reads off or on, according as the argument
.Va int Ns 's
value is or isn't zero
.Pq Writes are always nonblocking .
.It Dv FIOASYNC
Turn asynchronous I/O for reads
.Po
i.e., generation of
.Dv SIGIO
when data is available to be read
.Pc
off or on, according as the argument
.Va int Ns 's
value is or isn't zero.
.It Dv FIONREAD
If any frames are queued to be read, store the size of the first one into the argument
.Va int ;
otherwise, store zero.
.It Dv TIOCSPGRP
Set the process group to receive
.Dv SIGIO
signals, when asynchronous I/O is enabled, to the argument
.Va int
value.
.It Dv TIOCGPGRP
Retrieve the process group value for
.Dv SIGIO
signals into the argument
.Va int
value.
.It SIOCGIFADDR
Retrieve the Media Access Control
.Pq MAC
address. This command should be executed on descriptor, associated with
control device
.Pq Pa /dev/tap Ns Sy N .
The
.Va buffer ,
which is passed as argument, is expected to have enought space to store
.Pq MAC
address.
.It SIOCSIFADDR
Set the Media Access Control
.Pq MAC
address. This command should be executed on a descriptor, associated with
control device
.Pq Pa /dev/tap Ns Sy N .
.El
.Pp
The control device also supports
.Xr select 2
for read; selecting for write is pointless, and always succeeds, since
writes are always non-blocking.
.Pp
On the last close of the data device, by default, the interface is
brought down
.Po
as if with
.Dq ifconfig tap Ns Sy N No down
.Pc .
All queued frames are thrown away. If the interface is up when the data
device is not open output frames are always thrown away rather than
letting them pile up.
.Pp
The
.Nm tap
device is also can be used with VMware port as a replacement
of VMnet device driver. The driver uses minor number to select between
.Nm tap
and
.Nm vmnet
devices. VMnet minor numbering is
.Va 0x10000
+
.Va N .
Where
.Va N
is a VMnet unit number. In this case control device is expected to be
.Pa /dev/vmnet Ns Sy N ,
and network interface will be
.Sy vmnet Ns Ar N .
Everything else is the same.
.Pp
In addition to mentioned above
.Xr ioctl 2
there are additional one for VMware port.
.Bl -tag -width VMIO_SIOCSETMACADDR
.It VMIO_SIOCSIFFLAGS
VMware
.Dv SIOCSIFFLAGS .
.El
.Sh SEE ALSO
.Xr inet 4 ,
.Xr intro 4
.\" .Sh BUGS
.Sh AUTHORS
This man page has been obtained from
.Bx Free .

View File

@ -581,6 +581,7 @@ net/if_sl.c optional sl
net/if_spppsubr.c optional sppp
net/if_stf.c count stf
net/if_tun.c optional tun
net/if_tap.c optional tap
net/if_vlan.c count vlan
net/intrq.c standard
net/net_osdep.c standard

785
sys/net/if_tap.c Normal file
View File

@ -0,0 +1,785 @@
/*
* Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BASED ON:
* -------------------------------------------------------------------------
*
* Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
* Nottingham University 1987.
*/
/*
* $FreeBSD$
* $Id: if_tap.c,v 0.19 2000/07/20 02:32:27 max Exp $
*/
#include "opt_inet.h"
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/ttycom.h>
#include <sys/uio.h>
#include <sys/vnode.h>
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/route.h>
#include <netinet/in.h>
#include <net/if_tapvar.h>
#include <net/if_tap.h>
#define CDEV_NAME "tap"
#define CDEV_MAJOR 149
#define TAPDEBUG if (tapdebug) printf
#define TAP "tap"
#define VMNET "vmnet"
#define VMNET_DEV_MASK 0x00010000
/* module */
static int tapmodevent __P((module_t, int, void *));
/* device */
static void tapcreate __P((dev_t));
/* network interface */
static void tapifstart __P((struct ifnet *));
static int tapifioctl __P((struct ifnet *, u_long, caddr_t));
static void tapifinit __P((void *));
/* character device */
static d_open_t tapopen;
static d_close_t tapclose;
static d_read_t tapread;
static d_write_t tapwrite;
static d_ioctl_t tapioctl;
static d_poll_t tappoll;
static struct cdevsw tap_cdevsw = {
/* open */ tapopen,
/* close */ tapclose,
/* read */ tapread,
/* write */ tapwrite,
/* ioctl */ tapioctl,
/* poll */ tappoll,
/* mmap */ nommap,
/* startegy */ nostrategy,
/* dev name */ CDEV_NAME,
/* dev major */ CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0,
/* bmaj */ -1
};
static int taprefcnt = 0; /* module ref. counter */
static int taplastunit = -1; /* max. open unit number */
static int tapdebug = 0; /* debug flag */
MALLOC_DECLARE(M_TAP);
MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
DEV_MODULE(if_tap, tapmodevent, NULL);
/*
* tapmodevent
*
* module event handler
*/
static int
tapmodevent(mod, type, data)
module_t mod;
int type;
void *data;
{
static int attached = 0;
struct ifnet *ifp = NULL;
int unit, s;
switch (type) {
case MOD_LOAD:
if (attached)
return (EEXIST);
cdevsw_add(&tap_cdevsw);
attached = 1;
break;
case MOD_UNLOAD:
if (taprefcnt > 0)
return (EBUSY);
cdevsw_remove(&tap_cdevsw);
unit = 0;
while (unit <= taplastunit) {
s = splimp();
TAILQ_FOREACH(ifp, &ifnet, if_link)
if ((strcmp(ifp->if_name, TAP) == 0) ||
(strcmp(ifp->if_name, VMNET) == 0))
if (ifp->if_unit == unit)
break;
splx(s);
if (ifp != NULL) {
struct tap_softc *tp = ifp->if_softc;
TAPDEBUG("detaching %s%d. taplastunit = %d\n",
ifp->if_name, unit, taplastunit);
ether_ifdetach(ifp, 1);
destroy_dev(tp->tap_dev);
FREE(tp, M_TAP);
}
else
unit ++;
}
attached = 0;
break;
default:
return (EOPNOTSUPP);
}
return (0);
} /* tapmodevent */
/*
* tapcreate
*
* to create interface
*/
static void
tapcreate(dev)
dev_t dev;
{
struct ifnet *ifp = NULL;
struct tap_softc *tp = NULL;
unsigned short macaddr_hi;
int unit;
char *name = NULL;
/* allocate driver storage and create device */
MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK);
bzero(tp, sizeof(*tp));
/* select device: tap or vmnet */
if (minor(dev) & VMNET_DEV_MASK) {
name = VMNET;
unit = lminor(dev) & 0xff;
}
else {
name = TAP;
unit = lminor(dev);
}
tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_UUCP, GID_DIALER,
0600, "%s%d", name, unit);
tp->tap_dev->si_drv1 = dev->si_drv1 = tp;
/* generate fake MAC address: 00 bd xx xx xx unit_no */
macaddr_hi = htons(0x00bd);
bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
tp->arpcom.ac_enaddr[5] = (u_char)unit;
/* fill the rest and attach interface */
ifp = &tp->tap_if;
ifp->if_softc = tp;
ifp->if_unit = unit;
if (unit > taplastunit)
taplastunit = unit;
ifp->if_name = name;
ifp->if_init = tapifinit;
ifp->if_output = ether_output;
ifp->if_start = tapifstart;
ifp->if_ioctl = tapifioctl;
ifp->if_mtu = ETHERMTU;
ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ether_ifattach(ifp, 1);
tp->tap_flags = TAP_INITED;
} /* tapcreate */
/*
* tapopen
*
* to open tunnel. must be superuser
*/
static int
tapopen(dev, flag, mode, p)
dev_t dev;
int flag;
int mode;
struct proc *p;
{
struct tap_softc *tp = NULL;
int error;
if ((error = suser(p)) != 0)
return (error);
tp = dev->si_drv1;
if (tp == NULL) {
tapcreate(dev);
tp = dev->si_drv1;
}
if (tp->tap_flags & TAP_OPEN)
return (EBUSY);
tp->tap_pid = p->p_pid;
tp->tap_flags |= TAP_OPEN;
taprefcnt ++;
TAPDEBUG("%s%d is open. refcnt = %d, taplastunit = %d\n",
tp->tap_if.if_name, tp->tap_if.if_unit, taprefcnt, taplastunit);
return (0);
} /* tapopen */
/*
* tapclose
*
* close the device - mark i/f down & delete routing info
*/
static int
tapclose(dev, foo, bar, p)
dev_t dev;
int foo;
int bar;
struct proc *p;
{
int s;
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
struct mbuf *m = NULL;
/* junk all pending output */
s = splimp();
do {
IF_DEQUEUE(&ifp->if_snd, m);
if (m != NULL)
m_freem(m);
} while (m != NULL);
splx(s);
if (ifp->if_flags & IFF_UP) {
s = splimp();
if_down(ifp);
if (ifp->if_flags & IFF_RUNNING) {
/* find internet addresses and delete routes */
struct ifaddr *ifa = NULL;
for (ifa = ifp->if_addrhead.tqh_first; ifa;
ifa = ifa->ifa_link.tqe_next) {
if (ifa->ifa_addr->sa_family == AF_INET) {
rtinit(ifa, (int)RTM_DELETE, 0);
/* remove address from interface */
bzero(ifa->ifa_addr,
sizeof(*(ifa->ifa_addr)));
bzero(ifa->ifa_dstaddr,
sizeof(*(ifa->ifa_dstaddr)));
bzero(ifa->ifa_netmask,
sizeof(*(ifa->ifa_netmask)));
}
}
ifp->if_flags &= ~IFF_RUNNING;
}
splx(s);
}
funsetown(tp->tap_sigio);
selwakeup(&tp->tap_rsel);
tp->tap_flags &= ~TAP_OPEN;
tp->tap_pid = 0;
taprefcnt --;
if (taprefcnt < 0) {
taprefcnt = 0;
printf("%s%d refcnt = %d is out of sync. set refcnt to 0\n",
ifp->if_name, ifp->if_unit, taprefcnt);
}
TAPDEBUG("%s%d is closed. refcnt = %d, taplastunit = %d\n",
ifp->if_name, ifp->if_unit, taprefcnt, taplastunit);
return (0);
} /* tapclose */
/*
* tapifinit
*
* network interface initialization function
*/
static void
tapifinit(xtp)
void *xtp;
{
struct tap_softc *tp = (struct tap_softc *)xtp;
struct ifnet *ifp = &tp->tap_if;
TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit);
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
/* attempt to start output */
tapifstart(ifp);
} /* tapifinit */
/*
* tapifioctl
*
* Process an ioctl request on network interface
*/
int
tapifioctl(ifp, cmd, data)
struct ifnet *ifp;
u_long cmd;
caddr_t data;
{
struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc);
struct ifstat *ifs = NULL;
int s, dummy;
switch (cmd) {
case SIOCSIFADDR:
case SIOCGIFADDR:
case SIOCSIFMTU:
s = splimp();
dummy = ether_ioctl(ifp, cmd, data);
splx(s);
return (dummy);
case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
case SIOCADDMULTI:
case SIOCDELMULTI:
break;
case SIOCGIFSTATUS:
s = splimp();
ifs = (struct ifstat *)data;
dummy = strlen(ifs->ascii);
if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
snprintf(ifs->ascii + dummy,
sizeof(ifs->ascii) - dummy,
"\tOpened by PID %d\n", tp->tap_pid);
splx(s);
break;
default:
return (EINVAL);
}
return (0);
} /* tapifioctl */
/*
* tapifstart
*
* queue packets from higher level ready to put out
*/
static void
tapifstart(ifp)
struct ifnet *ifp;
{
struct tap_softc *tp = ifp->if_softc;
int s;
TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit);
if ((tp->tap_flags & TAP_READY) != TAP_READY) {
struct mbuf *m = NULL;
TAPDEBUG("%s%d not ready. tap_flags = 0x%x\n",
ifp->if_name, ifp->if_unit, tp->tap_flags);
s = splimp();
do {
IF_DEQUEUE(&ifp->if_snd, m);
if (m != NULL)
m_freem(m);
ifp->if_oerrors ++;
} while (m != NULL);
splx(s);
return;
}
s = splimp();
ifp->if_flags |= IFF_OACTIVE;
if (ifp->if_snd.ifq_len != 0) {
if (tp->tap_flags & TAP_RWAIT) {
tp->tap_flags &= ~TAP_RWAIT;
wakeup((caddr_t)tp);
}
if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
pgsigio(tp->tap_sigio, SIGIO, 0);
selwakeup(&tp->tap_rsel);
ifp->if_opackets ++; /* obytes are counted in ether_output */
}
ifp->if_flags &= ~IFF_OACTIVE;
splx(s);
} /* tapifstart */
/*
* tapioctl
*
* the cdevsw interface is now pretty minimal
*/
static int
tapioctl(dev, cmd, data, flag, p)
dev_t dev;
u_long cmd;
caddr_t data;
int flag;
struct proc *p;
{
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
struct tapinfo *tapp = NULL;
int s;
switch (cmd) {
case TAPSIFINFO:
s = splimp();
tapp = (struct tapinfo *)data;
ifp->if_mtu = tapp->mtu;
ifp->if_type = tapp->type;
ifp->if_baudrate = tapp->baudrate;
splx(s);
break;
case TAPGIFINFO:
tapp = (struct tapinfo *)data;
tapp->mtu = ifp->if_mtu;
tapp->type = ifp->if_type;
tapp->baudrate = ifp->if_baudrate;
break;
case TAPSDEBUG:
tapdebug = *(int *)data;
break;
case TAPGDEBUG:
*(int *)data = tapdebug;
break;
case FIONBIO:
break;
case FIOASYNC:
if (*(int *)data)
tp->tap_flags |= TAP_ASYNC;
else
tp->tap_flags &= ~TAP_ASYNC;
break;
case FIONREAD:
s = splimp();
if (ifp->if_snd.ifq_head) {
struct mbuf *mb = ifp->if_snd.ifq_head;
for(*(int *)data = 0; mb != 0; mb = mb->m_next)
*(int *)data += mb->m_len;
}
else
*(int *)data = 0;
splx(s);
break;
case FIOSETOWN:
return (fsetown(*(int *)data, &tp->tap_sigio));
case FIOGETOWN:
*(int *)data = fgetown(tp->tap_sigio);
return (0);
/* this is deprecated, FIOSETOWN should be used instead */
case TIOCSPGRP:
return (fsetown(-(*(int *)data), &tp->tap_sigio));
/* this is deprecated, FIOGETOWN should be used instead */
case TIOCGPGRP:
*(int *)data = -fgetown(tp->tap_sigio);
return (0);
/* VMware/VMnet port ioctl's */
case SIOCGIFFLAGS: /* get ifnet flags */
bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
break;
case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */
short f = *(short *)data;
f &= 0x0fff;
f &= ~IFF_CANTCHANGE;
f |= IFF_UP;
s = splimp();
ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
splx(s);
} break;
case OSIOCGIFADDR: /* get MAC address */
case SIOCGIFADDR:
bcopy(tp->arpcom.ac_enaddr, data, ETHER_ADDR_LEN);
break;
case SIOCSIFADDR: /* set MAC address */
s = splimp();
bcopy(data, tp->arpcom.ac_enaddr, ETHER_ADDR_LEN);
splx(s);
break;
default:
return (ENOTTY);
}
return (0);
} /* tapioctl */
/*
* tapread
*
* the cdevsw read interface - reads a packet at a time, or at
* least as much of a packet as can be read
*/
static int
tapread(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
struct mbuf *m = NULL, *m0 = NULL;
int error = 0, len, s;
TAPDEBUG("%s%d reading\n", ifp->if_name, ifp->if_unit);
if ((tp->tap_flags & TAP_READY) != TAP_READY) {
TAPDEBUG("%s%d not ready. tap_flags = 0x%x\n",
ifp->if_name, ifp->if_unit, tp->tap_flags);
return (EHOSTDOWN);
}
tp->tap_flags &= ~TAP_RWAIT;
/* sleep until we get a packet */
do {
s = splimp();
IF_DEQUEUE(&ifp->if_snd, m0);
splx(s);
if (m0 == NULL) {
if (flag & IO_NDELAY)
return (EWOULDBLOCK);
tp->tap_flags |= TAP_RWAIT;
error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
if (error)
return (error);
}
} while (m0 == 0);
/* feed packet to bpf */
if (ifp->if_bpf != NULL)
bpf_mtap(ifp, m0);
/* xfer packet to user space */
while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) {
len = min(uio->uio_resid, m0->m_len);
if (len == 0)
break;
error = uiomove(mtod(m0, caddr_t), len, uio);
MFREE(m0, m);
m0 = m;
}
if (m0 != NULL) {
TAPDEBUG("%s%d dropping mbuf\n", ifp->if_name, ifp->if_unit);
m_freem(m0);
}
return (error);
} /* tapread */
/*
* tapwrite
*
* the cdevsw write interface - an atomic write is a packet - or else!
*/
static int
tapwrite(dev, uio, flag)
dev_t dev;
struct uio *uio;
int flag;
{
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
struct mbuf *top = NULL, **mp = NULL, *m = NULL;
struct ether_header *eh = NULL;
int error = 0, tlen, mlen;
TAPDEBUG("%s%d writting\n", ifp->if_name, ifp->if_unit);
if (uio->uio_resid == 0)
return (0);
if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
TAPDEBUG("%s%d invalid packet len = %d\n",
ifp->if_name, ifp->if_unit, uio->uio_resid);
return (EIO);
}
tlen = uio->uio_resid;
/* get a header mbuf */
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
return (ENOBUFS);
mlen = MHLEN;
top = 0;
mp = &top;
while ((error == 0) && (uio->uio_resid > 0)) {
m->m_len = min(mlen, uio->uio_resid);
error = uiomove(mtod(m, caddr_t), m->m_len, uio);
*mp = m;
mp = &m->m_next;
if (uio->uio_resid > 0) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0) {
error = ENOBUFS;
break;
}
mlen = MLEN;
}
}
if (error) {
ifp->if_ierrors ++;
if (top)
m_freem(top);
return (error);
}
top->m_pkthdr.len = tlen;
top->m_pkthdr.rcvif = ifp;
/*
* Ethernet bridge and bpf are handled in ether_input
*
* adjust mbuf and give packet to the ether_input
*/
eh = mtod(top, struct ether_header *);
m_adj(top, sizeof(struct ether_header));
ether_input(ifp, eh, top);
ifp->if_ipackets ++; /* ibytes are counted in ether_input */
return (0);
} /* tapwrite */
/*
* tappoll
*
* the poll interface, this is only useful on reads
* really. the write detect always returns true, write never blocks
* anyway, it either accepts the packet or drops it
*/
static int
tappoll(dev, events, p)
dev_t dev;
int events;
struct proc *p;
{
struct tap_softc *tp = dev->si_drv1;
struct ifnet *ifp = &tp->tap_if;
int s, revents = 0;
TAPDEBUG("%s%d polling\n", ifp->if_name, ifp->if_unit);
s = splimp();
if (events & (POLLIN | POLLRDNORM)) {
if (ifp->if_snd.ifq_len > 0) {
TAPDEBUG("%s%d have data in queue. len = %d\n",
ifp->if_name,ifp->if_unit, ifp->if_snd.ifq_len);
revents |= (events & (POLLIN | POLLRDNORM));
}
else {
TAPDEBUG("%s%d waiting for data\n",
ifp->if_name, ifp->if_unit);
selrecord(p, &tp->tap_rsel);
}
}
if (events & (POLLOUT | POLLWRNORM))
revents |= (events & (POLLOUT | POLLWRNORM));
splx(s);
return (revents);
} /* tappoll */

73
sys/net/if_tap.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BASED ON:
* -------------------------------------------------------------------------
*
* Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
* Nottingham University 1987.
*/
/*
* $FreeBSD$
* $Id: if_tap.h,v 0.7 2000/07/12 04:12:51 max Exp $
*/
#ifndef _NET_IF_TAP_H_
#define _NET_IF_TAP_H_
/* refer to if_tapvar.h for the softc stuff */
/* maximum receive packet size (hard limit) */
#define TAPMRU 16384
struct tapinfo {
int baudrate; /* linespeed */
short mtu; /* maximum transmission unit */
u_char type; /* ethernet, tokenring, etc. */
u_char dummy; /* place holder */
};
/* ioctl's for get/set debug */
#define TAPSDEBUG _IOW('t', 90, int)
#define TAPGDEBUG _IOR('t', 89, int)
#define TAPSIFINFO _IOW('t', 91, struct tapinfo)
#define TAPGIFINFO _IOR('t', 92, struct tapinfo)
/* VMware ioctl's */
#define VMIO_SIOCSIFFLAGS _IO('V', 0)
#define VMIO_SIOCSKEEP _IO('V', 1)
#define VMIO_SIOCSIFBR _IO('V', 2)
#define VMIO_SIOCSLADRF _IO('V', 3)
/* XXX -- unimplemented */
#define VMIO_SIOCSETMACADDR _IO('V', 4)
/* XXX -- not used? */
#define VMIO_SIOCPORT _IO('V', 5)
#define VMIO_SIOCBRIDGE _IO('V', 6)
#define VMIO_SIOCNETIF _IO('V', 7)
#endif /* !_NET_IF_TAP_H_ */

61
sys/net/if_tapvar.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BASED ON:
* -------------------------------------------------------------------------
*
* Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
* All rights reserved.
*
* Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
* Nottingham University 1987.
*/
/*
* $FreeBSD$
* $Id: if_tapvar.h,v 0.6 2000/07/11 02:16:08 max Exp $
*/
#ifndef _NET_IF_TAPVAR_H_
#define _NET_IF_TAPVAR_H_
struct tap_softc {
struct arpcom arpcom; /* ethernet common data */
#define tap_if arpcom.ac_if
dev_t tap_dev; /* device */
u_short tap_flags; /* misc flags */
#define TAP_OPEN (1 << 0)
#define TAP_INITED (1 << 1)
#define TAP_RWAIT (1 << 2)
#define TAP_ASYNC (1 << 3)
#define TAP_READY (TAP_OPEN|TAP_INITED)
pid_t tap_pid; /* PID of process to open */
struct sigio *tap_sigio; /* information for async I/O */
struct selinfo tap_rsel; /* read select */
};
#endif /* !_NET_IF_TAPVAR_H_ */