if_tap.c revision 137101
11590Srgrimes/* 21590Srgrimes * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 31590Srgrimes * All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 141590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241590Srgrimes * SUCH DAMAGE. 251590Srgrimes * 261590Srgrimes * BASED ON: 271590Srgrimes * ------------------------------------------------------------------------- 281590Srgrimes * 291590Srgrimes * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 301590Srgrimes * Nottingham University 1987. 311590Srgrimes */ 321590Srgrimes 331590Srgrimes/* 3487690Smarkm * $FreeBSD: head/sys/net/if_tap.c 137101 2004-10-31 17:39:46Z glebius $ 3587690Smarkm * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3687690Smarkm */ 3787690Smarkm 381590Srgrimes#include "opt_inet.h" 3928693Scharnier 401590Srgrimes#include <sys/param.h> 411590Srgrimes#include <sys/conf.h> 4287690Smarkm#include <sys/filedesc.h> 431590Srgrimes#include <sys/filio.h> 441590Srgrimes#include <sys/kernel.h> 4587690Smarkm#include <sys/malloc.h> 4628693Scharnier#include <sys/mbuf.h> 471590Srgrimes#include <sys/module.h> 481590Srgrimes#include <sys/poll.h> 491590Srgrimes#include <sys/proc.h> 501590Srgrimes#include <sys/signalvar.h> 511590Srgrimes#include <sys/socket.h> 5212811Sbde#include <sys/sockio.h> 531590Srgrimes#include <sys/sysctl.h> 541590Srgrimes#include <sys/systm.h> 551590Srgrimes#include <sys/ttycom.h> 561590Srgrimes#include <sys/uio.h> 571590Srgrimes#include <sys/vnode.h> 581590Srgrimes#include <sys/queue.h> 5912804Speter 6012811Sbde#include <net/bpf.h> 6112811Sbde#include <net/ethernet.h> 6212811Sbde#include <net/if.h> 6328693Scharnier#include <net/if_arp.h> 6487690Smarkm#include <net/route.h> 6528693Scharnier 6628693Scharnier#include <netinet/in.h> 6728693Scharnier 6828693Scharnier#include <net/if_tapvar.h> 691590Srgrimes#include <net/if_tap.h> 7028693Scharnier 711590Srgrimes 721590Srgrimes#define CDEV_NAME "tap" 731590Srgrimes#define TAPDEBUG if (tapdebug) printf 7430180Sdima 7528693Scharnier#define TAP "tap" 7628693Scharnier#define VMNET "vmnet" 771590Srgrimes#define TAPMAXUNIT 0x7fff 7887690Smarkm#define VMNET_DEV_MASK CLONE_FLAG0 7987690Smarkm 8087690Smarkm/* module */ 811590Srgrimesstatic int tapmodevent(module_t, int, void *); 821590Srgrimes 8339230Sgibbs/* device */ 841590Srgrimesstatic void tapclone(void *, char *, int, struct cdev **); 8539230Sgibbsstatic void tapcreate(struct cdev *); 861590Srgrimes 8739230Sgibbs/* network interface */ 881590Srgrimesstatic void tapifstart(struct ifnet *); 8939230Sgibbsstatic int tapifioctl(struct ifnet *, u_long, caddr_t); 901590Srgrimesstatic void tapifinit(void *); 9139230Sgibbs 921590Srgrimes/* character device */ 9339230Sgibbsstatic d_open_t tapopen; 941590Srgrimesstatic d_close_t tapclose; 9539230Sgibbsstatic d_read_t tapread; 961590Srgrimesstatic d_write_t tapwrite; 9739230Sgibbsstatic d_ioctl_t tapioctl; 981590Srgrimesstatic d_poll_t tappoll; 9939230Sgibbs 1001590Srgrimesstatic struct cdevsw tap_cdevsw = { 10130180Sdima .d_version = D_VERSION, 10294729Sjeff .d_flags = D_PSEUDO | D_NEEDGIANT, 1031590Srgrimes .d_open = tapopen, 10494729Sjeff .d_close = tapclose, 1051590Srgrimes .d_read = tapread, 10694729Sjeff .d_write = tapwrite, 1071590Srgrimes .d_ioctl = tapioctl, 10894729Sjeff .d_poll = tappoll, 1091590Srgrimes .d_name = CDEV_NAME, 11094729Sjeff}; 1111590Srgrimes 11294729Sjeff/* 11392653Sjeff * All global variables in if_tap.c are locked with tapmtx, with the 11494729Sjeff * exception of tapdebug, which is accessed unlocked; tapclones is 1151590Srgrimes * static at runtime. 1161590Srgrimes */ 1171590Srgrimesstatic struct mtx tapmtx; 1181590Srgrimesstatic int tapdebug = 0; /* debug flag */ 11939230Sgibbsstatic SLIST_HEAD(, tap_softc) taphead; /* first device */ 12039498Skenstatic struct clonedevs *tapclones; 12139498Sken 12239230SgibbsMALLOC_DECLARE(M_TAP); 12339230SgibbsMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12439230SgibbsSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 12539230SgibbsDEV_MODULE(if_tap, tapmodevent, NULL); 12639498Sken 12739498Sken/* 12839230Sgibbs * tapmodevent 12939230Sgibbs * 1301590Srgrimes * module event handler 1311590Srgrimes */ 1321590Srgrimesstatic int 1331590Srgrimestapmodevent(mod, type, data) 13439372Sdillon module_t mod; 1351590Srgrimes int type; 1361590Srgrimes void *data; 1371590Srgrimes{ 1381590Srgrimes static eventhandler_tag eh_tag = NULL; 1391590Srgrimes struct tap_softc *tp = NULL; 1401590Srgrimes struct ifnet *ifp = NULL; 1411590Srgrimes int s; 1421590Srgrimes 1431590Srgrimes switch (type) { 14443962Sdillon case MOD_LOAD: 1451590Srgrimes 14692922Simp /* intitialize device */ 14792922Simp 14894729Sjeff mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF); 14992922Simp SLIST_INIT(&taphead); 15092922Simp 15192922Simp clone_setup(&tapclones); 15292922Simp eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 15392922Simp if (eh_tag == NULL) { 15492922Simp clone_cleanup(&tapclones); 15592922Simp mtx_destroy(&tapmtx); 15692922Simp return (ENOMEM); 15792922Simp } 1581590Srgrimes return (0); 15992922Simp 16092922Simp case MOD_UNLOAD: 16187690Smarkm /* 16292922Simp * The EBUSY algorithm here can't quite atomically 16387690Smarkm * guarantee that this is race-free since we have to 16428693Scharnier * release the tap mtx to deregister the clone handler. 1651590Srgrimes */ 16687690Smarkm mtx_lock(&tapmtx); 16787690Smarkm SLIST_FOREACH(tp, &taphead, tap_next) { 1681590Srgrimes mtx_lock(&tp->tap_mtx); 16987690Smarkm if (tp->tap_flags & TAP_OPEN) { 1701590Srgrimes mtx_unlock(&tp->tap_mtx); 1711590Srgrimes mtx_unlock(&tapmtx); 1721590Srgrimes return (EBUSY); 17378474Sschweikh } 1741590Srgrimes mtx_unlock(&tp->tap_mtx); 1751590Srgrimes } 1761590Srgrimes mtx_unlock(&tapmtx); 17743822Sken 17844067Sbde EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 1791590Srgrimes 1801590Srgrimes mtx_lock(&tapmtx); 1811590Srgrimes while ((tp = SLIST_FIRST(&taphead)) != NULL) { 1821590Srgrimes SLIST_REMOVE_HEAD(&taphead, tap_next); 1831590Srgrimes mtx_unlock(&tapmtx); 18430180Sdima 1851590Srgrimes ifp = &tp->tap_if; 1861590Srgrimes 1871590Srgrimes TAPDEBUG("detaching %s\n", ifp->if_xname); 1881590Srgrimes 1891590Srgrimes /* Unlocked read. */ 1901590Srgrimes KASSERT(!(tp->tap_flags & TAP_OPEN), 1911590Srgrimes ("%s flags is out of sync", ifp->if_xname)); 1921590Srgrimes 1931590Srgrimes destroy_dev(tp->tap_dev); 1941590Srgrimes s = splimp(); 1951590Srgrimes ether_ifdetach(ifp); 1961590Srgrimes splx(s); 1971590Srgrimes 19839230Sgibbs mtx_destroy(&tp->tap_mtx); 19939372Sdillon free(tp, M_TAP); 20039230Sgibbs mtx_lock(&tapmtx); 20139230Sgibbs } 20239230Sgibbs mtx_unlock(&tapmtx); 20339230Sgibbs clone_cleanup(&tapclones); 20439230Sgibbs 20539230Sgibbs mtx_destroy(&tapmtx); 20639230Sgibbs 20739230Sgibbs break; 20839230Sgibbs 2091590Srgrimes default: 2101590Srgrimes return (EOPNOTSUPP); 2111590Srgrimes } 2121590Srgrimes 21330180Sdima return (0); 2141590Srgrimes} /* tapmodevent */ 21530180Sdima 21630180Sdima 21730180Sdima/* 2181590Srgrimes * DEVFS handler 2191590Srgrimes * 2201590Srgrimes * We need to support two kind of devices - tap and vmnet 2211590Srgrimes */ 22244067Sbdestatic void 22344067Sbdetapclone(arg, name, namelen, dev) 22444067Sbde void *arg; 2251590Srgrimes char *name; 2261590Srgrimes int namelen; 2271590Srgrimes struct cdev **dev; 2281590Srgrimes{ 2291590Srgrimes u_int extra; 2301590Srgrimes int i, unit; 2311590Srgrimes char *device_name = name; 2321590Srgrimes 2331590Srgrimes if (*dev != NULL) 2341590Srgrimes return; 2351590Srgrimes 2361590Srgrimes device_name = TAP; 2371590Srgrimes extra = 0; 2381590Srgrimes if (strcmp(name, TAP) == 0) { 2391590Srgrimes unit = -1; 2401590Srgrimes } else if (strcmp(name, VMNET) == 0) { 2411590Srgrimes device_name = VMNET; 2421590Srgrimes extra = VMNET_DEV_MASK; 24328693Scharnier unit = -1; 24428693Scharnier } else if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 24528693Scharnier device_name = VMNET; 24682664Sru extra = VMNET_DEV_MASK; 2471590Srgrimes if (dev_stdclone(name, NULL, device_name, &unit) != 1) 2481590Srgrimes return; 2491590Srgrimes } 25028693Scharnier 2511590Srgrimes /* find any existing device, or allocate new unit number */ 25287690Smarkm i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra); 25387690Smarkm if (i) { 2541590Srgrimes *dev = make_dev(&tap_cdevsw, unit2minor(unit | extra), 25581537Sken UID_ROOT, GID_WHEEL, 0600, "%s%d", device_name, unit); 2561590Srgrimes if (*dev != NULL) 2571590Srgrimes (*dev)->si_flags |= SI_CHEAPCLONE; 2581590Srgrimes } 25928693Scharnier} /* tapclone */ 2601590Srgrimes 2611590Srgrimes 2621590Srgrimes/* 2631590Srgrimes * tapcreate 2641590Srgrimes * 2651590Srgrimes * to create interface 26643819Sken */ 26743819Skenstatic void 26843819Skentapcreate(dev) 26943819Sken struct cdev *dev; 27043819Sken{ 27143819Sken struct ifnet *ifp = NULL; 27243819Sken struct tap_softc *tp = NULL; 27343819Sken unsigned short macaddr_hi; 27443819Sken int unit, s; 2751590Srgrimes char *name = NULL; 2761590Srgrimes 2771590Srgrimes dev->si_flags &= ~SI_CHEAPCLONE; 2781590Srgrimes 2791590Srgrimes /* allocate driver storage and create device */ 2801590Srgrimes MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 2811590Srgrimes mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF); 2821590Srgrimes mtx_lock(&tapmtx); 2831590Srgrimes SLIST_INSERT_HEAD(&taphead, tp, tap_next); 2841590Srgrimes mtx_unlock(&tapmtx); 2851590Srgrimes 2861590Srgrimes unit = dev2unit(dev); 2871590Srgrimes 2881590Srgrimes /* select device: tap or vmnet */ 2891590Srgrimes if (unit & VMNET_DEV_MASK) { 2901590Srgrimes name = VMNET; 2911590Srgrimes tp->tap_flags |= TAP_VMNET; 2921590Srgrimes } else 2931590Srgrimes name = TAP; 2941590Srgrimes 2951590Srgrimes unit &= TAPMAXUNIT; 2961590Srgrimes 2971590Srgrimes TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 29830180Sdima 2991590Srgrimes /* generate fake MAC address: 00 bd xx xx xx unit_no */ 3001590Srgrimes macaddr_hi = htons(0x00bd); 3011590Srgrimes bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 3021590Srgrimes bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 3031590Srgrimes tp->arpcom.ac_enaddr[5] = (u_char)unit; 30443962Sdillon 30543962Sdillon /* fill the rest and attach interface */ 3061590Srgrimes ifp = &tp->tap_if; 3071590Srgrimes ifp->if_softc = tp; 30830180Sdima if_initname(ifp, name, unit); 3091590Srgrimes ifp->if_init = tapifinit; 3101590Srgrimes ifp->if_start = tapifstart; 3111590Srgrimes ifp->if_ioctl = tapifioctl; 3121590Srgrimes ifp->if_mtu = ETHERMTU; 3131590Srgrimes ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 3141590Srgrimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 3151590Srgrimes 3161590Srgrimes dev->si_drv1 = tp; 3171590Srgrimes tp->tap_dev = dev; 3181590Srgrimes 3191590Srgrimes s = splimp(); 3201590Srgrimes ether_ifattach(ifp, tp->arpcom.ac_enaddr); 3211590Srgrimes splx(s); 3221590Srgrimes 32339230Sgibbs mtx_lock(&tp->tap_mtx); 32439230Sgibbs tp->tap_flags |= TAP_INITED; 3251590Srgrimes mtx_unlock(&tp->tap_mtx); 32639230Sgibbs 32739230Sgibbs TAPDEBUG("interface %s is created. minor = %#x\n", 32839230Sgibbs ifp->if_xname, minor(dev)); 32939230Sgibbs} /* tapcreate */ 33039230Sgibbs 33139230Sgibbs 33239230Sgibbs/* 33339230Sgibbs * tapopen 33439230Sgibbs * 33539230Sgibbs * to open tunnel. must be superuser 33639230Sgibbs */ 33739230Sgibbsstatic int 33839230Sgibbstapopen(dev, flag, mode, td) 3391590Srgrimes struct cdev *dev; 3401590Srgrimes int flag; 34139230Sgibbs int mode; 34239230Sgibbs struct thread *td; 34339230Sgibbs{ 34439230Sgibbs struct tap_softc *tp = NULL; 34539230Sgibbs struct ifnet *ifp = NULL; 3461590Srgrimes int error, s; 34739230Sgibbs 34839230Sgibbs if ((error = suser(td)) != 0) 34939372Sdillon return (error); 35039372Sdillon 35139372Sdillon if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT) 35239230Sgibbs return (ENXIO); 35339230Sgibbs 35439230Sgibbs /* 35539230Sgibbs * XXXRW: Non-atomic test-and-set of si_drv1. Currently protected 35639230Sgibbs * by Giant, but the race actually exists under memory pressure as 35739230Sgibbs * well even when running with Giant, as malloc() may sleep. 35839230Sgibbs */ 35939230Sgibbs tp = dev->si_drv1; 36039230Sgibbs if (tp == NULL) { 36139230Sgibbs tapcreate(dev); 36239230Sgibbs tp = dev->si_drv1; 36387690Smarkm } 36439230Sgibbs 36539230Sgibbs mtx_lock(&tp->tap_mtx); 36639230Sgibbs if (tp->tap_flags & TAP_OPEN) { 36739230Sgibbs mtx_unlock(&tp->tap_mtx); 36839230Sgibbs return (EBUSY); 36939230Sgibbs } 37039230Sgibbs 37139230Sgibbs bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 37239230Sgibbs tp->tap_pid = td->td_proc->p_pid; 37339230Sgibbs tp->tap_flags |= TAP_OPEN; 37439230Sgibbs ifp = &tp->tap_if; 37539230Sgibbs mtx_unlock(&tp->tap_mtx); 37639230Sgibbs 37739230Sgibbs s = splimp(); 37839230Sgibbs ifp->if_flags |= IFF_RUNNING; 37939230Sgibbs ifp->if_flags &= ~IFF_OACTIVE; 38039230Sgibbs splx(s); 38139230Sgibbs 3821590Srgrimes TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, minor(dev)); 3831590Srgrimes 3841590Srgrimes return (0); 3851590Srgrimes} /* tapopen */ 3861590Srgrimes 3871590Srgrimes 388101590Stmm/* 389101590Stmm * tapclose 3901590Srgrimes * 3911590Srgrimes * close the device - mark i/f down & delete routing info 392101590Stmm */ 3931590Srgrimesstatic int 3941590Srgrimestapclose(dev, foo, bar, td) 395101590Stmm struct cdev *dev; 39628693Scharnier int foo; 39728693Scharnier int bar; 3981590Srgrimes struct thread *td; 3991590Srgrimes{ 4001590Srgrimes struct tap_softc *tp = dev->si_drv1; 4011590Srgrimes struct ifnet *ifp = &tp->tap_if; 4021590Srgrimes int s; 4031590Srgrimes 4041590Srgrimes /* junk all pending output */ 4051590Srgrimes IF_DRAIN(&ifp->if_snd); 4061590Srgrimes 4071590Srgrimes /* 4081590Srgrimes * do not bring the interface down, and do not anything with 4091590Srgrimes * interface, if we are in VMnet mode. just close the device. 41039230Sgibbs */ 41180551Stmm 41280551Stmm mtx_lock(&tp->tap_mtx); 4131590Srgrimes if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 4141590Srgrimes mtx_unlock(&tp->tap_mtx); 4151590Srgrimes s = splimp(); 4161590Srgrimes if_down(ifp); 4171590Srgrimes if (ifp->if_flags & IFF_RUNNING) { 4181590Srgrimes /* find internet addresses and delete routes */ 4191590Srgrimes struct ifaddr *ifa = NULL; 4201590Srgrimes 4211590Srgrimes /* In desparate need of ifaddr locking. */ 4221590Srgrimes TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 4231590Srgrimes if (ifa->ifa_addr->sa_family == AF_INET) { 4241590Srgrimes rtinit(ifa, (int)RTM_DELETE, 0); 4251590Srgrimes 42639230Sgibbs /* remove address from interface */ 42739230Sgibbs bzero(ifa->ifa_addr, 42839230Sgibbs sizeof(*(ifa->ifa_addr))); 42939230Sgibbs bzero(ifa->ifa_dstaddr, 43039230Sgibbs sizeof(*(ifa->ifa_dstaddr))); 43139230Sgibbs bzero(ifa->ifa_netmask, 43239230Sgibbs sizeof(*(ifa->ifa_netmask))); 43339230Sgibbs } 43439230Sgibbs } 43539230Sgibbs 43639230Sgibbs ifp->if_flags &= ~IFF_RUNNING; 43739230Sgibbs } 43839230Sgibbs splx(s); 43939230Sgibbs } else 44039230Sgibbs mtx_unlock(&tp->tap_mtx); 44139230Sgibbs 44239230Sgibbs funsetown(&tp->tap_sigio); 44339230Sgibbs selwakeuppri(&tp->tap_rsel, PZERO+1); 44439230Sgibbs 44539230Sgibbs mtx_lock(&tp->tap_mtx); 44639230Sgibbs tp->tap_flags &= ~TAP_OPEN; 44739230Sgibbs tp->tap_pid = 0; 44839230Sgibbs mtx_unlock(&tp->tap_mtx); 44939230Sgibbs 45039230Sgibbs TAPDEBUG("%s is closed. minor = %#x\n", 45139230Sgibbs ifp->if_xname, minor(dev)); 45239230Sgibbs 45339230Sgibbs return (0); 45439230Sgibbs} /* tapclose */ 45539230Sgibbs 45639230Sgibbs 45739230Sgibbs/* 45839230Sgibbs * tapifinit 45939230Sgibbs * 46039230Sgibbs * network interface initialization function 46139230Sgibbs */ 46239230Sgibbsstatic void 46339230Sgibbstapifinit(xtp) 46439230Sgibbs void *xtp; 46539230Sgibbs{ 46639230Sgibbs struct tap_softc *tp = (struct tap_softc *)xtp; 46739230Sgibbs struct ifnet *ifp = &tp->tap_if; 46839230Sgibbs 46939230Sgibbs TAPDEBUG("initializing %s\n", ifp->if_xname); 47039230Sgibbs 47139230Sgibbs ifp->if_flags |= IFF_RUNNING; 4721590Srgrimes ifp->if_flags &= ~IFF_OACTIVE; 4731590Srgrimes 4741590Srgrimes /* attempt to start output */ 4751590Srgrimes tapifstart(ifp); 4761590Srgrimes} /* tapifinit */ 47781537Sken 47881537Sken 4791590Srgrimes/* 4801590Srgrimes * tapifioctl 48178672Sschweikh * 4821590Srgrimes * Process an ioctl request on network interface 48372887Salfred */ 4841590Srgrimesstatic int 48581537Skentapifioctl(ifp, cmd, data) 48681537Sken struct ifnet *ifp; 48737453Sbde u_long cmd; 48837453Sbde caddr_t data; 4891590Srgrimes{ 49037453Sbde struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 49137453Sbde struct ifstat *ifs = NULL; 49237453Sbde int s, dummy; 4933659Sdg 49437453Sbde switch (cmd) { 49537453Sbde case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 4963693Sdg case SIOCADDMULTI: 49737453Sbde case SIOCDELMULTI: 49837453Sbde break; 49937453Sbde 50037453Sbde case SIOCGIFSTATUS: 50139230Sgibbs s = splimp(); 5021590Srgrimes ifs = (struct ifstat *)data; 50337453Sbde dummy = strlen(ifs->ascii); 50437453Sbde mtx_lock(&tp->tap_mtx); 50537453Sbde if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 5061590Srgrimes snprintf(ifs->ascii + dummy, 5071590Srgrimes sizeof(ifs->ascii) - dummy, 5081590Srgrimes "\tOpened by PID %d\n", tp->tap_pid); 5091590Srgrimes mtx_unlock(&tp->tap_mtx); 5101590Srgrimes splx(s); 5111590Srgrimes break; 5121590Srgrimes 5131590Srgrimes default: 5141590Srgrimes s = splimp(); 5151590Srgrimes dummy = ether_ioctl(ifp, cmd, data); 5161590Srgrimes splx(s); 5173659Sdg return (dummy); 5183659Sdg } 5193659Sdg 5203659Sdg return (0); 5211590Srgrimes} /* tapifioctl */ 5221590Srgrimes 5231590Srgrimes 5241590Srgrimes/* 52528693Scharnier * tapifstart 5261590Srgrimes * 5271590Srgrimes * queue packets from higher level ready to put out 52843822Sken */ 5291590Srgrimesstatic void 53043822Skentapifstart(ifp) 53178672Sschweikh struct ifnet *ifp; 53243822Sken{ 53343822Sken struct tap_softc *tp = ifp->if_softc; 53443822Sken int s; 53543822Sken 53643822Sken TAPDEBUG("%s starting\n", ifp->if_xname); 53778672Sschweikh 53839230Sgibbs /* 53939230Sgibbs * do not junk pending output if we are in VMnet mode. 54039230Sgibbs * XXX: can this do any harm because of queue overflow? 54139230Sgibbs */ 54239230Sgibbs 54339230Sgibbs mtx_lock(&tp->tap_mtx); 5441590Srgrimes if (((tp->tap_flags & TAP_VMNET) == 0) && 5451590Srgrimes ((tp->tap_flags & TAP_READY) != TAP_READY)) { 5461590Srgrimes struct mbuf *m = NULL; 5471590Srgrimes 5481590Srgrimes mtx_unlock(&tp->tap_mtx); 5491590Srgrimes 5501590Srgrimes /* Unlocked read. */ 5511590Srgrimes TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 55287690Smarkm tp->tap_flags); 55387690Smarkm 5541590Srgrimes s = splimp(); 5551590Srgrimes do { 5561590Srgrimes IF_DEQUEUE(&ifp->if_snd, m); 5571590Srgrimes if (m != NULL) 5581590Srgrimes m_freem(m); 55930180Sdima ifp->if_oerrors ++; 5601590Srgrimes } while (m != NULL); 5611590Srgrimes splx(s); 5621590Srgrimes 5631590Srgrimes return; 5641590Srgrimes } 5651590Srgrimes mtx_unlock(&tp->tap_mtx); 5661590Srgrimes 5671590Srgrimes s = splimp(); 5681590Srgrimes ifp->if_flags |= IFF_OACTIVE; 5691590Srgrimes 5701590Srgrimes if (ifp->if_snd.ifq_len != 0) { 5711590Srgrimes mtx_lock(&tp->tap_mtx); 5721590Srgrimes if (tp->tap_flags & TAP_RWAIT) { 5731590Srgrimes tp->tap_flags &= ~TAP_RWAIT; 5741590Srgrimes wakeup(tp); 5751590Srgrimes } 5761590Srgrimes 5771590Srgrimes if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { 5781590Srgrimes mtx_unlock(&tp->tap_mtx); 57928693Scharnier pgsigio(&tp->tap_sigio, SIGIO, 0); 5801590Srgrimes } else 5811590Srgrimes mtx_unlock(&tp->tap_mtx); 5821590Srgrimes 5831590Srgrimes selwakeuppri(&tp->tap_rsel, PZERO+1); 5841590Srgrimes ifp->if_opackets ++; /* obytes are counted in ether_output */ 5851590Srgrimes } 5861590Srgrimes 5871590Srgrimes ifp->if_flags &= ~IFF_OACTIVE; 5881590Srgrimes splx(s); 5891590Srgrimes} /* tapifstart */ 5901590Srgrimes 5911590Srgrimes 5921590Srgrimes/* 5931590Srgrimes * tapioctl 5941590Srgrimes * 5951590Srgrimes * the cdevsw interface is now pretty minimal 59687690Smarkm */ 5971590Srgrimesstatic int 5981590Srgrimestapioctl(dev, cmd, data, flag, td) 5991590Srgrimes struct cdev *dev; 6001590Srgrimes u_long cmd; 6011590Srgrimes caddr_t data; 6021590Srgrimes int flag; 6031590Srgrimes struct thread *td; 6041590Srgrimes{ 60571429Sume struct tap_softc *tp = dev->si_drv1; 60671429Sume struct ifnet *ifp = &tp->tap_if; 60771429Sume struct tapinfo *tapp = NULL; 60871429Sume int s; 6093659Sdg int f; 6103693Sdg 6113659Sdg switch (cmd) { 6123659Sdg case TAPSIFINFO: 6133659Sdg s = splimp(); 6143693Sdg tapp = (struct tapinfo *)data; 6153659Sdg ifp->if_mtu = tapp->mtu; 6163659Sdg ifp->if_type = tapp->type; 6173693Sdg ifp->if_baudrate = tapp->baudrate; 6183693Sdg splx(s); 6191590Srgrimes break; 6207351Sdg 62134214Sdyson case TAPGIFINFO: 6227351Sdg tapp = (struct tapinfo *)data; 62334214Sdyson tapp->mtu = ifp->if_mtu; 6241590Srgrimes tapp->type = ifp->if_type; 6251590Srgrimes tapp->baudrate = ifp->if_baudrate; 62671429Sume break; 62771429Sume 62871429Sume case TAPSDEBUG: 62971429Sume tapdebug = *(int *)data; 6303693Sdg break; 6311590Srgrimes 6321590Srgrimes case TAPGDEBUG: 6331590Srgrimes *(int *)data = tapdebug; 6341590Srgrimes break; 6355463Sdg 6363693Sdg case FIONBIO: 6373693Sdg break; 6381590Srgrimes 63987690Smarkm case FIOASYNC: 64087690Smarkm s = splimp(); 64187690Smarkm mtx_lock(&tp->tap_mtx); 64287690Smarkm if (*(int *)data) 6431590Srgrimes tp->tap_flags |= TAP_ASYNC; 6441590Srgrimes else 64528693Scharnier tp->tap_flags &= ~TAP_ASYNC; 64687690Smarkm mtx_unlock(&tp->tap_mtx); 64787690Smarkm splx(s); 64887690Smarkm break; 64928693Scharnier 65087690Smarkm case FIONREAD: 65187690Smarkm s = splimp(); 65287690Smarkm if (ifp->if_snd.ifq_head) { 6531590Srgrimes struct mbuf *mb = ifp->if_snd.ifq_head; 6541590Srgrimes 65530180Sdima for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 6561590Srgrimes *(int *)data += mb->m_len; 6571590Srgrimes } else 6581590Srgrimes *(int *)data = 0; 6591590Srgrimes splx(s); 6601590Srgrimes break; 6611590Srgrimes 6621590Srgrimes case FIOSETOWN: 6631590Srgrimes return (fsetown(*(int *)data, &tp->tap_sigio)); 6641590Srgrimes 6651590Srgrimes case FIOGETOWN: 6661590Srgrimes *(int *)data = fgetown(&tp->tap_sigio); 6671590Srgrimes return (0); 6681590Srgrimes 66939230Sgibbs /* this is deprecated, FIOSETOWN should be used instead */ 67039230Sgibbs case TIOCSPGRP: 6711590Srgrimes return (fsetown(-(*(int *)data), &tp->tap_sigio)); 67287690Smarkm 67339230Sgibbs /* this is deprecated, FIOGETOWN should be used instead */ 67439230Sgibbs case TIOCGPGRP: 6751590Srgrimes *(int *)data = -fgetown(&tp->tap_sigio); 67639230Sgibbs return (0); 6771590Srgrimes 67839230Sgibbs /* VMware/VMnet port ioctl's */ 67939230Sgibbs 68039230Sgibbs case SIOCGIFFLAGS: /* get ifnet flags */ 6811590Srgrimes bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 68239230Sgibbs break; 68339230Sgibbs 68439230Sgibbs case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 68539230Sgibbs f = *(int *)data; 68639230Sgibbs f &= 0x0fff; 68739230Sgibbs f &= ~IFF_CANTCHANGE; 68839230Sgibbs f |= IFF_UP; 68939230Sgibbs 6901590Srgrimes s = splimp(); 69139230Sgibbs ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 69239230Sgibbs splx(s); 69339230Sgibbs break; 69481537Sken 69581537Sken case OSIOCGIFADDR: /* get MAC address of the remote side */ 69681537Sken case SIOCGIFADDR: 69781537Sken mtx_lock(&tp->tap_mtx); 69839230Sgibbs bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 69939230Sgibbs mtx_unlock(&tp->tap_mtx); 70081537Sken break; 7011590Srgrimes 7021590Srgrimes case SIOCSIFADDR: /* set MAC address of the remote side */ 7031590Srgrimes mtx_lock(&tp->tap_mtx); 7041590Srgrimes bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 7051590Srgrimes mtx_unlock(&tp->tap_mtx); 7061590Srgrimes break; 70787690Smarkm 70887690Smarkm default: 7091590Srgrimes return (ENOTTY); 7101590Srgrimes } 7111590Srgrimes return (0); 71239230Sgibbs} /* tapioctl */ 7131590Srgrimes 71487690Smarkm 7151590Srgrimes/* 71687690Smarkm * tapread 71739230Sgibbs * 71887690Smarkm * the cdevsw read interface - reads a packet at a time, or at 71939230Sgibbs * least as much of a packet as can be read 72087690Smarkm */ 72187690Smarkmstatic int 7221590Srgrimestapread(dev, uio, flag) 7231590Srgrimes struct cdev *dev; 7241590Srgrimes struct uio *uio; 7251590Srgrimes int flag; 7261590Srgrimes{ 72787690Smarkm struct tap_softc *tp = dev->si_drv1; 72887690Smarkm struct ifnet *ifp = &tp->tap_if; 72987690Smarkm struct mbuf *m = NULL; 73087690Smarkm int error = 0, len, s; 7311590Srgrimes 7321590Srgrimes TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev)); 7331590Srgrimes 7341590Srgrimes mtx_lock(&tp->tap_mtx); 7351590Srgrimes if ((tp->tap_flags & TAP_READY) != TAP_READY) { 7361590Srgrimes mtx_unlock(&tp->tap_mtx); 7371590Srgrimes 73828693Scharnier /* Unlocked read. */ 73928693Scharnier TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n", 7401590Srgrimes ifp->if_xname, minor(dev), tp->tap_flags); 7411590Srgrimes 74278849Sschweikh return (EHOSTDOWN); 7431590Srgrimes } 7441590Srgrimes 7451590Srgrimes tp->tap_flags &= ~TAP_RWAIT; 7461590Srgrimes mtx_unlock(&tp->tap_mtx); 74778849Sschweikh 7481590Srgrimes /* sleep until we get a packet */ 7491590Srgrimes do { 7501590Srgrimes s = splimp(); 7511590Srgrimes IF_DEQUEUE(&ifp->if_snd, m); 75278849Sschweikh splx(s); 75349107Sn_hibma 7541590Srgrimes if (m == NULL) { 7551590Srgrimes if (flag & IO_NDELAY) 75694729Sjeff return (EWOULDBLOCK); 75794729Sjeff 75894729Sjeff mtx_lock(&tp->tap_mtx); 75994729Sjeff tp->tap_flags |= TAP_RWAIT; 76094729Sjeff mtx_unlock(&tp->tap_mtx); 76146852Simp error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); 7621590Srgrimes if (error) 76394729Sjeff return (error); 7641590Srgrimes } 76594729Sjeff } while (m == NULL); 7661590Srgrimes 7671590Srgrimes /* feed packet to bpf */ 76843962Sdillon BPF_MTAP(ifp, m); 76994729Sjeff 77043962Sdillon /* xfer packet to user space */ 77171404Sdes while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 77271404Sdes len = min(uio->uio_resid, m->m_len); 77343962Sdillon if (len == 0) 77471404Sdes break; 77571404Sdes 77671404Sdes error = uiomove(mtod(m, void *), len, uio); 77771404Sdes m = m_free(m); 77871404Sdes } 77994729Sjeff 78043962Sdillon if (m != NULL) { 78171404Sdes TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 78271404Sdes minor(dev)); 78371404Sdes m_freem(m); 78443962Sdillon } 78571404Sdes 78671404Sdes return (error); 78771404Sdes} /* tapread */ 78843962Sdillon 78943962Sdillon 7901590Srgrimes/* 7911590Srgrimes * tapwrite 7921590Srgrimes * 7931590Srgrimes * the cdevsw write interface - an atomic write is a packet - or else! 7941590Srgrimes */ 7951590Srgrimesstatic int 7961590Srgrimestapwrite(dev, uio, flag) 7971590Srgrimes struct cdev *dev; 7981590Srgrimes struct uio *uio; 7991590Srgrimes int flag; 8001590Srgrimes{ 80140690Sjdp struct tap_softc *tp = dev->si_drv1; 8021590Srgrimes struct ifnet *ifp = &tp->tap_if; 8031590Srgrimes struct mbuf *m; 8041590Srgrimes int error = 0; 80528693Scharnier 8061590Srgrimes TAPDEBUG("%s writting, minor = %#x\n", 80787690Smarkm ifp->if_xname, minor(dev)); 8081590Srgrimes 8091590Srgrimes if (uio->uio_resid == 0) 8101590Srgrimes return (0); 81128693Scharnier 8121590Srgrimes if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 8131590Srgrimes TAPDEBUG("%s invalid packet len = %d, minor = %#x\n", 8141590Srgrimes ifp->if_xname, uio->uio_resid, minor(dev)); 8151590Srgrimes 8161590Srgrimes return (EIO); 8171590Srgrimes } 81872887Salfred 81972887Salfred if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL) { 82072887Salfred ifp->if_ierrors ++; 8211590Srgrimes return (error); 8221590Srgrimes } 823 824 m->m_pkthdr.rcvif = ifp; 825 826 /* Pass packet up to parent. */ 827 (*ifp->if_input)(ifp, m); 828 ifp->if_ipackets ++; /* ibytes are counted in parent */ 829 830 return (0); 831} /* tapwrite */ 832 833 834/* 835 * tappoll 836 * 837 * the poll interface, this is only useful on reads 838 * really. the write detect always returns true, write never blocks 839 * anyway, it either accepts the packet or drops it 840 */ 841static int 842tappoll(dev, events, td) 843 struct cdev *dev; 844 int events; 845 struct thread *td; 846{ 847 struct tap_softc *tp = dev->si_drv1; 848 struct ifnet *ifp = &tp->tap_if; 849 int s, revents = 0; 850 851 TAPDEBUG("%s polling, minor = %#x\n", 852 ifp->if_xname, minor(dev)); 853 854 s = splimp(); 855 if (events & (POLLIN | POLLRDNORM)) { 856 if (ifp->if_snd.ifq_len > 0) { 857 TAPDEBUG("%s have data in queue. len = %d, " \ 858 "minor = %#x\n", ifp->if_xname, 859 ifp->if_snd.ifq_len, minor(dev)); 860 861 revents |= (events & (POLLIN | POLLRDNORM)); 862 } else { 863 TAPDEBUG("%s waiting for data, minor = %#x\n", 864 ifp->if_xname, minor(dev)); 865 866 selrecord(td, &tp->tap_rsel); 867 } 868 } 869 870 if (events & (POLLOUT | POLLWRNORM)) 871 revents |= (events & (POLLOUT | POLLWRNORM)); 872 873 splx(s); 874 return (revents); 875} /* tappoll */ 876