if_tap.c revision 126077
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 126077 2004-02-21 20:29:52Z 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 = { 100111815Sphk .d_open = tapopen, 101111815Sphk .d_close = tapclose, 102111815Sphk .d_read = tapread, 103111815Sphk .d_write = tapwrite, 104111815Sphk .d_ioctl = tapioctl, 105111815Sphk .d_poll = tappoll, 106111815Sphk .d_name = CDEV_NAME, 107126077Sphk .d_flags = D_PSEUDO, 10863670Snsayer}; 10963670Snsayer 11083043Sbrooksstatic int tapdebug = 0; /* debug flag */ 11183043Sbrooksstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 112126077Sphkstatic struct clonedevs *tapclones; 11363670Snsayer 11463670SnsayerMALLOC_DECLARE(M_TAP); 11563670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 11663670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 11763670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 11863670Snsayer 11963670Snsayer/* 12063670Snsayer * tapmodevent 12163670Snsayer * 12263670Snsayer * module event handler 12363670Snsayer */ 12463670Snsayerstatic int 12563670Snsayertapmodevent(mod, type, data) 12663670Snsayer module_t mod; 12763670Snsayer int type; 12863670Snsayer void *data; 12963670Snsayer{ 13083043Sbrooks static eventhandler_tag eh_tag = NULL; 13183043Sbrooks struct tap_softc *tp = NULL; 13283043Sbrooks struct ifnet *ifp = NULL; 133126077Sphk int s; 13463670Snsayer 13563670Snsayer switch (type) { 13663670Snsayer case MOD_LOAD: 13763670Snsayer 13883043Sbrooks /* intitialize device */ 13983043Sbrooks 14083043Sbrooks SLIST_INIT(&taphead); 14183043Sbrooks 14271602Sphk eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 143126077Sphk if (eh_tag == NULL) 144126077Sphk return (ENOMEM); 14583043Sbrooks return (0); 14663670Snsayer 14783043Sbrooks case MOD_UNLOAD: 14883043Sbrooks SLIST_FOREACH(tp, &taphead, tap_next) 149126077Sphk if (tp->tap_flags & TAP_OPEN) 15083043Sbrooks return (EBUSY); 15183043Sbrooks 15271602Sphk EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 15363670Snsayer 15483043Sbrooks while ((tp = SLIST_FIRST(&taphead)) != NULL) { 15583043Sbrooks SLIST_REMOVE_HEAD(&taphead, tap_next); 15683043Sbrooks 15783043Sbrooks ifp = &tp->tap_if; 15883043Sbrooks 159121816Sbrooks TAPDEBUG("detaching %s\n", ifp->if_xname); 16083043Sbrooks 161121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 162121816Sbrooks ("%s flags is out of sync", ifp->if_xname)); 16383043Sbrooks 164126077Sphk destroy_dev(tp->tap_dev); 16563670Snsayer s = splimp(); 166106939Ssam ether_ifdetach(ifp); 16763670Snsayer splx(s); 16863670Snsayer 16993752Sluigi free(tp, M_TAP); 17083043Sbrooks } 171126077Sphk clone_cleanup(&tapclones); 17263670Snsayer 17383043Sbrooks break; 17463670Snsayer 17563670Snsayer default: 17663670Snsayer return (EOPNOTSUPP); 17763670Snsayer } 17863670Snsayer 17963670Snsayer return (0); 18063670Snsayer} /* tapmodevent */ 18163670Snsayer 18263670Snsayer 18363670Snsayer/* 18471602Sphk * DEVFS handler 18571602Sphk * 18671602Sphk * We need to support two kind of devices - tap and vmnet 18771602Sphk */ 18871602Sphkstatic void 18971602Sphktapclone(arg, name, namelen, dev) 19071602Sphk void *arg; 19171602Sphk char *name; 19271602Sphk int namelen; 19371602Sphk dev_t *dev; 19471602Sphk{ 195126077Sphk u_int extra; 196126077Sphk int i, unit; 19783043Sbrooks char *device_name = name; 19871602Sphk 19971602Sphk if (*dev != NODEV) 20071602Sphk return; 20171602Sphk 202126077Sphk device_name = TAP; 203126077Sphk extra = 0; 204126077Sphk if (strcmp(name, TAP) == 0) { 205126077Sphk unit = -1; 206126077Sphk } else if (strcmp(name, VMNET) == 0) { 207126077Sphk device_name = VMNET; 208126077Sphk extra = VMNET_DEV_MASK; 209126077Sphk unit = -1; 210126077Sphk } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 211126077Sphk device_name = VMNET; 212126077Sphk extra = VMNET_DEV_MASK; 213126077Sphk if (dev_stdclone(name, NULL, device_name, &unit) != 1) 214126077Sphk return; 21583043Sbrooks } 21671602Sphk 217126077Sphk /* find any existing device, or allocate new unit number */ 218126077Sphk i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 219126077Sphk if (i) { 220126077Sphk *dev = make_dev(&tap_cdevsw, unit2minor(unit) | extra, 221126077Sphk UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 222126077Sphk if (*dev != NULL) 223126077Sphk (*dev)->si_flags |= SI_CHEAPCLONE; 22471602Sphk } 22571602Sphk} /* tapclone */ 22671602Sphk 22771602Sphk 22871602Sphk/* 22963670Snsayer * tapcreate 23063670Snsayer * 23163670Snsayer * to create interface 23263670Snsayer */ 23363670Snsayerstatic void 23463670Snsayertapcreate(dev) 23563670Snsayer dev_t dev; 23663670Snsayer{ 23763670Snsayer struct ifnet *ifp = NULL; 23863670Snsayer struct tap_softc *tp = NULL; 23963670Snsayer unsigned short macaddr_hi; 24063803Snsayer int unit, s; 24163670Snsayer char *name = NULL; 24263670Snsayer 243126077Sphk dev->si_flags &= ~SI_CHEAPCLONE; 244126077Sphk 24563670Snsayer /* allocate driver storage and create device */ 246111119Simp MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 24783043Sbrooks SLIST_INSERT_HEAD(&taphead, tp, tap_next); 24863670Snsayer 24983043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 25083043Sbrooks 25163670Snsayer /* select device: tap or vmnet */ 25263670Snsayer if (minor(dev) & VMNET_DEV_MASK) { 25363670Snsayer name = VMNET; 25463803Snsayer tp->tap_flags |= TAP_VMNET; 25583043Sbrooks } else 25663670Snsayer name = TAP; 25763670Snsayer 25883043Sbrooks TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 25983043Sbrooks 26083043Sbrooks if (!(dev->si_flags & SI_NAMED)) 261111742Sdes dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 26263670Snsayer 0600, "%s%d", name, unit); 26363670Snsayer 26463670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 26563670Snsayer macaddr_hi = htons(0x00bd); 26663670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 26763670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 26863670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 26963670Snsayer 270111742Sdes /* fill the rest and attach interface */ 27163670Snsayer ifp = &tp->tap_if; 27263670Snsayer ifp->if_softc = tp; 273121816Sbrooks if_initname(ifp, name, unit); 27463670Snsayer ifp->if_init = tapifinit; 27563670Snsayer ifp->if_start = tapifstart; 27663670Snsayer ifp->if_ioctl = tapifioctl; 27763670Snsayer ifp->if_mtu = ETHERMTU; 27863670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 27963670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 28063670Snsayer 28183043Sbrooks dev->si_drv1 = tp; 282126077Sphk tp->tap_dev = dev; 28383043Sbrooks 28463803Snsayer s = splimp(); 285106939Ssam ether_ifattach(ifp, tp->arpcom.ac_enaddr); 28663803Snsayer splx(s); 28763670Snsayer 28863803Snsayer tp->tap_flags |= TAP_INITED; 28963803Snsayer 290121816Sbrooks TAPDEBUG("interface %s is created. minor = %#x\n", 291121816Sbrooks ifp->if_xname, minor(dev)); 29263670Snsayer} /* tapcreate */ 29363670Snsayer 29463670Snsayer 29563670Snsayer/* 296111742Sdes * tapopen 29763670Snsayer * 29863670Snsayer * to open tunnel. must be superuser 29963670Snsayer */ 30063670Snsayerstatic int 30183366Sjuliantapopen(dev, flag, mode, td) 30263670Snsayer dev_t dev; 30363670Snsayer int flag; 30463670Snsayer int mode; 30583366Sjulian struct thread *td; 30663670Snsayer{ 30763670Snsayer struct tap_softc *tp = NULL; 30883043Sbrooks int unit, error; 30963670Snsayer 31093593Sjhb if ((error = suser(td)) != 0) 31163670Snsayer return (error); 31263670Snsayer 31383043Sbrooks unit = dev2unit(dev) & TAPMAXUNIT; 31483043Sbrooks 31583043Sbrooks 31663670Snsayer tp = dev->si_drv1; 31763670Snsayer if (tp == NULL) { 31863670Snsayer tapcreate(dev); 31963670Snsayer tp = dev->si_drv1; 32063670Snsayer } 32163670Snsayer 322121816Sbrooks KASSERT(!(tp->tap_flags & TAP_OPEN), 323121816Sbrooks ("%s flags is out of sync", tp->tap_if.if_xname)); 32463670Snsayer 32563861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 32663861Snsayer 32783366Sjulian tp->tap_pid = td->td_proc->p_pid; 32863670Snsayer tp->tap_flags |= TAP_OPEN; 32963670Snsayer 330121816Sbrooks TAPDEBUG("%s is open. minor = %#x\n", 331121816Sbrooks tp->tap_if.if_xname, minor(dev)); 33263670Snsayer 33363670Snsayer return (0); 33463670Snsayer} /* tapopen */ 33563670Snsayer 33663670Snsayer 33763670Snsayer/* 33863670Snsayer * tapclose 33963670Snsayer * 34063670Snsayer * close the device - mark i/f down & delete routing info 34163670Snsayer */ 34263670Snsayerstatic int 34383366Sjuliantapclose(dev, foo, bar, td) 34463670Snsayer dev_t dev; 34563670Snsayer int foo; 34663670Snsayer int bar; 34783366Sjulian struct thread *td; 34863670Snsayer{ 34963670Snsayer struct tap_softc *tp = dev->si_drv1; 35063670Snsayer struct ifnet *ifp = &tp->tap_if; 351126077Sphk int s; 35263670Snsayer 35363670Snsayer /* junk all pending output */ 35483043Sbrooks IF_DRAIN(&ifp->if_snd); 35563670Snsayer 35663803Snsayer /* 35763803Snsayer * do not bring the interface down, and do not anything with 35863803Snsayer * interface, if we are in VMnet mode. just close the device. 35963803Snsayer */ 36063803Snsayer 36163803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 36263670Snsayer s = splimp(); 36363670Snsayer if_down(ifp); 36463670Snsayer if (ifp->if_flags & IFF_RUNNING) { 36563670Snsayer /* find internet addresses and delete routes */ 36663670Snsayer struct ifaddr *ifa = NULL; 36763670Snsayer 36863803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 36963670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 37063670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 37163670Snsayer 37263670Snsayer /* remove address from interface */ 373111742Sdes bzero(ifa->ifa_addr, 37463670Snsayer sizeof(*(ifa->ifa_addr))); 375111742Sdes bzero(ifa->ifa_dstaddr, 37663670Snsayer sizeof(*(ifa->ifa_dstaddr))); 377111742Sdes bzero(ifa->ifa_netmask, 37863670Snsayer sizeof(*(ifa->ifa_netmask))); 37963670Snsayer } 38063670Snsayer } 38163670Snsayer 38263670Snsayer ifp->if_flags &= ~IFF_RUNNING; 38363670Snsayer } 38463670Snsayer splx(s); 38563670Snsayer } 38663670Snsayer 38796122Salfred funsetown(&tp->tap_sigio); 388122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 38963670Snsayer 39063670Snsayer tp->tap_flags &= ~TAP_OPEN; 39163670Snsayer tp->tap_pid = 0; 39263670Snsayer 393121816Sbrooks TAPDEBUG("%s is closed. minor = %#x\n", 394121816Sbrooks ifp->if_xname, minor(dev)); 39563670Snsayer 39663670Snsayer return (0); 39763670Snsayer} /* tapclose */ 39863670Snsayer 39963670Snsayer 40063670Snsayer/* 40163670Snsayer * tapifinit 40263670Snsayer * 40363670Snsayer * network interface initialization function 40463670Snsayer */ 40563670Snsayerstatic void 40663670Snsayertapifinit(xtp) 40763670Snsayer void *xtp; 40863670Snsayer{ 40963670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 41063670Snsayer struct ifnet *ifp = &tp->tap_if; 41163670Snsayer 412121816Sbrooks TAPDEBUG("initializing %s\n", ifp->if_xname); 41363670Snsayer 41463670Snsayer ifp->if_flags |= IFF_RUNNING; 41563670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 41663670Snsayer 41763670Snsayer /* attempt to start output */ 41863670Snsayer tapifstart(ifp); 41963670Snsayer} /* tapifinit */ 42063670Snsayer 42163670Snsayer 42263670Snsayer/* 42363670Snsayer * tapifioctl 42463670Snsayer * 42563670Snsayer * Process an ioctl request on network interface 42663670Snsayer */ 427105228Sphkstatic int 42863670Snsayertapifioctl(ifp, cmd, data) 42963670Snsayer struct ifnet *ifp; 43063670Snsayer u_long cmd; 43163670Snsayer caddr_t data; 43263670Snsayer{ 433111742Sdes struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 43463670Snsayer struct ifstat *ifs = NULL; 43563670Snsayer int s, dummy; 43663670Snsayer 43763670Snsayer switch (cmd) { 43863670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 43963670Snsayer case SIOCADDMULTI: 44063670Snsayer case SIOCDELMULTI: 44183043Sbrooks break; 44263670Snsayer 44363670Snsayer case SIOCGIFSTATUS: 44463670Snsayer s = splimp(); 44563670Snsayer ifs = (struct ifstat *)data; 44663670Snsayer dummy = strlen(ifs->ascii); 44763670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 44863670Snsayer snprintf(ifs->ascii + dummy, 44963670Snsayer sizeof(ifs->ascii) - dummy, 45063670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 45163670Snsayer splx(s); 45283043Sbrooks break; 45363670Snsayer 45463670Snsayer default: 455106939Ssam s = splimp(); 456106939Ssam dummy = ether_ioctl(ifp, cmd, data); 457106939Ssam splx(s); 458106939Ssam return (dummy); 45963670Snsayer } 46063670Snsayer 46163670Snsayer return (0); 46263670Snsayer} /* tapifioctl */ 46363670Snsayer 46463670Snsayer 46563670Snsayer/* 466111742Sdes * tapifstart 467111742Sdes * 46863670Snsayer * queue packets from higher level ready to put out 46963670Snsayer */ 47063670Snsayerstatic void 47163670Snsayertapifstart(ifp) 47263670Snsayer struct ifnet *ifp; 47363670Snsayer{ 47463670Snsayer struct tap_softc *tp = ifp->if_softc; 47563670Snsayer int s; 47663670Snsayer 477121816Sbrooks TAPDEBUG("%s starting\n", ifp->if_xname); 47863670Snsayer 47963803Snsayer /* 48063803Snsayer * do not junk pending output if we are in VMnet mode. 48163803Snsayer * XXX: can this do any harm because of queue overflow? 48263803Snsayer */ 48363803Snsayer 484111742Sdes if (((tp->tap_flags & TAP_VMNET) == 0) && 48563803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 48663670Snsayer struct mbuf *m = NULL; 48763670Snsayer 488121816Sbrooks TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 489121816Sbrooks tp->tap_flags); 49063670Snsayer 49163670Snsayer s = splimp(); 49263670Snsayer do { 49363670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 49463670Snsayer if (m != NULL) 49563670Snsayer m_freem(m); 49663670Snsayer ifp->if_oerrors ++; 49763670Snsayer } while (m != NULL); 49863670Snsayer splx(s); 49963670Snsayer 50063670Snsayer return; 50163670Snsayer } 50263670Snsayer 50363670Snsayer s = splimp(); 50463670Snsayer ifp->if_flags |= IFF_OACTIVE; 50563670Snsayer 50663670Snsayer if (ifp->if_snd.ifq_len != 0) { 50763670Snsayer if (tp->tap_flags & TAP_RWAIT) { 50863670Snsayer tp->tap_flags &= ~TAP_RWAIT; 509111748Sdes wakeup(tp); 51063670Snsayer } 51163670Snsayer 51263670Snsayer if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 51395883Salfred pgsigio(&tp->tap_sigio, SIGIO, 0); 51463670Snsayer 515122352Stanimura selwakeuppri(&tp->tap_rsel, PZERO+1); 51663670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 51763670Snsayer } 51863670Snsayer 51963670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 52063670Snsayer splx(s); 52163670Snsayer} /* tapifstart */ 52263670Snsayer 52363670Snsayer 52463670Snsayer/* 52563670Snsayer * tapioctl 52663670Snsayer * 52763670Snsayer * the cdevsw interface is now pretty minimal 52863670Snsayer */ 52963670Snsayerstatic int 53083366Sjuliantapioctl(dev, cmd, data, flag, td) 53163670Snsayer dev_t dev; 53263670Snsayer u_long cmd; 53363670Snsayer caddr_t data; 53463670Snsayer int flag; 53583366Sjulian struct thread *td; 53663670Snsayer{ 53763670Snsayer struct tap_softc *tp = dev->si_drv1; 53863670Snsayer struct ifnet *ifp = &tp->tap_if; 539111742Sdes struct tapinfo *tapp = NULL; 54063670Snsayer int s; 541102052Ssobomax int f; 54263670Snsayer 54363670Snsayer switch (cmd) { 544111742Sdes case TAPSIFINFO: 54563670Snsayer s = splimp(); 546111742Sdes tapp = (struct tapinfo *)data; 547111742Sdes ifp->if_mtu = tapp->mtu; 548111742Sdes ifp->if_type = tapp->type; 549111742Sdes ifp->if_baudrate = tapp->baudrate; 55063670Snsayer splx(s); 551111742Sdes break; 55263670Snsayer 553111742Sdes case TAPGIFINFO: 554111742Sdes tapp = (struct tapinfo *)data; 555111742Sdes tapp->mtu = ifp->if_mtu; 556111742Sdes tapp->type = ifp->if_type; 557111742Sdes tapp->baudrate = ifp->if_baudrate; 558111742Sdes break; 55963670Snsayer 56063670Snsayer case TAPSDEBUG: 56163670Snsayer tapdebug = *(int *)data; 56283043Sbrooks break; 56363670Snsayer 56463670Snsayer case TAPGDEBUG: 56563670Snsayer *(int *)data = tapdebug; 56683043Sbrooks break; 56763670Snsayer 56863670Snsayer case FIONBIO: 56983043Sbrooks break; 57063670Snsayer 57163670Snsayer case FIOASYNC: 57263803Snsayer s = splimp(); 57363670Snsayer if (*(int *)data) 57463670Snsayer tp->tap_flags |= TAP_ASYNC; 57563670Snsayer else 57663670Snsayer tp->tap_flags &= ~TAP_ASYNC; 57763803Snsayer splx(s); 57883043Sbrooks break; 57963670Snsayer 58063670Snsayer case FIONREAD: 58163670Snsayer s = splimp(); 58263670Snsayer if (ifp->if_snd.ifq_head) { 58363670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 58463670Snsayer 58563803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 58663670Snsayer *(int *)data += mb->m_len; 58783043Sbrooks } else 58863670Snsayer *(int *)data = 0; 58963670Snsayer splx(s); 59083043Sbrooks break; 59163670Snsayer 59263670Snsayer case FIOSETOWN: 59363670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 59463670Snsayer 59563670Snsayer case FIOGETOWN: 596104393Struckman *(int *)data = fgetown(&tp->tap_sigio); 59763670Snsayer return (0); 59863670Snsayer 59963670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 60063670Snsayer case TIOCSPGRP: 60163670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 60263670Snsayer 60363670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 60463670Snsayer case TIOCGPGRP: 605104393Struckman *(int *)data = -fgetown(&tp->tap_sigio); 60663670Snsayer return (0); 60763670Snsayer 60863670Snsayer /* VMware/VMnet port ioctl's */ 60963670Snsayer 61063670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 61163670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 61283043Sbrooks break; 61363670Snsayer 61483043Sbrooks case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 615102052Ssobomax f = *(int *)data; 61663670Snsayer f &= 0x0fff; 61763670Snsayer f &= ~IFF_CANTCHANGE; 61863670Snsayer f |= IFF_UP; 61963670Snsayer 62063670Snsayer s = splimp(); 62163670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 62263670Snsayer splx(s); 62383043Sbrooks break; 62463670Snsayer 62563861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 62663670Snsayer case SIOCGIFADDR: 62763861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 62883043Sbrooks break; 62963670Snsayer 63063861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 63163861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 63283043Sbrooks break; 63363670Snsayer 63463670Snsayer default: 63563670Snsayer return (ENOTTY); 63663670Snsayer } 63763670Snsayer return (0); 63863670Snsayer} /* tapioctl */ 63963670Snsayer 64063670Snsayer 64163670Snsayer/* 64263670Snsayer * tapread 64363670Snsayer * 64463670Snsayer * the cdevsw read interface - reads a packet at a time, or at 64563670Snsayer * least as much of a packet as can be read 64663670Snsayer */ 64763670Snsayerstatic int 64863670Snsayertapread(dev, uio, flag) 64963670Snsayer dev_t dev; 65063670Snsayer struct uio *uio; 65163670Snsayer int flag; 65263670Snsayer{ 65363670Snsayer struct tap_softc *tp = dev->si_drv1; 65463670Snsayer struct ifnet *ifp = &tp->tap_if; 65590227Sdillon struct mbuf *m = NULL; 65663670Snsayer int error = 0, len, s; 65763670Snsayer 658121816Sbrooks TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 65963670Snsayer 66063670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 661121816Sbrooks TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 662121816Sbrooks ifp->if_xname, minor(dev), tp->tap_flags); 66363803Snsayer 66463670Snsayer return (EHOSTDOWN); 66563670Snsayer } 66663670Snsayer 66763670Snsayer tp->tap_flags &= ~TAP_RWAIT; 66863670Snsayer 66963670Snsayer /* sleep until we get a packet */ 67063670Snsayer do { 67163670Snsayer s = splimp(); 67290227Sdillon IF_DEQUEUE(&ifp->if_snd, m); 67363670Snsayer splx(s); 67463670Snsayer 67590227Sdillon if (m == NULL) { 67663670Snsayer if (flag & IO_NDELAY) 67763670Snsayer return (EWOULDBLOCK); 678111742Sdes 67963670Snsayer tp->tap_flags |= TAP_RWAIT; 680111748Sdes error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 68163670Snsayer if (error) 68263670Snsayer return (error); 68363670Snsayer } 68490227Sdillon } while (m == NULL); 68563670Snsayer 68663670Snsayer /* feed packet to bpf */ 687106939Ssam BPF_MTAP(ifp, m); 68863670Snsayer 68963670Snsayer /* xfer packet to user space */ 69090227Sdillon while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 69190227Sdillon len = min(uio->uio_resid, m->m_len); 69263670Snsayer if (len == 0) 69363670Snsayer break; 69463670Snsayer 695111741Sdes error = uiomove(mtod(m, void *), len, uio); 69690227Sdillon m = m_free(m); 69763670Snsayer } 69863670Snsayer 69990227Sdillon if (m != NULL) { 700121816Sbrooks TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 701121816Sbrooks minor(dev)); 70290227Sdillon m_freem(m); 70363670Snsayer } 70463670Snsayer 70563670Snsayer return (error); 70663670Snsayer} /* tapread */ 70763670Snsayer 70863670Snsayer 70963670Snsayer/* 71063670Snsayer * tapwrite 71163670Snsayer * 71263670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 71363670Snsayer */ 71463670Snsayerstatic int 71563670Snsayertapwrite(dev, uio, flag) 71663670Snsayer dev_t dev; 71763670Snsayer struct uio *uio; 71863670Snsayer int flag; 71963670Snsayer{ 72063670Snsayer struct tap_softc *tp = dev->si_drv1; 72163670Snsayer struct ifnet *ifp = &tp->tap_if; 72263670Snsayer struct mbuf *top = NULL, **mp = NULL, *m = NULL; 723111742Sdes int error = 0, tlen, mlen; 72463670Snsayer 725121816Sbrooks TAPDEBUG("%s writting, minor = %#x\n", 726121816Sbrooks ifp->if_xname, minor(dev)); 72763670Snsayer 72863670Snsayer if (uio->uio_resid == 0) 72963670Snsayer return (0); 73063670Snsayer 73163670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 732121816Sbrooks TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 733121816Sbrooks ifp->if_xname, uio->uio_resid, minor(dev)); 73463803Snsayer 73563670Snsayer return (EIO); 73663670Snsayer } 73763670Snsayer tlen = uio->uio_resid; 73863670Snsayer 73963670Snsayer /* get a header mbuf */ 740111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 74163670Snsayer if (m == NULL) 74263670Snsayer return (ENOBUFS); 74363670Snsayer mlen = MHLEN; 74463670Snsayer 74563670Snsayer top = 0; 74663670Snsayer mp = ⊤ 74763670Snsayer while ((error == 0) && (uio->uio_resid > 0)) { 74863670Snsayer m->m_len = min(mlen, uio->uio_resid); 749111741Sdes error = uiomove(mtod(m, void *), m->m_len, uio); 75063670Snsayer *mp = m; 75163670Snsayer mp = &m->m_next; 75263670Snsayer if (uio->uio_resid > 0) { 753111119Simp MGET(m, M_DONTWAIT, MT_DATA); 75463803Snsayer if (m == NULL) { 75563670Snsayer error = ENOBUFS; 75663670Snsayer break; 75763670Snsayer } 75863670Snsayer mlen = MLEN; 75963670Snsayer } 76063670Snsayer } 76163670Snsayer if (error) { 76263670Snsayer ifp->if_ierrors ++; 76363670Snsayer if (top) 76463670Snsayer m_freem(top); 76563670Snsayer return (error); 76663670Snsayer } 76763670Snsayer 76863670Snsayer top->m_pkthdr.len = tlen; 76963670Snsayer top->m_pkthdr.rcvif = ifp; 770111742Sdes 771106939Ssam /* Pass packet up to parent. */ 772106939Ssam (*ifp->if_input)(ifp, top); 773106939Ssam ifp->if_ipackets ++; /* ibytes are counted in parent */ 77463670Snsayer 77563670Snsayer return (0); 77663670Snsayer} /* tapwrite */ 77763670Snsayer 77863670Snsayer 77963670Snsayer/* 78063670Snsayer * tappoll 78163670Snsayer * 78263670Snsayer * the poll interface, this is only useful on reads 78363670Snsayer * really. the write detect always returns true, write never blocks 78463670Snsayer * anyway, it either accepts the packet or drops it 78563670Snsayer */ 78663670Snsayerstatic int 78783366Sjuliantappoll(dev, events, td) 78863670Snsayer dev_t dev; 78963670Snsayer int events; 79083366Sjulian struct thread *td; 79163670Snsayer{ 79263670Snsayer struct tap_softc *tp = dev->si_drv1; 79363670Snsayer struct ifnet *ifp = &tp->tap_if; 794111742Sdes int s, revents = 0; 79563670Snsayer 796121816Sbrooks TAPDEBUG("%s polling, minor = %#x\n", 797121816Sbrooks ifp->if_xname, minor(dev)); 79863670Snsayer 79963670Snsayer s = splimp(); 80063670Snsayer if (events & (POLLIN | POLLRDNORM)) { 80163670Snsayer if (ifp->if_snd.ifq_len > 0) { 802121816Sbrooks TAPDEBUG("%s have data in queue. len = %d, " \ 803121816Sbrooks "minor = %#x\n", ifp->if_xname, 80483043Sbrooks ifp->if_snd.ifq_len, minor(dev)); 80563803Snsayer 80663670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 80783043Sbrooks } else { 808121816Sbrooks TAPDEBUG("%s waiting for data, minor = %#x\n", 809121816Sbrooks ifp->if_xname, minor(dev)); 81063803Snsayer 81183805Sjhb selrecord(td, &tp->tap_rsel); 81263670Snsayer } 81363670Snsayer } 81463670Snsayer 81563670Snsayer if (events & (POLLOUT | POLLWRNORM)) 81663670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 81763670Snsayer 81863670Snsayer splx(s); 81963670Snsayer return (revents); 82063670Snsayer} /* tappoll */ 821