if_tap.c revision 126080
163670Snsayer/* 263670Snsayer * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 363670Snsayer * All rights reserved. 463670Snsayer * 563670Snsayer * Redistribution and use in source and binary forms, with or without 663670Snsayer * modification, are permitted provided that the following conditions 763670Snsayer * are met: 863670Snsayer * 1. Redistributions of source code must retain the above copyright 963670Snsayer * notice, this list of conditions and the following disclaimer. 1063670Snsayer * 2. Redistributions in binary form must reproduce the above copyright 1163670Snsayer * notice, this list of conditions and the following disclaimer in the 1263670Snsayer * documentation and/or other materials provided with the distribution. 1363670Snsayer * 1463670Snsayer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1563670Snsayer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1663670Snsayer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1763670Snsayer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1863670Snsayer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1963670Snsayer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2063670Snsayer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2163670Snsayer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2263670Snsayer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2363670Snsayer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2463670Snsayer * SUCH DAMAGE. 2563670Snsayer * 2663670Snsayer * BASED ON: 2763670Snsayer * ------------------------------------------------------------------------- 2863670Snsayer * 2963670Snsayer * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 3063670Snsayer * Nottingham University 1987. 3163670Snsayer */ 3263670Snsayer 3363670Snsayer/* 3463670Snsayer * $FreeBSD: head/sys/net/if_tap.c 126080 2004-02-21 21:10:55Z phk $ 3563803Snsayer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3663670Snsayer */ 3763670Snsayer 3863670Snsayer#include "opt_inet.h" 3963670Snsayer 4063670Snsayer#include <sys/param.h> 4163670Snsayer#include <sys/conf.h> 4263670Snsayer#include <sys/filedesc.h> 4363670Snsayer#include <sys/filio.h> 4463670Snsayer#include <sys/kernel.h> 4563670Snsayer#include <sys/malloc.h> 4663670Snsayer#include <sys/mbuf.h> 4763670Snsayer#include <sys/poll.h> 4863670Snsayer#include <sys/proc.h> 4963670Snsayer#include <sys/signalvar.h> 5063670Snsayer#include <sys/socket.h> 5163670Snsayer#include <sys/sockio.h> 5263670Snsayer#include <sys/sysctl.h> 5363670Snsayer#include <sys/systm.h> 5463670Snsayer#include <sys/ttycom.h> 5563670Snsayer#include <sys/uio.h> 5663670Snsayer#include <sys/vnode.h> 5783043Sbrooks#include <sys/queue.h> 5863670Snsayer 5963670Snsayer#include <net/bpf.h> 6063670Snsayer#include <net/ethernet.h> 6163670Snsayer#include <net/if.h> 6263670Snsayer#include <net/if_arp.h> 6363670Snsayer#include <net/route.h> 6463670Snsayer 6563670Snsayer#include <netinet/in.h> 6663670Snsayer 6763670Snsayer#include <net/if_tapvar.h> 6863670Snsayer#include <net/if_tap.h> 6963670Snsayer 7063670Snsayer 7163670Snsayer#define CDEV_NAME "tap" 7263670Snsayer#define TAPDEBUG if (tapdebug) printf 7363670Snsayer 7463670Snsayer#define TAP "tap" 7563670Snsayer#define VMNET "vmnet" 7683043Sbrooks#define TAPMAXUNIT 0x7fff 77126077Sphk#define VMNET_DEV_MASK CLONE_FLAG0 7863670Snsayer 7963670Snsayer/* module */ 80111742Sdesstatic int tapmodevent(module_t, int, void *); 8163670Snsayer 8263670Snsayer/* device */ 8393084Sbdestatic void tapclone(void *, char *, int, dev_t *); 8493084Sbdestatic void tapcreate(dev_t); 8563670Snsayer 8663670Snsayer/* network interface */ 8793084Sbdestatic void tapifstart(struct ifnet *); 8893084Sbdestatic int tapifioctl(struct ifnet *, u_long, caddr_t); 8993084Sbdestatic void tapifinit(void *); 9063670Snsayer 9163670Snsayer/* character device */ 9263670Snsayerstatic d_open_t tapopen; 9363670Snsayerstatic d_close_t tapclose; 9463670Snsayerstatic d_read_t tapread; 9563670Snsayerstatic d_write_t tapwrite; 9663670Snsayerstatic d_ioctl_t tapioctl; 9763670Snsayerstatic d_poll_t tappoll; 9863670Snsayer 9963670Snsayerstatic struct cdevsw tap_cdevsw = { 100126080Sphk .d_version = D_VERSION, 101126080Sphk .d_flags = D_NEEDGIANT, 102111815Sphk .d_open = tapopen, 103111815Sphk .d_close = tapclose, 104111815Sphk .d_read = tapread, 105111815Sphk .d_write = tapwrite, 106111815Sphk .d_ioctl = tapioctl, 107111815Sphk .d_poll = tappoll, 108111815Sphk .d_name = CDEV_NAME, 109126077Sphk .d_flags = D_PSEUDO, 11063670Snsayer}; 11163670Snsayer 11283043Sbrooksstatic int tapdebug = 0; /* debug flag */ 11383043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 114126077Sphkstatic struct clonedevs *tapclones; 11563670Snsayer 11663670SnsayerMALLOC_DECLARE(M_TAP); 11763670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 11863670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 11963670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 12063670Snsayer 12163670Snsayer/* 12263670Snsayer * tapmodevent 12363670Snsayer * 12463670Snsayer * module event handler 12563670Snsayer */ 12663670Snsayerstatic int 12763670Snsayertapmodevent(mod, type, data) 12863670Snsayer module_t mod; 12963670Snsayer int type; 13063670Snsayer void *data; 13163670Snsayer{ 13283043Sbrooks static eventhandler_tag eh_tag = NULL; 13383043Sbrooks struct tap_softc *tp = NULL; 13483043Sbrooks struct ifnet *ifp = NULL; 135126077Sphk int s; 13663670Snsayer 13763670Snsayer switch (type) { 13863670Snsayer case MOD_LOAD: 13963670Snsayer 14083043Sbrooks /* intitialize device */ 14183043Sbrooks 14283043Sbrooks SLIST_INIT(&taphead); 14383043Sbrooks 14471602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 145126077Sphk if (eh_tag == NULL) 146126077Sphk return (ENOMEM); 14783043Sbrooks return (0); 14863670Snsayer 14983043Sbrooks case MOD_UNLOAD: 15083043Sbrooks SLIST_FOREACH(tp, &taphead, tap_next) 151126077Sphk if (tp->tap_flags & TAP_OPEN) 15283043Sbrooks return (EBUSY); 15383043Sbrooks 15471602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 15563670Snsayer 15683043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 15783043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 15883043Sbrooks 15983043Sbrooks ifp = &tp->tap_if; 16083043Sbrooks 161121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 16283043Sbrooks 163121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 164121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 16583043Sbrooks 166126077Sphk destroy_dev(tp->tap_dev); 16763670Snsayer s = splimp(); 168106939Ssam ether_ifdetach(ifp); 16963670Snsayer splx(s); 17063670Snsayer 17193752Sluigi free(tp, M_TAP); 17283043Sbrooks } 173126077Sphk clone_cleanup(&tapclones); 17463670Snsayer 17583043Sbrooks break; 17663670Snsayer 17763670Snsayer default: 17863670Snsayer return (EOPNOTSUPP); 17963670Snsayer } 18063670Snsayer 18163670Snsayer return (0); 18263670Snsayer} /* tapmodevent */ 18363670Snsayer 18463670Snsayer 18563670Snsayer/* 18671602Sphk * DEVFS handler 18771602Sphk * 18871602Sphk * We need to support two kind of devices - tap and vmnet 18971602Sphk */ 19071602Sphkstatic void 19171602Sphktapclone(arg, name, namelen, dev) 19271602Sphk void *arg; 19371602Sphk char *name; 19471602Sphk int namelen; 19571602Sphk dev_t *dev; 19671602Sphk{ 197126077Sphk u_int extra; 198126077Sphk int i, unit; 19983043Sbrooks char *device_name = name; 20071602Sphk 20171602Sphk if (*dev != NODEV) 20271602Sphk return; 20371602Sphk 204126077Sphk device_name = TAP; 205126077Sphk extra = 0; 206126077Sphk if (strcmp(name, TAP) == 0) { 207126077Sphk unit = -1; 208126077Sphk } else if (strcmp(name, VMNET) == 0) { 209126077Sphk device_name = VMNET; 210126077Sphk extra = VMNET_DEV_MASK; 211126077Sphk unit = -1; 212126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 213126077Sphk device_name = VMNET; 214126077Sphk extra = VMNET_DEV_MASK; 215126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 216126077Sphk return; 21783043Sbrooks } 21871602Sphk 219126077Sphk /* find any existing device, or allocate new unit number */ 220126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 221126077Sphk if (i) { 222126077Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit) | extra, 223126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 224126077Sphk if (*dev != NULL) 225126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 22671602Sphk } 22771602Sphk} /* tapclone */ 22871602Sphk 22971602Sphk 23071602Sphk/* 23163670Snsayer * tapcreate 23263670Snsayer * 23363670Snsayer * to create interface 23463670Snsayer */ 23563670Snsayerstatic void 23663670Snsayertapcreate(dev) 23763670Snsayer dev_t dev; 23863670Snsayer{ 23963670Snsayer struct ifnet *ifp = NULL; 24063670Snsayer struct tap_softc *tp = NULL; 24163670Snsayer unsigned short macaddr_hi; 24263803Snsayer int unit, s; 24363670Snsayer char *name = NULL; 24463670Snsayer 245126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 246126077Sphk 24763670Snsayer /* allocate driver storage and create device */ 248111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 24983043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 25063670Snsayer 25183043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 25283043Sbrooks 25363670Snsayer /* select device: tap or vmnet */ 25463670Snsayer if (minor(dev) & VMNET_DEV_MASK) { 25563670Snsayer name = VMNET; 25663803Snsayer tp->tap_flags |= TAP_VMNET; 25783043Sbrooks } else 25863670Snsayer name = TAP; 25963670Snsayer 26083043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 26183043Sbrooks 26283043Sbrooks if (!(dev->si_flags & SI_NAMED)) 263111742Sdes dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 26463670Snsayer 0600, "%s%d", name, unit); 26563670Snsayer 26663670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 26763670Snsayer macaddr_hi = htons(0x00bd); 26863670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 26963670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 27063670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 27163670Snsayer 272111742Sdes /* fill the rest and attach interface */ 27363670Snsayer ifp = &tp->tap_if; 27463670Snsayer ifp->if_softc = tp; 275121816Sbrooks if_initname(ifp, name, unit); 27663670Snsayer ifp->if_init = tapifinit; 27763670Snsayer ifp->if_start = tapifstart; 27863670Snsayer ifp->if_ioctl = tapifioctl; 27963670Snsayer ifp->if_mtu = ETHERMTU; 28063670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 28163670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 28263670Snsayer 28383043Sbrooks dev->si_drv1 = tp; 284126077Sphk tp->tap_dev = dev; 28583043Sbrooks 28663803Snsayer s = splimp(); 287106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 28863803Snsayer splx(s); 28963670Snsayer 29063803Snsayer tp->tap_flags |= TAP_INITED; 29163803Snsayer 292121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 293121816Sbrooks ifp->if_xname, minor(dev)); 29463670Snsayer} /* tapcreate */ 29563670Snsayer 29663670Snsayer 29763670Snsayer/* 298111742Sdes * tapopen 29963670Snsayer * 30063670Snsayer * to open tunnel. must be superuser 30163670Snsayer */ 30263670Snsayerstatic int 30383366Sjuliantapopen(dev, flag, mode, td) 30463670Snsayer dev_t dev; 30563670Snsayer int flag; 30663670Snsayer int mode; 30783366Sjulian struct thread *td; 30863670Snsayer{ 30963670Snsayer struct tap_softc *tp = NULL; 31083043Sbrooks int unit, error; 31163670Snsayer 31293593Sjhb if ((error = suser(td)) != 0) 31363670Snsayer return (error); 31463670Snsayer 31583043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 31683043Sbrooks 31783043Sbrooks 31863670Snsayer tp = dev->si_drv1; 31963670Snsayer if (tp == NULL) { 32063670Snsayer tapcreate(dev); 32163670Snsayer tp = dev->si_drv1; 32263670Snsayer } 32363670Snsayer 324121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 325121816Sbrooks ("%s flags is out of sync", tp->tap_if.if_xname)); 32663670Snsayer 32763861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 32863861Snsayer 32983366Sjulian tp->tap_pid = td->td_proc->p_pid; 33063670Snsayer tp->tap_flags |= TAP_OPEN; 33163670Snsayer 332121816Sbrooks TAPDEBUG("%s is open. minor = %#x\n", 333121816Sbrooks tp->tap_if.if_xname, minor(dev)); 33463670Snsayer 33563670Snsayer return (0); 33663670Snsayer} /* tapopen */ 33763670Snsayer 33863670Snsayer 33963670Snsayer/* 34063670Snsayer * tapclose 34163670Snsayer * 34263670Snsayer * close the device - mark i/f down & delete routing info 34363670Snsayer */ 34463670Snsayerstatic int 34583366Sjuliantapclose(dev, foo, bar, td) 34663670Snsayer dev_t dev; 34763670Snsayer int foo; 34863670Snsayer int bar; 34983366Sjulian struct thread *td; 35063670Snsayer{ 35163670Snsayer struct tap_softc *tp = dev->si_drv1; 35263670Snsayer struct ifnet *ifp = &tp->tap_if; 353126077Sphk int s; 35463670Snsayer 35563670Snsayer /* junk all pending output */ 35683043Sbrooks IF_DRAIN(&ifp->if_snd); 35763670Snsayer 35863803Snsayer /* 35963803Snsayer * do not bring the interface down, and do not anything with 36063803Snsayer * interface, if we are in VMnet mode. just close the device. 36163803Snsayer */ 36263803Snsayer 36363803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 36463670Snsayer s = splimp(); 36563670Snsayer if_down(ifp); 36663670Snsayer if (ifp->if_flags & IFF_RUNNING) { 36763670Snsayer /* find internet addresses and delete routes */ 36863670Snsayer struct ifaddr *ifa = NULL; 36963670Snsayer 37063803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 37163670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 37263670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 37363670Snsayer 37463670Snsayer /* remove address from interface */ 375111742Sdes bzero(ifa->ifa_addr, 37663670Snsayer sizeof(*(ifa->ifa_addr))); 377111742Sdes bzero(ifa->ifa_dstaddr, 37863670Snsayer sizeof(*(ifa->ifa_dstaddr))); 379111742Sdes bzero(ifa->ifa_netmask, 38063670Snsayer sizeof(*(ifa->ifa_netmask))); 38163670Snsayer } 38263670Snsayer } 38363670Snsayer 38463670Snsayer ifp->if_flags &= ~IFF_RUNNING; 38563670Snsayer } 38663670Snsayer splx(s); 38763670Snsayer } 38863670Snsayer 38996122Salfred funsetown(&tp->tap_sigio); 390122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 39163670Snsayer 39263670Snsayer tp->tap_flags &= ~TAP_OPEN; 39363670Snsayer tp->tap_pid = 0; 39463670Snsayer 395121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 396121816Sbrooks ifp->if_xname, minor(dev)); 39763670Snsayer 39863670Snsayer return (0); 39963670Snsayer} /* tapclose */ 40063670Snsayer 40163670Snsayer 40263670Snsayer/* 40363670Snsayer * tapifinit 40463670Snsayer * 40563670Snsayer * network interface initialization function 40663670Snsayer */ 40763670Snsayerstatic void 40863670Snsayertapifinit(xtp) 40963670Snsayer void *xtp; 41063670Snsayer{ 41163670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 41263670Snsayer struct ifnet *ifp = &tp->tap_if; 41363670Snsayer 414121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 41563670Snsayer 41663670Snsayer ifp->if_flags |= IFF_RUNNING; 41763670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 41863670Snsayer 41963670Snsayer /* attempt to start output */ 42063670Snsayer tapifstart(ifp); 42163670Snsayer} /* tapifinit */ 42263670Snsayer 42363670Snsayer 42463670Snsayer/* 42563670Snsayer * tapifioctl 42663670Snsayer * 42763670Snsayer * Process an ioctl request on network interface 42863670Snsayer */ 429105228Sphkstatic int 43063670Snsayertapifioctl(ifp, cmd, data) 43163670Snsayer struct ifnet *ifp; 43263670Snsayer u_long cmd; 43363670Snsayer caddr_t data; 43463670Snsayer{ 435111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 43663670Snsayer struct ifstat *ifs = NULL; 43763670Snsayer int s, dummy; 43863670Snsayer 43963670Snsayer switch (cmd) { 44063670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 44163670Snsayer case SIOCADDMULTI: 44263670Snsayer case SIOCDELMULTI: 44383043Sbrooks break; 44463670Snsayer 44563670Snsayer case SIOCGIFSTATUS: 44663670Snsayer s = splimp(); 44763670Snsayer ifs = (struct ifstat *)data; 44863670Snsayer dummy = strlen(ifs->ascii); 44963670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 45063670Snsayer snprintf(ifs->ascii + dummy, 45163670Snsayer sizeof(ifs->ascii) - dummy, 45263670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 45363670Snsayer splx(s); 45483043Sbrooks break; 45563670Snsayer 45663670Snsayer default: 457106939Ssam s = splimp(); 458106939Ssam dummy = ether_ioctl(ifp, cmd, data); 459106939Ssam splx(s); 460106939Ssam return (dummy); 46163670Snsayer } 46263670Snsayer 46363670Snsayer return (0); 46463670Snsayer} /* tapifioctl */ 46563670Snsayer 46663670Snsayer 46763670Snsayer/* 468111742Sdes * tapifstart 469111742Sdes * 47063670Snsayer * queue packets from higher level ready to put out 47163670Snsayer */ 47263670Snsayerstatic void 47363670Snsayertapifstart(ifp) 47463670Snsayer struct ifnet *ifp; 47563670Snsayer{ 47663670Snsayer struct tap_softc *tp = ifp->if_softc; 47763670Snsayer int s; 47863670Snsayer 479121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 48063670Snsayer 48163803Snsayer /* 48263803Snsayer * do not junk pending output if we are in VMnet mode. 48363803Snsayer * XXX: can this do any harm because of queue overflow? 48463803Snsayer */ 48563803Snsayer 486111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 48763803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 48863670Snsayer struct mbuf *m = NULL; 48963670Snsayer 490121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 491121816Sbrooks tp->tap_flags); 49263670Snsayer 49363670Snsayer s = splimp(); 49463670Snsayer do { 49563670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 49663670Snsayer if (m != NULL) 49763670Snsayer m_freem(m); 49863670Snsayer ifp->if_oerrors ++; 49963670Snsayer } while (m != NULL); 50063670Snsayer splx(s); 50163670Snsayer 50263670Snsayer return; 50363670Snsayer } 50463670Snsayer 50563670Snsayer s = splimp(); 50663670Snsayer ifp->if_flags |= IFF_OACTIVE; 50763670Snsayer 50863670Snsayer if (ifp->if_snd.ifq_len != 0) { 50963670Snsayer if (tp->tap_flags & TAP_RWAIT) { 51063670Snsayer tp->tap_flags &= ~TAP_RWAIT; 511111748Sdes wakeup(tp); 51263670Snsayer } 51363670Snsayer 51463670Snsayer if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 51595883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 51663670Snsayer 517122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 51863670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 51963670Snsayer } 52063670Snsayer 52163670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 52263670Snsayer splx(s); 52363670Snsayer} /* tapifstart */ 52463670Snsayer 52563670Snsayer 52663670Snsayer/* 52763670Snsayer * tapioctl 52863670Snsayer * 52963670Snsayer * the cdevsw interface is now pretty minimal 53063670Snsayer */ 53163670Snsayerstatic int 53283366Sjuliantapioctl(dev, cmd, data, flag, td) 53363670Snsayer dev_t dev; 53463670Snsayer u_long cmd; 53563670Snsayer caddr_t data; 53663670Snsayer int flag; 53783366Sjulian struct thread *td; 53863670Snsayer{ 53963670Snsayer struct tap_softc *tp = dev->si_drv1; 54063670Snsayer struct ifnet *ifp = &tp->tap_if; 541111742Sdes struct tapinfo *tapp = NULL; 54263670Snsayer int s; 543102052Ssobomax int f; 54463670Snsayer 54563670Snsayer switch (cmd) { 546111742Sdes case TAPSIFINFO: 54763670Snsayer s = splimp(); 548111742Sdes tapp = (struct tapinfo *)data; 549111742Sdes ifp->if_mtu = tapp->mtu; 550111742Sdes ifp->if_type = tapp->type; 551111742Sdes ifp->if_baudrate = tapp->baudrate; 55263670Snsayer splx(s); 553111742Sdes break; 55463670Snsayer 555111742Sdes case TAPGIFINFO: 556111742Sdes tapp = (struct tapinfo *)data; 557111742Sdes tapp->mtu = ifp->if_mtu; 558111742Sdes tapp->type = ifp->if_type; 559111742Sdes tapp->baudrate = ifp->if_baudrate; 560111742Sdes break; 56163670Snsayer 56263670Snsayer case TAPSDEBUG: 56363670Snsayer tapdebug = *(int *)data; 56483043Sbrooks break; 56563670Snsayer 56663670Snsayer case TAPGDEBUG: 56763670Snsayer *(int *)data = tapdebug; 56883043Sbrooks break; 56963670Snsayer 57063670Snsayer case FIONBIO: 57183043Sbrooks break; 57263670Snsayer 57363670Snsayer case FIOASYNC: 57463803Snsayer s = splimp(); 57563670Snsayer if (*(int *)data) 57663670Snsayer tp->tap_flags |= TAP_ASYNC; 57763670Snsayer else 57863670Snsayer tp->tap_flags &= ~TAP_ASYNC; 57963803Snsayer splx(s); 58083043Sbrooks break; 58163670Snsayer 58263670Snsayer case FIONREAD: 58363670Snsayer s = splimp(); 58463670Snsayer if (ifp->if_snd.ifq_head) { 58563670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 58663670Snsayer 58763803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 58863670Snsayer *(int *)data += mb->m_len; 58983043Sbrooks } else 59063670Snsayer *(int *)data = 0; 59163670Snsayer splx(s); 59283043Sbrooks break; 59363670Snsayer 59463670Snsayer case FIOSETOWN: 59563670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 59663670Snsayer 59763670Snsayer case FIOGETOWN: 598104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 59963670Snsayer return (0); 60063670Snsayer 60163670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 60263670Snsayer case TIOCSPGRP: 60363670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 60463670Snsayer 60563670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 60663670Snsayer case TIOCGPGRP: 607104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 60863670Snsayer return (0); 60963670Snsayer 61063670Snsayer /* VMware/VMnet port ioctl's */ 61163670Snsayer 61263670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 61363670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 61483043Sbrooks break; 61563670Snsayer 61683043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 617102052Ssobomax f = *(int *)data; 61863670Snsayer f &= 0x0fff; 61963670Snsayer f &= ~IFF_CANTCHANGE; 62063670Snsayer f |= IFF_UP; 62163670Snsayer 62263670Snsayer s = splimp(); 62363670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 62463670Snsayer splx(s); 62583043Sbrooks break; 62663670Snsayer 62763861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 62863670Snsayer case SIOCGIFADDR: 62963861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 63083043Sbrooks break; 63163670Snsayer 63263861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 63363861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 63483043Sbrooks break; 63563670Snsayer 63663670Snsayer default: 63763670Snsayer return (ENOTTY); 63863670Snsayer } 63963670Snsayer return (0); 64063670Snsayer} /* tapioctl */ 64163670Snsayer 64263670Snsayer 64363670Snsayer/* 64463670Snsayer * tapread 64563670Snsayer * 64663670Snsayer * the cdevsw read interface - reads a packet at a time, or at 64763670Snsayer * least as much of a packet as can be read 64863670Snsayer */ 64963670Snsayerstatic int 65063670Snsayertapread(dev, uio, flag) 65163670Snsayer dev_t dev; 65263670Snsayer struct uio *uio; 65363670Snsayer int flag; 65463670Snsayer{ 65563670Snsayer struct tap_softc *tp = dev->si_drv1; 65663670Snsayer struct ifnet *ifp = &tp->tap_if; 65790227Sdillon struct mbuf *m = NULL; 65863670Snsayer int error = 0, len, s; 65963670Snsayer 660121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 66163670Snsayer 66263670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 663121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 664121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 66563803Snsayer 66663670Snsayer return (EHOSTDOWN); 66763670Snsayer } 66863670Snsayer 66963670Snsayer tp->tap_flags &= ~TAP_RWAIT; 67063670Snsayer 67163670Snsayer /* sleep until we get a packet */ 67263670Snsayer do { 67363670Snsayer s = splimp(); 67490227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 67563670Snsayer splx(s); 67663670Snsayer 67790227Sdillon if (m == NULL) { 67863670Snsayer if (flag & IO_NDELAY) 67963670Snsayer return (EWOULDBLOCK); 680111742Sdes 68163670Snsayer tp->tap_flags |= TAP_RWAIT; 682111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 68363670Snsayer if (error) 68463670Snsayer return (error); 68563670Snsayer } 68690227Sdillon } while (m == NULL); 68763670Snsayer 68863670Snsayer /* feed packet to bpf */ 689106939Ssam BPF_MTAP(ifp, m); 69063670Snsayer 69163670Snsayer /* xfer packet to user space */ 69290227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 69390227Sdillon len = min(uio->uio_resid, m->m_len); 69463670Snsayer if (len == 0) 69563670Snsayer break; 69663670Snsayer 697111741Sdes error = uiomove(mtod(m, void *), len, uio); 69890227Sdillon m = m_free(m); 69963670Snsayer } 70063670Snsayer 70190227Sdillon if (m != NULL) { 702121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 703121816Sbrooks minor(dev)); 70490227Sdillon m_freem(m); 70563670Snsayer } 70663670Snsayer 70763670Snsayer return (error); 70863670Snsayer} /* tapread */ 70963670Snsayer 71063670Snsayer 71163670Snsayer/* 71263670Snsayer * tapwrite 71363670Snsayer * 71463670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 71563670Snsayer */ 71663670Snsayerstatic int 71763670Snsayertapwrite(dev, uio, flag) 71863670Snsayer dev_t dev; 71963670Snsayer struct uio *uio; 72063670Snsayer int flag; 72163670Snsayer{ 72263670Snsayer struct tap_softc *tp = dev->si_drv1; 72363670Snsayer struct ifnet *ifp = &tp->tap_if; 72463670Snsayer struct mbuf *top = NULL, **mp = NULL, *m = NULL; 725111742Sdes int error = 0, tlen, mlen; 72663670Snsayer 727121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 728121816Sbrooks ifp->if_xname, minor(dev)); 72963670Snsayer 73063670Snsayer if (uio->uio_resid == 0) 73163670Snsayer return (0); 73263670Snsayer 73363670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 734121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 735121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 73663803Snsayer 73763670Snsayer return (EIO); 73863670Snsayer } 73963670Snsayer tlen = uio->uio_resid; 74063670Snsayer 74163670Snsayer /* get a header mbuf */ 742111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 74363670Snsayer if (m == NULL) 74463670Snsayer return (ENOBUFS); 74563670Snsayer mlen = MHLEN; 74663670Snsayer 74763670Snsayer top = 0; 74863670Snsayer mp = ⊤ 74963670Snsayer while ((error == 0) && (uio->uio_resid > 0)) { 75063670Snsayer m->m_len = min(mlen, uio->uio_resid); 751111741Sdes error = uiomove(mtod(m, void *), m->m_len, uio); 75263670Snsayer *mp = m; 75363670Snsayer mp = &m->m_next; 75463670Snsayer if (uio->uio_resid > 0) { 755111119Simp MGET(m, M_DONTWAIT, MT_DATA); 75663803Snsayer if (m == NULL) { 75763670Snsayer error = ENOBUFS; 75863670Snsayer break; 75963670Snsayer } 76063670Snsayer mlen = MLEN; 76163670Snsayer } 76263670Snsayer } 76363670Snsayer if (error) { 76463670Snsayer ifp->if_ierrors ++; 76563670Snsayer if (top) 76663670Snsayer m_freem(top); 76763670Snsayer return (error); 76863670Snsayer } 76963670Snsayer 77063670Snsayer top->m_pkthdr.len = tlen; 77163670Snsayer top->m_pkthdr.rcvif = ifp; 772111742Sdes 773106939Ssam /* Pass packet up to parent. */ 774106939Ssam (*ifp->if_input)(ifp, top); 775106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 77663670Snsayer 77763670Snsayer return (0); 77863670Snsayer} /* tapwrite */ 77963670Snsayer 78063670Snsayer 78163670Snsayer/* 78263670Snsayer * tappoll 78363670Snsayer * 78463670Snsayer * the poll interface, this is only useful on reads 78563670Snsayer * really. the write detect always returns true, write never blocks 78663670Snsayer * anyway, it either accepts the packet or drops it 78763670Snsayer */ 78863670Snsayerstatic int 78983366Sjuliantappoll(dev, events, td) 79063670Snsayer dev_t dev; 79163670Snsayer int events; 79283366Sjulian struct thread *td; 79363670Snsayer{ 79463670Snsayer struct tap_softc *tp = dev->si_drv1; 79563670Snsayer struct ifnet *ifp = &tp->tap_if; 796111742Sdes int s, revents = 0; 79763670Snsayer 798121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 799121816Sbrooks ifp->if_xname, minor(dev)); 80063670Snsayer 80163670Snsayer s = splimp(); 80263670Snsayer if (events & (POLLIN | POLLRDNORM)) { 80363670Snsayer if (ifp->if_snd.ifq_len > 0) { 804121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 805121816Sbrooks "minor = %#x\n", ifp->if_xname, 80683043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 80763803Snsayer 80863670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 80983043Sbrooks } else { 810121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 811121816Sbrooks ifp->if_xname, minor(dev)); 81263803Snsayer 81383805Sjhb selrecord(td, &tp->tap_rsel); 81463670Snsayer } 81563670Snsayer } 81663670Snsayer 81763670Snsayer if (events & (POLLOUT | POLLWRNORM)) 81863670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 81963670Snsayer 82063670Snsayer splx(s); 82163670Snsayer return (revents); 82263670Snsayer} /* tappoll */ 823