if_tap.c revision 63861
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 63861 2000-07-25 23:50:30Z nsayer $ 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> 5763670Snsayer 5863670Snsayer#include <net/bpf.h> 5963670Snsayer#include <net/ethernet.h> 6063670Snsayer#include <net/if.h> 6163670Snsayer#include <net/if_arp.h> 6263670Snsayer#include <net/route.h> 6363670Snsayer 6463670Snsayer#include <netinet/in.h> 6563670Snsayer 6663670Snsayer#include <net/if_tapvar.h> 6763670Snsayer#include <net/if_tap.h> 6863670Snsayer 6963670Snsayer 7063670Snsayer#define CDEV_NAME "tap" 7163670Snsayer#define CDEV_MAJOR 149 7263670Snsayer#define TAPDEBUG if (tapdebug) printf 7363670Snsayer 7463670Snsayer#define TAP "tap" 7563670Snsayer#define VMNET "vmnet" 7663670Snsayer#define VMNET_DEV_MASK 0x00010000 7763670Snsayer 7863670Snsayer/* module */ 7963670Snsayerstatic int tapmodevent __P((module_t, int, void *)); 8063670Snsayer 8163670Snsayer/* device */ 8263670Snsayerstatic void tapcreate __P((dev_t)); 8363670Snsayer 8463670Snsayer/* network interface */ 8563670Snsayerstatic void tapifstart __P((struct ifnet *)); 8663670Snsayerstatic int tapifioctl __P((struct ifnet *, u_long, caddr_t)); 8763670Snsayerstatic void tapifinit __P((void *)); 8863670Snsayer 8963670Snsayer/* character device */ 9063670Snsayerstatic d_open_t tapopen; 9163670Snsayerstatic d_close_t tapclose; 9263670Snsayerstatic d_read_t tapread; 9363670Snsayerstatic d_write_t tapwrite; 9463670Snsayerstatic d_ioctl_t tapioctl; 9563670Snsayerstatic d_poll_t tappoll; 9663670Snsayer 9763670Snsayerstatic struct cdevsw tap_cdevsw = { 9863670Snsayer /* open */ tapopen, 9963670Snsayer /* close */ tapclose, 10063670Snsayer /* read */ tapread, 10163670Snsayer /* write */ tapwrite, 10263670Snsayer /* ioctl */ tapioctl, 10363670Snsayer /* poll */ tappoll, 10463670Snsayer /* mmap */ nommap, 10563670Snsayer /* startegy */ nostrategy, 10663670Snsayer /* dev name */ CDEV_NAME, 10763670Snsayer /* dev major */ CDEV_MAJOR, 10863670Snsayer /* dump */ nodump, 10963670Snsayer /* psize */ nopsize, 11063670Snsayer /* flags */ 0, 11163670Snsayer /* bmaj */ -1 11263670Snsayer}; 11363670Snsayer 11463670Snsayerstatic int taprefcnt = 0; /* module ref. counter */ 11563670Snsayerstatic int taplastunit = -1; /* max. open unit number */ 11663670Snsayerstatic int tapdebug = 0; /* debug flag */ 11763670Snsayer 11863670SnsayerMALLOC_DECLARE(M_TAP); 11963670SnsayerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12063670SnsayerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 12163670SnsayerDEV_MODULE(if_tap, tapmodevent, NULL); 12263670Snsayer 12363670Snsayer/* 12463670Snsayer * tapmodevent 12563670Snsayer * 12663670Snsayer * module event handler 12763670Snsayer */ 12863670Snsayerstatic int 12963670Snsayertapmodevent(mod, type, data) 13063670Snsayer module_t mod; 13163670Snsayer int type; 13263670Snsayer void *data; 13363670Snsayer{ 13463670Snsayer static int attached = 0; 13563670Snsayer struct ifnet *ifp = NULL; 13663670Snsayer int unit, s; 13763670Snsayer 13863670Snsayer switch (type) { 13963670Snsayer case MOD_LOAD: 14063670Snsayer if (attached) 14163670Snsayer return (EEXIST); 14263670Snsayer 14363670Snsayer cdevsw_add(&tap_cdevsw); 14463670Snsayer attached = 1; 14563670Snsayer break; 14663670Snsayer 14763670Snsayer case MOD_UNLOAD: 14863670Snsayer if (taprefcnt > 0) 14963670Snsayer return (EBUSY); 15063670Snsayer 15163670Snsayer cdevsw_remove(&tap_cdevsw); 15263670Snsayer 15363670Snsayer unit = 0; 15463670Snsayer while (unit <= taplastunit) { 15563670Snsayer s = splimp(); 15663670Snsayer TAILQ_FOREACH(ifp, &ifnet, if_link) 15763670Snsayer if ((strcmp(ifp->if_name, TAP) == 0) || 15863670Snsayer (strcmp(ifp->if_name, VMNET) == 0)) 15963670Snsayer if (ifp->if_unit == unit) 16063670Snsayer break; 16163670Snsayer splx(s); 16263670Snsayer 16363670Snsayer if (ifp != NULL) { 16463670Snsayer struct tap_softc *tp = ifp->if_softc; 16563670Snsayer 16663803Snsayer TAPDEBUG("detaching %s%d. minor = %#x, " \ 16763803Snsayer "taplastunit = %d\n", 16863803Snsayer ifp->if_name, unit, minor(tp->tap_dev), 16963803Snsayer taplastunit); 17063670Snsayer 17163803Snsayer s = splimp(); 17263670Snsayer ether_ifdetach(ifp, 1); 17363803Snsayer splx(s); 17463670Snsayer destroy_dev(tp->tap_dev); 17563670Snsayer FREE(tp, M_TAP); 17663670Snsayer } 17763670Snsayer else 17863670Snsayer unit ++; 17963670Snsayer } 18063670Snsayer 18163670Snsayer attached = 0; 18263670Snsayer break; 18363670Snsayer 18463670Snsayer default: 18563670Snsayer return (EOPNOTSUPP); 18663670Snsayer } 18763670Snsayer 18863670Snsayer return (0); 18963670Snsayer} /* tapmodevent */ 19063670Snsayer 19163670Snsayer 19263670Snsayer/* 19363670Snsayer * tapcreate 19463670Snsayer * 19563670Snsayer * to create interface 19663670Snsayer */ 19763670Snsayerstatic void 19863670Snsayertapcreate(dev) 19963670Snsayer dev_t dev; 20063670Snsayer{ 20163670Snsayer struct ifnet *ifp = NULL; 20263670Snsayer struct tap_softc *tp = NULL; 20363670Snsayer unsigned short macaddr_hi; 20463803Snsayer int unit, s; 20563670Snsayer char *name = NULL; 20663670Snsayer 20763670Snsayer /* allocate driver storage and create device */ 20863670Snsayer MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK); 20963670Snsayer bzero(tp, sizeof(*tp)); 21063670Snsayer 21163670Snsayer /* select device: tap or vmnet */ 21263670Snsayer if (minor(dev) & VMNET_DEV_MASK) { 21363670Snsayer name = VMNET; 21463670Snsayer unit = lminor(dev) & 0xff; 21563803Snsayer tp->tap_flags |= TAP_VMNET; 21663670Snsayer } 21763670Snsayer else { 21863670Snsayer name = TAP; 21963670Snsayer unit = lminor(dev); 22063670Snsayer } 22163670Snsayer 22263803Snsayer tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 22363670Snsayer 0600, "%s%d", name, unit); 22463670Snsayer tp->tap_dev->si_drv1 = dev->si_drv1 = tp; 22563670Snsayer 22663670Snsayer /* generate fake MAC address: 00 bd xx xx xx unit_no */ 22763670Snsayer macaddr_hi = htons(0x00bd); 22863670Snsayer bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 22963670Snsayer bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 23063670Snsayer tp->arpcom.ac_enaddr[5] = (u_char)unit; 23163670Snsayer 23263670Snsayer /* fill the rest and attach interface */ 23363670Snsayer ifp = &tp->tap_if; 23463670Snsayer ifp->if_softc = tp; 23563670Snsayer 23663670Snsayer ifp->if_unit = unit; 23763670Snsayer if (unit > taplastunit) 23863670Snsayer taplastunit = unit; 23963670Snsayer 24063670Snsayer ifp->if_name = name; 24163670Snsayer ifp->if_init = tapifinit; 24263670Snsayer ifp->if_output = ether_output; 24363670Snsayer ifp->if_start = tapifstart; 24463670Snsayer ifp->if_ioctl = tapifioctl; 24563670Snsayer ifp->if_mtu = ETHERMTU; 24663670Snsayer ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 24763670Snsayer ifp->if_snd.ifq_maxlen = ifqmaxlen; 24863670Snsayer 24963803Snsayer s = splimp(); 25063670Snsayer ether_ifattach(ifp, 1); 25163803Snsayer splx(s); 25263670Snsayer 25363803Snsayer tp->tap_flags |= TAP_INITED; 25463803Snsayer 25563803Snsayer TAPDEBUG("interface %s%d created. minor = %#x\n", 25663803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 25763670Snsayer} /* tapcreate */ 25863670Snsayer 25963670Snsayer 26063670Snsayer/* 26163670Snsayer * tapopen 26263670Snsayer * 26363670Snsayer * to open tunnel. must be superuser 26463670Snsayer */ 26563670Snsayerstatic int 26663670Snsayertapopen(dev, flag, mode, p) 26763670Snsayer dev_t dev; 26863670Snsayer int flag; 26963670Snsayer int mode; 27063670Snsayer struct proc *p; 27163670Snsayer{ 27263670Snsayer struct tap_softc *tp = NULL; 27363670Snsayer int error; 27463670Snsayer 27563670Snsayer if ((error = suser(p)) != 0) 27663670Snsayer return (error); 27763670Snsayer 27863670Snsayer tp = dev->si_drv1; 27963670Snsayer if (tp == NULL) { 28063670Snsayer tapcreate(dev); 28163670Snsayer tp = dev->si_drv1; 28263670Snsayer } 28363670Snsayer 28463670Snsayer if (tp->tap_flags & TAP_OPEN) 28563670Snsayer return (EBUSY); 28663670Snsayer 28763861Snsayer bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 28863861Snsayer 28963670Snsayer tp->tap_pid = p->p_pid; 29063670Snsayer tp->tap_flags |= TAP_OPEN; 29163670Snsayer taprefcnt ++; 29263670Snsayer 29363803Snsayer TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n", 29463803Snsayer tp->tap_if.if_name, tp->tap_if.if_unit, 29563803Snsayer minor(tp->tap_dev), taprefcnt, taplastunit); 29663670Snsayer 29763670Snsayer return (0); 29863670Snsayer} /* tapopen */ 29963670Snsayer 30063670Snsayer 30163670Snsayer/* 30263670Snsayer * tapclose 30363670Snsayer * 30463670Snsayer * close the device - mark i/f down & delete routing info 30563670Snsayer */ 30663670Snsayerstatic int 30763670Snsayertapclose(dev, foo, bar, p) 30863670Snsayer dev_t dev; 30963670Snsayer int foo; 31063670Snsayer int bar; 31163670Snsayer struct proc *p; 31263670Snsayer{ 31363670Snsayer int s; 31463670Snsayer struct tap_softc *tp = dev->si_drv1; 31563670Snsayer struct ifnet *ifp = &tp->tap_if; 31663670Snsayer struct mbuf *m = NULL; 31763670Snsayer 31863670Snsayer /* junk all pending output */ 31963670Snsayer 32063670Snsayer s = splimp(); 32163670Snsayer do { 32263670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 32363670Snsayer if (m != NULL) 32463670Snsayer m_freem(m); 32563670Snsayer } while (m != NULL); 32663670Snsayer splx(s); 32763670Snsayer 32863803Snsayer /* 32963803Snsayer * do not bring the interface down, and do not anything with 33063803Snsayer * interface, if we are in VMnet mode. just close the device. 33163803Snsayer */ 33263803Snsayer 33363803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 33463670Snsayer s = splimp(); 33563670Snsayer if_down(ifp); 33663670Snsayer if (ifp->if_flags & IFF_RUNNING) { 33763670Snsayer /* find internet addresses and delete routes */ 33863670Snsayer struct ifaddr *ifa = NULL; 33963670Snsayer 34063803Snsayer TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 34163670Snsayer if (ifa->ifa_addr->sa_family == AF_INET) { 34263670Snsayer rtinit(ifa, (int)RTM_DELETE, 0); 34363670Snsayer 34463670Snsayer /* remove address from interface */ 34563670Snsayer bzero(ifa->ifa_addr, 34663670Snsayer sizeof(*(ifa->ifa_addr))); 34763670Snsayer bzero(ifa->ifa_dstaddr, 34863670Snsayer sizeof(*(ifa->ifa_dstaddr))); 34963670Snsayer bzero(ifa->ifa_netmask, 35063670Snsayer sizeof(*(ifa->ifa_netmask))); 35163670Snsayer } 35263670Snsayer } 35363670Snsayer 35463670Snsayer ifp->if_flags &= ~IFF_RUNNING; 35563670Snsayer } 35663670Snsayer splx(s); 35763670Snsayer } 35863670Snsayer 35963670Snsayer funsetown(tp->tap_sigio); 36063670Snsayer selwakeup(&tp->tap_rsel); 36163670Snsayer 36263670Snsayer tp->tap_flags &= ~TAP_OPEN; 36363670Snsayer tp->tap_pid = 0; 36463670Snsayer 36563670Snsayer taprefcnt --; 36663670Snsayer if (taprefcnt < 0) { 36763670Snsayer taprefcnt = 0; 36863803Snsayer printf("%s%d minor = %#x, refcnt = %d is out of sync. " \ 36963803Snsayer "set refcnt to 0\n", ifp->if_name, ifp->if_unit, 37063803Snsayer minor(tp->tap_dev), taprefcnt); 37163670Snsayer } 37263670Snsayer 37363803Snsayer TAPDEBUG("%s%d is closed. minor = %#x, refcnt = %d, taplastunit = %d\n", 37463803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev), 37563803Snsayer taprefcnt, taplastunit); 37663670Snsayer 37763670Snsayer return (0); 37863670Snsayer} /* tapclose */ 37963670Snsayer 38063670Snsayer 38163670Snsayer/* 38263670Snsayer * tapifinit 38363670Snsayer * 38463670Snsayer * network interface initialization function 38563670Snsayer */ 38663670Snsayerstatic void 38763670Snsayertapifinit(xtp) 38863670Snsayer void *xtp; 38963670Snsayer{ 39063670Snsayer struct tap_softc *tp = (struct tap_softc *)xtp; 39163670Snsayer struct ifnet *ifp = &tp->tap_if; 39263670Snsayer 39363803Snsayer TAPDEBUG("initializing %s%d, minor = %#x\n", 39463803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 39563670Snsayer 39663670Snsayer ifp->if_flags |= IFF_RUNNING; 39763670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 39863670Snsayer 39963670Snsayer /* attempt to start output */ 40063670Snsayer tapifstart(ifp); 40163670Snsayer} /* tapifinit */ 40263670Snsayer 40363670Snsayer 40463670Snsayer/* 40563670Snsayer * tapifioctl 40663670Snsayer * 40763670Snsayer * Process an ioctl request on network interface 40863670Snsayer */ 40963670Snsayerint 41063670Snsayertapifioctl(ifp, cmd, data) 41163670Snsayer struct ifnet *ifp; 41263670Snsayer u_long cmd; 41363670Snsayer caddr_t data; 41463670Snsayer{ 41563670Snsayer struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 41663670Snsayer struct ifstat *ifs = NULL; 41763670Snsayer int s, dummy; 41863670Snsayer 41963670Snsayer switch (cmd) { 42063670Snsayer case SIOCSIFADDR: 42163670Snsayer case SIOCGIFADDR: 42263670Snsayer case SIOCSIFMTU: 42363670Snsayer s = splimp(); 42463670Snsayer dummy = ether_ioctl(ifp, cmd, data); 42563670Snsayer splx(s); 42663670Snsayer return (dummy); 42763670Snsayer 42863670Snsayer case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 42963670Snsayer case SIOCADDMULTI: 43063670Snsayer case SIOCDELMULTI: 43163670Snsayer break; 43263670Snsayer 43363670Snsayer case SIOCGIFSTATUS: 43463670Snsayer s = splimp(); 43563670Snsayer ifs = (struct ifstat *)data; 43663670Snsayer dummy = strlen(ifs->ascii); 43763670Snsayer if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 43863670Snsayer snprintf(ifs->ascii + dummy, 43963670Snsayer sizeof(ifs->ascii) - dummy, 44063670Snsayer "\tOpened by PID %d\n", tp->tap_pid); 44163670Snsayer splx(s); 44263670Snsayer break; 44363670Snsayer 44463670Snsayer default: 44563670Snsayer return (EINVAL); 44663670Snsayer } 44763670Snsayer 44863670Snsayer return (0); 44963670Snsayer} /* tapifioctl */ 45063670Snsayer 45163670Snsayer 45263670Snsayer/* 45363670Snsayer * tapifstart 45463670Snsayer * 45563670Snsayer * queue packets from higher level ready to put out 45663670Snsayer */ 45763670Snsayerstatic void 45863670Snsayertapifstart(ifp) 45963670Snsayer struct ifnet *ifp; 46063670Snsayer{ 46163670Snsayer struct tap_softc *tp = ifp->if_softc; 46263670Snsayer int s; 46363670Snsayer 46463803Snsayer TAPDEBUG("%s%d starting, minor = %#x\n", 46563803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 46663670Snsayer 46763803Snsayer /* 46863803Snsayer * do not junk pending output if we are in VMnet mode. 46963803Snsayer * XXX: can this do any harm because of queue overflow? 47063803Snsayer */ 47163803Snsayer 47263803Snsayer if (((tp->tap_flags & TAP_VMNET) == 0) && 47363803Snsayer ((tp->tap_flags & TAP_READY) != TAP_READY)) { 47463670Snsayer struct mbuf *m = NULL; 47563670Snsayer 47663803Snsayer TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 47763803Snsayer ifp->if_name, ifp->if_unit, 47863803Snsayer minor(tp->tap_dev), tp->tap_flags); 47963670Snsayer 48063670Snsayer s = splimp(); 48163670Snsayer do { 48263670Snsayer IF_DEQUEUE(&ifp->if_snd, m); 48363670Snsayer if (m != NULL) 48463670Snsayer m_freem(m); 48563670Snsayer ifp->if_oerrors ++; 48663670Snsayer } while (m != NULL); 48763670Snsayer splx(s); 48863670Snsayer 48963670Snsayer return; 49063670Snsayer } 49163670Snsayer 49263670Snsayer s = splimp(); 49363670Snsayer ifp->if_flags |= IFF_OACTIVE; 49463670Snsayer 49563670Snsayer if (ifp->if_snd.ifq_len != 0) { 49663670Snsayer if (tp->tap_flags & TAP_RWAIT) { 49763670Snsayer tp->tap_flags &= ~TAP_RWAIT; 49863670Snsayer wakeup((caddr_t)tp); 49963670Snsayer } 50063670Snsayer 50163670Snsayer if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 50263670Snsayer pgsigio(tp->tap_sigio, SIGIO, 0); 50363670Snsayer 50463670Snsayer selwakeup(&tp->tap_rsel); 50563670Snsayer ifp->if_opackets ++; /* obytes are counted in ether_output */ 50663670Snsayer } 50763670Snsayer 50863670Snsayer ifp->if_flags &= ~IFF_OACTIVE; 50963670Snsayer splx(s); 51063670Snsayer} /* tapifstart */ 51163670Snsayer 51263670Snsayer 51363670Snsayer/* 51463670Snsayer * tapioctl 51563670Snsayer * 51663670Snsayer * the cdevsw interface is now pretty minimal 51763670Snsayer */ 51863670Snsayerstatic int 51963670Snsayertapioctl(dev, cmd, data, flag, p) 52063670Snsayer dev_t dev; 52163670Snsayer u_long cmd; 52263670Snsayer caddr_t data; 52363670Snsayer int flag; 52463670Snsayer struct proc *p; 52563670Snsayer{ 52663670Snsayer struct tap_softc *tp = dev->si_drv1; 52763670Snsayer struct ifnet *ifp = &tp->tap_if; 52863670Snsayer struct tapinfo *tapp = NULL; 52963670Snsayer int s; 53063670Snsayer 53163670Snsayer switch (cmd) { 53263670Snsayer case TAPSIFINFO: 53363670Snsayer s = splimp(); 53463670Snsayer tapp = (struct tapinfo *)data; 53563670Snsayer ifp->if_mtu = tapp->mtu; 53663670Snsayer ifp->if_type = tapp->type; 53763670Snsayer ifp->if_baudrate = tapp->baudrate; 53863670Snsayer splx(s); 53963670Snsayer break; 54063670Snsayer 54163670Snsayer case TAPGIFINFO: 54263670Snsayer tapp = (struct tapinfo *)data; 54363670Snsayer tapp->mtu = ifp->if_mtu; 54463670Snsayer tapp->type = ifp->if_type; 54563670Snsayer tapp->baudrate = ifp->if_baudrate; 54663670Snsayer break; 54763670Snsayer 54863670Snsayer case TAPSDEBUG: 54963670Snsayer tapdebug = *(int *)data; 55063670Snsayer break; 55163670Snsayer 55263670Snsayer case TAPGDEBUG: 55363670Snsayer *(int *)data = tapdebug; 55463670Snsayer break; 55563670Snsayer 55663670Snsayer case FIONBIO: 55763670Snsayer break; 55863670Snsayer 55963670Snsayer case FIOASYNC: 56063803Snsayer s = splimp(); 56163670Snsayer if (*(int *)data) 56263670Snsayer tp->tap_flags |= TAP_ASYNC; 56363670Snsayer else 56463670Snsayer tp->tap_flags &= ~TAP_ASYNC; 56563803Snsayer splx(s); 56663670Snsayer break; 56763670Snsayer 56863670Snsayer case FIONREAD: 56963670Snsayer s = splimp(); 57063670Snsayer if (ifp->if_snd.ifq_head) { 57163670Snsayer struct mbuf *mb = ifp->if_snd.ifq_head; 57263670Snsayer 57363803Snsayer for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 57463670Snsayer *(int *)data += mb->m_len; 57563670Snsayer } 57663670Snsayer else 57763670Snsayer *(int *)data = 0; 57863670Snsayer splx(s); 57963670Snsayer break; 58063670Snsayer 58163670Snsayer case FIOSETOWN: 58263670Snsayer return (fsetown(*(int *)data, &tp->tap_sigio)); 58363670Snsayer 58463670Snsayer case FIOGETOWN: 58563670Snsayer *(int *)data = fgetown(tp->tap_sigio); 58663670Snsayer return (0); 58763670Snsayer 58863670Snsayer /* this is deprecated, FIOSETOWN should be used instead */ 58963670Snsayer case TIOCSPGRP: 59063670Snsayer return (fsetown(-(*(int *)data), &tp->tap_sigio)); 59163670Snsayer 59263670Snsayer /* this is deprecated, FIOGETOWN should be used instead */ 59363670Snsayer case TIOCGPGRP: 59463670Snsayer *(int *)data = -fgetown(tp->tap_sigio); 59563670Snsayer return (0); 59663670Snsayer 59763670Snsayer /* VMware/VMnet port ioctl's */ 59863670Snsayer 59963670Snsayer case SIOCGIFFLAGS: /* get ifnet flags */ 60063670Snsayer bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 60163670Snsayer break; 60263670Snsayer 60363670Snsayer case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */ 60463670Snsayer short f = *(short *)data; 60563670Snsayer 60663670Snsayer f &= 0x0fff; 60763670Snsayer f &= ~IFF_CANTCHANGE; 60863670Snsayer f |= IFF_UP; 60963670Snsayer 61063670Snsayer s = splimp(); 61163670Snsayer ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 61263670Snsayer splx(s); 61363670Snsayer } break; 61463670Snsayer 61563861Snsayer case OSIOCGIFADDR: /* get MAC address of the remote side */ 61663670Snsayer case SIOCGIFADDR: 61763861Snsayer bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 61863670Snsayer break; 61963670Snsayer 62063861Snsayer case SIOCSIFADDR: /* set MAC address of the remote side */ 62163861Snsayer bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 62263670Snsayer break; 62363670Snsayer 62463670Snsayer default: 62563670Snsayer return (ENOTTY); 62663670Snsayer } 62763670Snsayer return (0); 62863670Snsayer} /* tapioctl */ 62963670Snsayer 63063670Snsayer 63163670Snsayer/* 63263670Snsayer * tapread 63363670Snsayer * 63463670Snsayer * the cdevsw read interface - reads a packet at a time, or at 63563670Snsayer * least as much of a packet as can be read 63663670Snsayer */ 63763670Snsayerstatic int 63863670Snsayertapread(dev, uio, flag) 63963670Snsayer dev_t dev; 64063670Snsayer struct uio *uio; 64163670Snsayer int flag; 64263670Snsayer{ 64363670Snsayer struct tap_softc *tp = dev->si_drv1; 64463670Snsayer struct ifnet *ifp = &tp->tap_if; 64563670Snsayer struct mbuf *m = NULL, *m0 = NULL; 64663670Snsayer int error = 0, len, s; 64763670Snsayer 64863803Snsayer TAPDEBUG("%s%d reading, minor = %#x\n", 64963803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 65063670Snsayer 65163670Snsayer if ((tp->tap_flags & TAP_READY) != TAP_READY) { 65263803Snsayer TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 65363803Snsayer ifp->if_name, ifp->if_unit, 65463803Snsayer minor(tp->tap_dev), tp->tap_flags); 65563803Snsayer 65663670Snsayer return (EHOSTDOWN); 65763670Snsayer } 65863670Snsayer 65963670Snsayer tp->tap_flags &= ~TAP_RWAIT; 66063670Snsayer 66163670Snsayer /* sleep until we get a packet */ 66263670Snsayer do { 66363670Snsayer s = splimp(); 66463670Snsayer IF_DEQUEUE(&ifp->if_snd, m0); 66563670Snsayer splx(s); 66663670Snsayer 66763670Snsayer if (m0 == NULL) { 66863670Snsayer if (flag & IO_NDELAY) 66963670Snsayer return (EWOULDBLOCK); 67063670Snsayer 67163670Snsayer tp->tap_flags |= TAP_RWAIT; 67263670Snsayer error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 67363670Snsayer if (error) 67463670Snsayer return (error); 67563670Snsayer } 67663803Snsayer } while (m0 == NULL); 67763670Snsayer 67863670Snsayer /* feed packet to bpf */ 67963670Snsayer if (ifp->if_bpf != NULL) 68063670Snsayer bpf_mtap(ifp, m0); 68163670Snsayer 68263670Snsayer /* xfer packet to user space */ 68363670Snsayer while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) { 68463670Snsayer len = min(uio->uio_resid, m0->m_len); 68563670Snsayer if (len == 0) 68663670Snsayer break; 68763670Snsayer 68863670Snsayer error = uiomove(mtod(m0, caddr_t), len, uio); 68963670Snsayer MFREE(m0, m); 69063670Snsayer m0 = m; 69163670Snsayer } 69263670Snsayer 69363670Snsayer if (m0 != NULL) { 69463803Snsayer TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", 69563803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 69663670Snsayer m_freem(m0); 69763670Snsayer } 69863670Snsayer 69963670Snsayer return (error); 70063670Snsayer} /* tapread */ 70163670Snsayer 70263670Snsayer 70363670Snsayer/* 70463670Snsayer * tapwrite 70563670Snsayer * 70663670Snsayer * the cdevsw write interface - an atomic write is a packet - or else! 70763670Snsayer */ 70863670Snsayerstatic int 70963670Snsayertapwrite(dev, uio, flag) 71063670Snsayer dev_t dev; 71163670Snsayer struct uio *uio; 71263670Snsayer int flag; 71363670Snsayer{ 71463670Snsayer struct tap_softc *tp = dev->si_drv1; 71563670Snsayer struct ifnet *ifp = &tp->tap_if; 71663670Snsayer struct mbuf *top = NULL, **mp = NULL, *m = NULL; 71763670Snsayer struct ether_header *eh = NULL; 71863670Snsayer int error = 0, tlen, mlen; 71963670Snsayer 72063803Snsayer TAPDEBUG("%s%d writting, minor = %#x\n", 72163803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 72263670Snsayer 72363670Snsayer if (uio->uio_resid == 0) 72463670Snsayer return (0); 72563670Snsayer 72663670Snsayer if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 72763803Snsayer TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 72863803Snsayer ifp->if_name, ifp->if_unit, 72963803Snsayer uio->uio_resid, minor(tp->tap_dev)); 73063803Snsayer 73163670Snsayer return (EIO); 73263670Snsayer } 73363670Snsayer tlen = uio->uio_resid; 73463670Snsayer 73563670Snsayer /* get a header mbuf */ 73663670Snsayer MGETHDR(m, M_DONTWAIT, MT_DATA); 73763670Snsayer if (m == NULL) 73863670Snsayer return (ENOBUFS); 73963670Snsayer mlen = MHLEN; 74063670Snsayer 74163670Snsayer top = 0; 74263670Snsayer mp = ⊤ 74363670Snsayer while ((error == 0) && (uio->uio_resid > 0)) { 74463670Snsayer m->m_len = min(mlen, uio->uio_resid); 74563670Snsayer error = uiomove(mtod(m, caddr_t), m->m_len, uio); 74663670Snsayer *mp = m; 74763670Snsayer mp = &m->m_next; 74863670Snsayer if (uio->uio_resid > 0) { 74963670Snsayer MGET(m, M_DONTWAIT, MT_DATA); 75063803Snsayer if (m == NULL) { 75163670Snsayer error = ENOBUFS; 75263670Snsayer break; 75363670Snsayer } 75463670Snsayer mlen = MLEN; 75563670Snsayer } 75663670Snsayer } 75763670Snsayer if (error) { 75863670Snsayer ifp->if_ierrors ++; 75963670Snsayer if (top) 76063670Snsayer m_freem(top); 76163670Snsayer return (error); 76263670Snsayer } 76363670Snsayer 76463670Snsayer top->m_pkthdr.len = tlen; 76563670Snsayer top->m_pkthdr.rcvif = ifp; 76663670Snsayer 76763670Snsayer /* 76863670Snsayer * Ethernet bridge and bpf are handled in ether_input 76963670Snsayer * 77063670Snsayer * adjust mbuf and give packet to the ether_input 77163670Snsayer */ 77263670Snsayer 77363670Snsayer eh = mtod(top, struct ether_header *); 77463670Snsayer m_adj(top, sizeof(struct ether_header)); 77563670Snsayer ether_input(ifp, eh, top); 77663670Snsayer ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 77763670Snsayer 77863670Snsayer return (0); 77963670Snsayer} /* tapwrite */ 78063670Snsayer 78163670Snsayer 78263670Snsayer/* 78363670Snsayer * tappoll 78463670Snsayer * 78563670Snsayer * the poll interface, this is only useful on reads 78663670Snsayer * really. the write detect always returns true, write never blocks 78763670Snsayer * anyway, it either accepts the packet or drops it 78863670Snsayer */ 78963670Snsayerstatic int 79063670Snsayertappoll(dev, events, p) 79163670Snsayer dev_t dev; 79263670Snsayer int events; 79363670Snsayer struct proc *p; 79463670Snsayer{ 79563670Snsayer struct tap_softc *tp = dev->si_drv1; 79663670Snsayer struct ifnet *ifp = &tp->tap_if; 79763670Snsayer int s, revents = 0; 79863670Snsayer 79963803Snsayer TAPDEBUG("%s%d polling, minor = %#x\n", 80063803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 80163670Snsayer 80263670Snsayer s = splimp(); 80363670Snsayer if (events & (POLLIN | POLLRDNORM)) { 80463670Snsayer if (ifp->if_snd.ifq_len > 0) { 80563803Snsayer TAPDEBUG("%s%d have data in queue. len = %d, " \ 80663803Snsayer "minor = %#x\n", ifp->if_name, ifp->if_unit, 80763803Snsayer ifp->if_snd.ifq_len, minor(tp->tap_dev)); 80863803Snsayer 80963670Snsayer revents |= (events & (POLLIN | POLLRDNORM)); 81063670Snsayer } 81163670Snsayer else { 81263803Snsayer TAPDEBUG("%s%d waiting for data, minor = %#x\n", 81363803Snsayer ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 81463803Snsayer 81563670Snsayer selrecord(p, &tp->tap_rsel); 81663670Snsayer } 81763670Snsayer } 81863670Snsayer 81963670Snsayer if (events & (POLLOUT | POLLWRNORM)) 82063670Snsayer revents |= (events & (POLLOUT | POLLWRNORM)); 82163670Snsayer 82263670Snsayer splx(s); 82363670Snsayer return (revents); 82463670Snsayer} /* tappoll */ 825