if_tun.c revision 137101
112115Sdyson/* $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $ */ 212115Sdyson 312115Sdyson/* 412115Sdyson * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 512115Sdyson * Nottingham University 1987. 612115Sdyson * 712115Sdyson * This source may be freely distributed, however I would be interested 812115Sdyson * in any changes that are made. 912115Sdyson * 1012115Sdyson * This driver takes packets off the IP i/f and hands them up to a 1112115Sdyson * user process to have its wicked way with. This driver has it's 1212115Sdyson * roots in a similar driver written by Phil Cockcroft (formerly) at 1312115Sdyson * UCL. This driver is based much more on read/write/poll mode of 1412115Sdyson * operation though. 1512115Sdyson * 1612115Sdyson * $FreeBSD: head/sys/net/if_tun.c 137101 2004-10-31 17:39:46Z glebius $ 1712115Sdyson */ 1812115Sdyson 1912115Sdyson#include "opt_atalk.h" 2012115Sdyson#include "opt_inet.h" 2112115Sdyson#include "opt_inet6.h" 2212115Sdyson#include "opt_ipx.h" 2312115Sdyson#include "opt_mac.h" 2412115Sdyson 2512115Sdyson#include <sys/param.h> 2612115Sdyson#include <sys/proc.h> 2712115Sdyson#include <sys/systm.h> 2812115Sdyson#include <sys/mac.h> 2912115Sdyson#include <sys/mbuf.h> 3012115Sdyson#include <sys/module.h> 3112115Sdyson#include <sys/socket.h> 3212115Sdyson#include <sys/filio.h> 3312115Sdyson#include <sys/sockio.h> 3412115Sdyson#include <sys/ttycom.h> 3512115Sdyson#include <sys/poll.h> 3612115Sdyson#include <sys/signalvar.h> 3712115Sdyson#include <sys/filedesc.h> 3812115Sdyson#include <sys/kernel.h> 3912115Sdyson#include <sys/sysctl.h> 4012115Sdyson#include <sys/conf.h> 4112115Sdyson#include <sys/uio.h> 4213260Swollman#include <sys/vnode.h> 4312115Sdyson#include <sys/malloc.h> 4412115Sdyson#include <sys/random.h> 4512115Sdyson 4612115Sdyson#include <net/if.h> 4712115Sdyson#include <net/if_types.h> 4812115Sdyson#include <net/netisr.h> 4912115Sdyson#include <net/route.h> 5012115Sdyson#ifdef INET 5112115Sdyson#include <netinet/in.h> 5229906Skato#endif 5324131Sbde#include <net/bpf.h> 5412115Sdyson#include <net/if_tun.h> 5512115Sdyson 5612115Sdyson#include <sys/queue.h> 5712115Sdyson 5812115Sdyson/* 5912115Sdyson * tun_list is protected by global tunmtx. Other mutable fields are 6012115Sdyson * protected by tun->tun_mtx, or by their owning subsystem. tun_dev is 6112115Sdyson * static for the duration of a tunnel interface. 6212115Sdyson */ 6312115Sdysonstruct tun_softc { 6412115Sdyson TAILQ_ENTRY(tun_softc) tun_list; 6512115Sdyson struct cdev *tun_dev; 6612115Sdyson u_short tun_flags; /* misc flags */ 6712115Sdyson#define TUN_OPEN 0x0001 6812115Sdyson#define TUN_INITED 0x0002 6912115Sdyson#define TUN_RCOLL 0x0004 7028270Swollman#define TUN_IASET 0x0008 7112911Sphk#define TUN_DSTADDR 0x0010 7212911Sphk#define TUN_LMODE 0x0020 7312911Sphk#define TUN_RWAIT 0x0040 7412911Sphk#define TUN_ASYNC 0x0080 7512911Sphk#define TUN_IFHEAD 0x0100 7612911Sphk 7712911Sphk#define TUN_READY (TUN_OPEN | TUN_INITED) 7812911Sphk 7912911Sphk /* 8012911Sphk * XXXRW: tun_pid is used to exclusively lock /dev/tun. Is this 8112911Sphk * actually needed? Can we just return EBUSY if already open? 8212911Sphk * Problem is that this involved inherent races when a tun device 8312911Sphk * is handed off from one process to another, as opposed to just 8412115Sdyson * being slightly stale informationally. 8531315Sbde */ 8630280Sphk pid_t tun_pid; /* owning pid */ 8712911Sphk struct ifnet tun_if; /* the interface */ 8812115Sdyson struct sigio *tun_sigio; /* information for async I/O */ 8912115Sdyson struct selinfo tun_rsel; /* read select */ 9012115Sdyson struct mtx tun_mtx; /* protect mutable softc fields */ 9112115Sdyson}; 9212115Sdyson 9312115Sdyson#define TUNDEBUG if (tundebug) if_printf 9412115Sdyson#define TUNNAME "tun" 9512115Sdyson 9612115Sdyson/* 9712115Sdyson * All mutable global variables in if_tun are locked using tunmtx, with 9812115Sdyson * the exception of tundebug, which is used unlocked, and tunclones, 9912115Sdyson * which is static after setup. 10012115Sdyson */ 10112115Sdysonstatic struct mtx tunmtx; 10212115Sdysonstatic MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface"); 10312115Sdysonstatic int tundebug = 0; 10412115Sdysonstatic struct clonedevs *tunclones; 10512911Sphkstatic TAILQ_HEAD(,tun_softc) tunhead = TAILQ_HEAD_INITIALIZER(tunhead); 10612115SdysonSYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); 10716322Sgpalmer 10816322Sgpalmerstatic void tunclone(void *arg, char *name, int namelen, struct cdev **dev); 10916322Sgpalmerstatic void tuncreate(struct cdev *dev); 11016322Sgpalmerstatic int tunifioctl(struct ifnet *, u_long, caddr_t); 11116322Sgpalmerstatic int tuninit(struct ifnet *); 11216322Sgpalmerstatic int tunmodevent(module_t, int, void *); 11316322Sgpalmerstatic int tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 11412115Sdyson struct rtentry *rt); 11516322Sgpalmerstatic void tunstart(struct ifnet *); 11612115Sdyson 11712115Sdysonstatic d_open_t tunopen; 11812115Sdysonstatic d_close_t tunclose; 11912115Sdysonstatic d_read_t tunread; 12012115Sdysonstatic d_write_t tunwrite; 12112911Sphkstatic d_ioctl_t tunioctl; 12212115Sdysonstatic d_poll_t tunpoll; 12312115Sdyson 12412115Sdysonstatic struct cdevsw tun_cdevsw = { 12512115Sdyson .d_version = D_VERSION, 12612115Sdyson .d_flags = D_PSEUDO | D_NEEDGIANT, 12712115Sdyson .d_open = tunopen, 12812115Sdyson .d_close = tunclose, 12912115Sdyson .d_read = tunread, 13012115Sdyson .d_write = tunwrite, 13129208Sbde .d_ioctl = tunioctl, 13229208Sbde .d_poll = tunpoll, 13329208Sbde .d_name = TUNNAME, 13429208Sbde}; 13512115Sdyson 13612115Sdysonstatic void 13712115Sdysontunclone(void *arg, char *name, int namelen, struct cdev **dev) 13812115Sdyson{ 13929888Skato int u, i; 14029888Skato 14129888Skato if (*dev != NULL) 14229888Skato return; 14312115Sdyson 14412115Sdyson if (strcmp(name, TUNNAME) == 0) { 14512115Sdyson u = -1; 14612115Sdyson } else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1) 14712115Sdyson return; /* Don't recognise the name */ 14812115Sdyson if (u != -1 && u > IF_MAXUNIT) 14912115Sdyson return; /* Unit number too high */ 15012115Sdyson 15112115Sdyson /* find any existing device, or allocate new unit number */ 15230469Sjulian i = clone_create(&tunclones, &tun_cdevsw, &u, dev, 0); 15312115Sdyson if (i) { 15412115Sdyson /* No preexisting struct cdev *, create one */ 15512115Sdyson *dev = make_dev(&tun_cdevsw, unit2minor(u), 15612115Sdyson UID_UUCP, GID_DIALER, 0600, "tun%d", u); 15712115Sdyson if (*dev != NULL) 15812115Sdyson (*dev)->si_flags |= SI_CHEAPCLONE; 15912115Sdyson } 16012115Sdyson} 16112115Sdyson 16212115Sdysonstatic void 16312115Sdysontun_destroy(struct tun_softc *tp) 16412115Sdyson{ 16512115Sdyson struct cdev *dev; 16612115Sdyson 16712115Sdyson /* Unlocked read. */ 16812115Sdyson KASSERT((tp->tun_flags & TUN_OPEN) == 0, 16916322Sgpalmer ("tununits is out of sync - unit %d", tp->tun_if.if_dunit)); 17012115Sdyson 17112115Sdyson dev = tp->tun_dev; 17212115Sdyson bpfdetach(&tp->tun_if); 17312115Sdyson if_detach(&tp->tun_if); 17412115Sdyson destroy_dev(dev); 17512115Sdyson mtx_destroy(&tp->tun_mtx); 17612911Sphk free(tp, M_TUN); 17712115Sdyson} 17812115Sdyson 17912115Sdysonstatic int 18012115Sdysontunmodevent(module_t mod, int type, void *data) 18112115Sdyson{ 18212115Sdyson static eventhandler_tag tag; 18312115Sdyson struct tun_softc *tp; 18412115Sdyson 18512115Sdyson switch (type) { 18612115Sdyson case MOD_LOAD: 18712115Sdyson mtx_init(&tunmtx, "tunmtx", NULL, MTX_DEF); 18812115Sdyson clone_setup(&tunclones); 18912115Sdyson tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000); 19012115Sdyson if (tag == NULL) 19112115Sdyson return (ENOMEM); 19212115Sdyson break; 19312115Sdyson case MOD_UNLOAD: 19412115Sdyson EVENTHANDLER_DEREGISTER(dev_clone, tag); 19512115Sdyson 19629888Skato mtx_lock(&tunmtx); 19729888Skato while ((tp = TAILQ_FIRST(&tunhead)) != NULL) { 19812115Sdyson TAILQ_REMOVE(&tunhead, tp, tun_list); 19912115Sdyson mtx_unlock(&tunmtx); 20012115Sdyson tun_destroy(tp); 20112115Sdyson mtx_lock(&tunmtx); 20212115Sdyson } 20329888Skato mtx_unlock(&tunmtx); 20429888Skato clone_cleanup(&tunclones); 20529888Skato mtx_destroy(&tunmtx); 20629888Skato break; 20712115Sdyson default: 20812115Sdyson return EOPNOTSUPP; 20912115Sdyson } 21012115Sdyson return 0; 21122521Sdyson} 21212115Sdyson 21312115Sdysonstatic moduledata_t tun_mod = { 21422521Sdyson "if_tun", 21512115Sdyson tunmodevent, 21612115Sdyson 0 21712115Sdyson}; 21812115Sdyson 21912115SdysonDECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 22031132Sjulian 22112115Sdysonstatic void 22212115Sdysontunstart(struct ifnet *ifp) 22312115Sdyson{ 22412115Sdyson struct tun_softc *tp = ifp->if_softc; 22512115Sdyson struct mbuf *m; 22612115Sdyson 22712115Sdyson if (ALTQ_IS_ENABLED(&ifp->if_snd)) { 22812115Sdyson IFQ_LOCK(&ifp->if_snd); 22912115Sdyson IFQ_POLL_NOLOCK(&ifp->if_snd, m); 23012115Sdyson if (m == NULL) { 23112115Sdyson IFQ_UNLOCK(&ifp->if_snd); 23212115Sdyson return; 23312115Sdyson } 23412115Sdyson IFQ_UNLOCK(&ifp->if_snd); 23512115Sdyson } 23612115Sdyson 23712115Sdyson mtx_lock(&tp->tun_mtx); 23812115Sdyson if (tp->tun_flags & TUN_RWAIT) { 23912115Sdyson tp->tun_flags &= ~TUN_RWAIT; 24012115Sdyson wakeup(tp); 24112115Sdyson } 24212115Sdyson if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) { 24312115Sdyson mtx_unlock(&tp->tun_mtx); 24412115Sdyson pgsigio(&tp->tun_sigio, SIGIO, 0); 24512115Sdyson } else 24612115Sdyson mtx_unlock(&tp->tun_mtx); 24712115Sdyson selwakeuppri(&tp->tun_rsel, PZERO + 1); 24812115Sdyson} 24912115Sdyson 25012115Sdysonstatic void 25129888Skatotuncreate(struct cdev *dev) 25229888Skato{ 25329888Skato struct tun_softc *sc; 25429888Skato struct ifnet *ifp; 25529888Skato 25612115Sdyson dev->si_flags &= ~SI_CHEAPCLONE; 25729888Skato 25812115Sdyson MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO); 25912115Sdyson mtx_init(&sc->tun_mtx, "tun_mtx", NULL, MTX_DEF); 26012115Sdyson sc->tun_flags = TUN_INITED; 26112115Sdyson sc->tun_dev = dev; 26212115Sdyson mtx_lock(&tunmtx); 26312115Sdyson TAILQ_INSERT_TAIL(&tunhead, sc, tun_list); 26412115Sdyson mtx_unlock(&tunmtx); 26512115Sdyson 26612115Sdyson ifp = &sc->tun_if; 26712115Sdyson if_initname(ifp, TUNNAME, dev2unit(dev)); 26812115Sdyson ifp->if_mtu = TUNMTU; 26912115Sdyson ifp->if_ioctl = tunifioctl; 27012115Sdyson ifp->if_output = tunoutput; 27112115Sdyson ifp->if_start = tunstart; 27212115Sdyson ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 27312115Sdyson ifp->if_type = IFT_PPP; 27412115Sdyson ifp->if_softc = sc; 27512115Sdyson IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 27612115Sdyson ifp->if_snd.ifq_drv_maxlen = 0; 27712115Sdyson IFQ_SET_READY(&ifp->if_snd); 27812115Sdyson 27912115Sdyson if_attach(ifp); 28012115Sdyson bpfattach(ifp, DLT_NULL, sizeof(u_int)); 28112115Sdyson dev->si_drv1 = sc; 28212115Sdyson} 28312115Sdyson 28412115Sdysonstatic int 28512115Sdysontunopen(struct cdev *dev, int flag, int mode, struct thread *td) 28612115Sdyson{ 28712115Sdyson struct ifnet *ifp; 28812115Sdyson struct tun_softc *tp; 28912115Sdyson 29012115Sdyson /* 29112115Sdyson * XXXRW: Non-atomic test and set of dev->si_drv1 requires 29212115Sdyson * synchronization. 29312115Sdyson */ 29412115Sdyson tp = dev->si_drv1; 29512115Sdyson if (!tp) { 29612115Sdyson tuncreate(dev); 29712115Sdyson tp = dev->si_drv1; 29812115Sdyson } 29912115Sdyson 30012115Sdyson /* 30112115Sdyson * XXXRW: This use of tun_pid is subject to error due to the 30212115Sdyson * fact that a reference to the tunnel can live beyond the 30312115Sdyson * death of the process that created it. Can we replace this 30412115Sdyson * with a simple busy flag? 30512115Sdyson */ 30612115Sdyson mtx_lock(&tp->tun_mtx); 30712115Sdyson if (tp->tun_pid != 0 && tp->tun_pid != td->td_proc->p_pid) { 30812115Sdyson mtx_unlock(&tp->tun_mtx); 30912115Sdyson return (EBUSY); 31012115Sdyson } 31112115Sdyson tp->tun_pid = td->td_proc->p_pid; 31212115Sdyson 31312115Sdyson tp->tun_flags |= TUN_OPEN; 31412115Sdyson mtx_unlock(&tp->tun_mtx); 31512115Sdyson ifp = &tp->tun_if; 31612115Sdyson TUNDEBUG(ifp, "open\n"); 31712115Sdyson 31812115Sdyson return (0); 31912115Sdyson} 32012115Sdyson 32112115Sdyson/* 32212115Sdyson * tunclose - close the device - mark i/f down & delete 32312115Sdyson * routing info 32412115Sdyson */ 32512115Sdysonstatic int 32612115Sdysontunclose(struct cdev *dev, int foo, int bar, struct thread *td) 32712115Sdyson{ 32812115Sdyson struct tun_softc *tp; 32912115Sdyson struct ifnet *ifp; 33012115Sdyson int s; 33112115Sdyson 33212115Sdyson tp = dev->si_drv1; 33312115Sdyson ifp = &tp->tun_if; 33412115Sdyson 33512115Sdyson mtx_lock(&tp->tun_mtx); 33612115Sdyson tp->tun_flags &= ~TUN_OPEN; 33712115Sdyson tp->tun_pid = 0; 33812115Sdyson 33912115Sdyson /* 34012115Sdyson * junk all pending output 34112115Sdyson */ 34212115Sdyson s = splimp(); 34312115Sdyson IFQ_PURGE(&ifp->if_snd); 34412115Sdyson splx(s); 34512115Sdyson mtx_unlock(&tp->tun_mtx); 34612115Sdyson 34712115Sdyson if (ifp->if_flags & IFF_UP) { 34812115Sdyson s = splimp(); 34912115Sdyson if_down(ifp); 35012115Sdyson splx(s); 35112115Sdyson } 35212115Sdyson 35312115Sdyson if (ifp->if_flags & IFF_RUNNING) { 35412115Sdyson struct ifaddr *ifa; 35512115Sdyson 35612115Sdyson s = splimp(); 35712115Sdyson /* find internet addresses and delete routes */ 35812115Sdyson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 35912115Sdyson if (ifa->ifa_addr->sa_family == AF_INET) 36012115Sdyson /* Unlocked read. */ 36112115Sdyson rtinit(ifa, (int)RTM_DELETE, 36212115Sdyson tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0); 36312115Sdyson ifp->if_flags &= ~IFF_RUNNING; 36412115Sdyson splx(s); 36512115Sdyson } 36612115Sdyson 36712115Sdyson funsetown(&tp->tun_sigio); 36812115Sdyson selwakeuppri(&tp->tun_rsel, PZERO + 1); 36912115Sdyson TUNDEBUG (ifp, "closed\n"); 37012115Sdyson return (0); 37112115Sdyson} 37212115Sdyson 37312115Sdysonstatic int 37412115Sdysontuninit(struct ifnet *ifp) 37512115Sdyson{ 37612115Sdyson struct tun_softc *tp = ifp->if_softc; 37712115Sdyson struct ifaddr *ifa; 37812115Sdyson int error = 0; 37912115Sdyson 38012115Sdyson TUNDEBUG(ifp, "tuninit\n"); 38112115Sdyson 38212115Sdyson ifp->if_flags |= IFF_UP | IFF_RUNNING; 38312115Sdyson getmicrotime(&ifp->if_lastchange); 38412115Sdyson 38512115Sdyson for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 38612115Sdyson ifa = TAILQ_NEXT(ifa, ifa_link)) { 38712115Sdyson if (ifa->ifa_addr == NULL) 38812115Sdyson error = EFAULT; 38912115Sdyson /* XXX: Should maybe return straight off? */ 39012115Sdyson else { 39112115Sdyson#ifdef INET 39212115Sdyson if (ifa->ifa_addr->sa_family == AF_INET) { 39312115Sdyson struct sockaddr_in *si; 39412115Sdyson 39512115Sdyson si = (struct sockaddr_in *)ifa->ifa_addr; 39612115Sdyson mtx_lock(&tp->tun_mtx); 39712115Sdyson if (si->sin_addr.s_addr) 39812115Sdyson tp->tun_flags |= TUN_IASET; 39912115Sdyson 40012115Sdyson si = (struct sockaddr_in *)ifa->ifa_dstaddr; 40112115Sdyson if (si && si->sin_addr.s_addr) 40212115Sdyson tp->tun_flags |= TUN_DSTADDR; 40312115Sdyson mtx_unlock(&tp->tun_mtx); 40412115Sdyson } 40512115Sdyson#endif 40612115Sdyson } 40712115Sdyson } 40812115Sdyson return (error); 40912115Sdyson} 41027881Sdyson 41127881Sdyson/* 41212115Sdyson * Process an ioctl request. 41312115Sdyson */ 41412115Sdysonstatic int 41527881Sdysontunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 41612115Sdyson{ 41712115Sdyson struct ifreq *ifr = (struct ifreq *)data; 41812115Sdyson struct tun_softc *tp = ifp->if_softc; 41912115Sdyson struct ifstat *ifs; 42012115Sdyson int error = 0, s; 42112115Sdyson 42212115Sdyson s = splimp(); 42312115Sdyson switch(cmd) { 42412115Sdyson case SIOCGIFSTATUS: 42512115Sdyson ifs = (struct ifstat *)data; 42612115Sdyson mtx_lock(&tp->tun_mtx); 42712115Sdyson if (tp->tun_pid) 42812115Sdyson sprintf(ifs->ascii + strlen(ifs->ascii), 42912115Sdyson "\tOpened by PID %d\n", tp->tun_pid); 43012115Sdyson mtx_unlock(&tp->tun_mtx); 43112115Sdyson break; 43212115Sdyson case SIOCSIFADDR: 43312115Sdyson error = tuninit(ifp); 43412115Sdyson TUNDEBUG(ifp, "address set, error=%d\n", error); 43512115Sdyson break; 43612115Sdyson case SIOCSIFDSTADDR: 43712115Sdyson error = tuninit(ifp); 43812115Sdyson TUNDEBUG(ifp, "destination address set, error=%d\n", error); 43912115Sdyson break; 44012115Sdyson case SIOCSIFMTU: 44112115Sdyson ifp->if_mtu = ifr->ifr_mtu; 44212115Sdyson TUNDEBUG(ifp, "mtu set\n"); 44312115Sdyson break; 44412115Sdyson case SIOCSIFFLAGS: 44512115Sdyson case SIOCADDMULTI: 44612911Sphk case SIOCDELMULTI: 44712115Sdyson break; 44812115Sdyson default: 44912115Sdyson error = EINVAL; 45012115Sdyson } 45112115Sdyson splx(s); 45212115Sdyson return (error); 45312115Sdyson} 45412115Sdyson 45512115Sdyson/* 45612115Sdyson * tunoutput - queue packets from higher level ready to put out. 45712147Sdyson */ 45812115Sdysonstatic int 45912115Sdysontunoutput( 46012115Sdyson struct ifnet *ifp, 46112115Sdyson struct mbuf *m0, 46212115Sdyson struct sockaddr *dst, 46312115Sdyson struct rtentry *rt) 46412115Sdyson{ 46512115Sdyson struct tun_softc *tp = ifp->if_softc; 46612115Sdyson u_short cached_tun_flags; 46712115Sdyson int error; 46812115Sdyson 46912115Sdyson TUNDEBUG (ifp, "tunoutput\n"); 47012115Sdyson 47112115Sdyson#ifdef MAC 47212115Sdyson error = mac_check_ifnet_transmit(ifp, m0); 47312115Sdyson if (error) { 47412115Sdyson m_freem(m0); 47512115Sdyson return (error); 47612115Sdyson } 47712115Sdyson#endif 47812115Sdyson 47912115Sdyson /* Could be unlocked read? */ 48012115Sdyson mtx_lock(&tp->tun_mtx); 48112115Sdyson cached_tun_flags = tp->tun_flags; 48212115Sdyson mtx_unlock(&tp->tun_mtx); 48312115Sdyson if ((cached_tun_flags & TUN_READY) != TUN_READY) { 48412115Sdyson TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags); 48512115Sdyson m_freem (m0); 48612115Sdyson return (EHOSTDOWN); 48712115Sdyson } 48812115Sdyson 48912115Sdyson if ((ifp->if_flags & IFF_UP) != IFF_UP) { 49012115Sdyson m_freem (m0); 49112115Sdyson return (EHOSTDOWN); 49212115Sdyson } 49312115Sdyson 49412115Sdyson /* BPF write needs to be handled specially */ 49512115Sdyson if (dst->sa_family == AF_UNSPEC) { 49612115Sdyson dst->sa_family = *(mtod(m0, int *)); 49712115Sdyson m0->m_len -= sizeof(int); 49812115Sdyson m0->m_pkthdr.len -= sizeof(int); 49912115Sdyson m0->m_data += sizeof(int); 50012115Sdyson } 50112115Sdyson 50212115Sdyson if (ifp->if_bpf) { 50312115Sdyson uint32_t af = dst->sa_family; 50412115Sdyson bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m0); 50512115Sdyson } 50612115Sdyson 50712115Sdyson /* prepend sockaddr? this may abort if the mbuf allocation fails */ 50812115Sdyson if (cached_tun_flags & TUN_LMODE) { 50912115Sdyson /* allocate space for sockaddr */ 51012115Sdyson M_PREPEND(m0, dst->sa_len, M_DONTWAIT); 51122521Sdyson 51212115Sdyson /* if allocation failed drop packet */ 51312115Sdyson if (m0 == NULL) { 51412115Sdyson ifp->if_iqdrops++; 51512115Sdyson ifp->if_oerrors++; 51612115Sdyson return (ENOBUFS); 51712115Sdyson } else { 51812115Sdyson bcopy(dst, m0->m_data, dst->sa_len); 51912115Sdyson } 52012115Sdyson } 52112115Sdyson 52212115Sdyson if (cached_tun_flags & TUN_IFHEAD) { 52312115Sdyson /* Prepend the address family */ 52412115Sdyson M_PREPEND(m0, 4, M_DONTWAIT); 52512115Sdyson 52612115Sdyson /* if allocation failed drop packet */ 52712115Sdyson if (m0 == NULL) { 52812115Sdyson ifp->if_iqdrops++; 52912115Sdyson ifp->if_oerrors++; 53012115Sdyson return (ENOBUFS); 53112115Sdyson } else 53212115Sdyson *(u_int32_t *)m0->m_data = htonl(dst->sa_family); 53312115Sdyson } else { 53412115Sdyson#ifdef INET 53512115Sdyson if (dst->sa_family != AF_INET) 53612115Sdyson#endif 53712115Sdyson { 53812115Sdyson m_freem(m0); 53912911Sphk return (EAFNOSUPPORT); 54012115Sdyson } 54112115Sdyson } 54212115Sdyson 54312115Sdyson IFQ_HANDOFF(ifp, m0, error); 54412115Sdyson if (error) { 54512115Sdyson ifp->if_collisions++; 54612115Sdyson return (ENOBUFS); 54712115Sdyson } 54812115Sdyson ifp->if_opackets++; 54912115Sdyson return (0); 55012115Sdyson} 55112115Sdyson 55212115Sdyson/* 55312115Sdyson * the cdevsw interface is now pretty minimal. 55412115Sdyson */ 55512115Sdysonstatic int 55612115Sdysontunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 55712115Sdyson{ 55812115Sdyson int s; 55912115Sdyson int error; 56012115Sdyson struct tun_softc *tp = dev->si_drv1; 56112115Sdyson struct tuninfo *tunp; 56212115Sdyson 56312115Sdyson switch (cmd) { 56412115Sdyson case TUNSIFINFO: 56512115Sdyson tunp = (struct tuninfo *)data; 56612115Sdyson if (tunp->mtu < IF_MINMTU) 56712115Sdyson return (EINVAL); 56812115Sdyson if (tp->tun_if.if_mtu != tunp->mtu 56912115Sdyson && (error = suser(td)) != 0) 57012115Sdyson return (error); 57112115Sdyson tp->tun_if.if_mtu = tunp->mtu; 57212115Sdyson tp->tun_if.if_type = tunp->type; 57312115Sdyson tp->tun_if.if_baudrate = tunp->baudrate; 57412115Sdyson break; 57512115Sdyson case TUNGIFINFO: 57612115Sdyson tunp = (struct tuninfo *)data; 57712115Sdyson tunp->mtu = tp->tun_if.if_mtu; 57812115Sdyson tunp->type = tp->tun_if.if_type; 57912115Sdyson tunp->baudrate = tp->tun_if.if_baudrate; 58012115Sdyson break; 58112115Sdyson case TUNSDEBUG: 58212115Sdyson tundebug = *(int *)data; 58312115Sdyson break; 58412115Sdyson case TUNGDEBUG: 58512115Sdyson *(int *)data = tundebug; 58612115Sdyson break; 58712115Sdyson case TUNSLMODE: 58812115Sdyson mtx_lock(&tp->tun_mtx); 58912115Sdyson if (*(int *)data) { 59012115Sdyson tp->tun_flags |= TUN_LMODE; 59112115Sdyson tp->tun_flags &= ~TUN_IFHEAD; 59212115Sdyson } else 59312115Sdyson tp->tun_flags &= ~TUN_LMODE; 59412115Sdyson mtx_unlock(&tp->tun_mtx); 59512115Sdyson break; 59612115Sdyson case TUNSIFHEAD: 59712115Sdyson mtx_lock(&tp->tun_mtx); 59812115Sdyson if (*(int *)data) { 59912115Sdyson tp->tun_flags |= TUN_IFHEAD; 60030280Sphk tp->tun_flags &= ~TUN_LMODE; 60130474Sphk } else 60230474Sphk tp->tun_flags &= ~TUN_IFHEAD; 60330492Sphk mtx_unlock(&tp->tun_mtx); 60430474Sphk break; 60530474Sphk case TUNGIFHEAD: 60612115Sdyson /* Could be unlocked read? */ 60712115Sdyson mtx_lock(&tp->tun_mtx); 60812115Sdyson *(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0; 60912115Sdyson mtx_unlock(&tp->tun_mtx); 61012115Sdyson break; 61112115Sdyson case TUNSIFMODE: 61212115Sdyson /* deny this if UP */ 61312115Sdyson if (tp->tun_if.if_flags & IFF_UP) 61412115Sdyson return(EBUSY); 61512115Sdyson 61612115Sdyson switch (*(int *)data & ~IFF_MULTICAST) { 61712115Sdyson case IFF_POINTOPOINT: 61812115Sdyson case IFF_BROADCAST: 61912115Sdyson tp->tun_if.if_flags &= 62012115Sdyson ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST); 62112115Sdyson tp->tun_if.if_flags |= *(int *)data; 62212115Sdyson break; 62312115Sdyson default: 62412115Sdyson return(EINVAL); 62512115Sdyson } 62612115Sdyson break; 62712115Sdyson case TUNSIFPID: 62812115Sdyson mtx_lock(&tp->tun_mtx); 62912115Sdyson tp->tun_pid = curthread->td_proc->p_pid; 63012115Sdyson mtx_unlock(&tp->tun_mtx); 63112115Sdyson break; 63212115Sdyson case FIONBIO: 63312115Sdyson break; 63412115Sdyson case FIOASYNC: 63512115Sdyson mtx_lock(&tp->tun_mtx); 63612115Sdyson if (*(int *)data) 63712115Sdyson tp->tun_flags |= TUN_ASYNC; 63812115Sdyson else 63912115Sdyson tp->tun_flags &= ~TUN_ASYNC; 64012115Sdyson mtx_unlock(&tp->tun_mtx); 64112115Sdyson break; 64212115Sdyson case FIONREAD: 64312115Sdyson s = splimp(); 64412115Sdyson if (!IFQ_IS_EMPTY(&tp->tun_if.if_snd)) { 64512115Sdyson struct mbuf *mb; 64612115Sdyson IFQ_LOCK(&tp->tun_if.if_snd); 64712115Sdyson IFQ_POLL_NOLOCK(&tp->tun_if.if_snd, mb); 64812115Sdyson for( *(int *)data = 0; mb != 0; mb = mb->m_next) 64912115Sdyson *(int *)data += mb->m_len; 65012115Sdyson IFQ_UNLOCK(&tp->tun_if.if_snd); 65112115Sdyson } else 65212115Sdyson *(int *)data = 0; 65312115Sdyson splx(s); 65412115Sdyson break; 65512115Sdyson case FIOSETOWN: 65612115Sdyson return (fsetown(*(int *)data, &tp->tun_sigio)); 65712115Sdyson 65812115Sdyson case FIOGETOWN: 65912115Sdyson *(int *)data = fgetown(&tp->tun_sigio); 66012115Sdyson return (0); 66112115Sdyson 66212115Sdyson /* This is deprecated, FIOSETOWN should be used instead. */ 66312115Sdyson case TIOCSPGRP: 66412115Sdyson return (fsetown(-(*(int *)data), &tp->tun_sigio)); 66512115Sdyson 66612115Sdyson /* This is deprecated, FIOGETOWN should be used instead. */ 66712115Sdyson case TIOCGPGRP: 66812115Sdyson *(int *)data = -fgetown(&tp->tun_sigio); 66912911Sphk return (0); 67012115Sdyson 67112115Sdyson default: 67212115Sdyson return (ENOTTY); 67312115Sdyson } 67412115Sdyson return (0); 67512115Sdyson} 67612115Sdyson 67712115Sdyson/* 67812115Sdyson * The cdevsw read interface - reads a packet at a time, or at 67912115Sdyson * least as much of a packet as can be read. 68012115Sdyson */ 68112115Sdysonstatic int 68212115Sdysontunread(struct cdev *dev, struct uio *uio, int flag) 68312115Sdyson{ 68412115Sdyson struct tun_softc *tp = dev->si_drv1; 68512115Sdyson struct ifnet *ifp = &tp->tun_if; 68612115Sdyson struct mbuf *m; 68712115Sdyson int error=0, len, s; 68812115Sdyson 68912115Sdyson TUNDEBUG (ifp, "read\n"); 69012115Sdyson mtx_lock(&tp->tun_mtx); 69112115Sdyson if ((tp->tun_flags & TUN_READY) != TUN_READY) { 69212115Sdyson mtx_unlock(&tp->tun_mtx); 69312115Sdyson TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags); 69427881Sdyson return (EHOSTDOWN); 69512115Sdyson } 69612115Sdyson 69727881Sdyson tp->tun_flags &= ~TUN_RWAIT; 69827881Sdyson mtx_unlock(&tp->tun_mtx); 69912115Sdyson 70012115Sdyson s = splimp(); 70112115Sdyson do { 70227881Sdyson IFQ_DEQUEUE(&ifp->if_snd, m); 70327881Sdyson if (m == NULL) { 70412115Sdyson if (flag & IO_NDELAY) { 70512115Sdyson splx(s); 70627881Sdyson return (EWOULDBLOCK); 70712115Sdyson } 70812115Sdyson mtx_lock(&tp->tun_mtx); 70912115Sdyson tp->tun_flags |= TUN_RWAIT; 71012115Sdyson mtx_unlock(&tp->tun_mtx); 71112115Sdyson if((error = tsleep(tp, PCATCH | (PZERO + 1), 71212115Sdyson "tunread", 0)) != 0) { 71312115Sdyson splx(s); 71412115Sdyson return (error); 71512115Sdyson } 71612115Sdyson } 71712115Sdyson } while (m == NULL); 71812115Sdyson splx(s); 71912115Sdyson 72012115Sdyson while (m && uio->uio_resid > 0 && error == 0) { 72112115Sdyson len = min(uio->uio_resid, m->m_len); 72212115Sdyson if (len != 0) 72312911Sphk error = uiomove(mtod(m, void *), len, uio); 72412115Sdyson m = m_free(m); 72512115Sdyson } 72612115Sdyson 72712115Sdyson if (m) { 72812115Sdyson TUNDEBUG(ifp, "Dropping mbuf\n"); 72912115Sdyson m_freem(m); 73012147Sdyson } 73112746Sbde return (error); 73212746Sbde} 73312746Sbde 73412115Sdyson/* 73512115Sdyson * the cdevsw write interface - an atomic write is a packet - or else! 73612115Sdyson */ 73712115Sdysonstatic int 73812115Sdysontunwrite(struct cdev *dev, struct uio *uio, int flag) 73912115Sdyson{ 74012115Sdyson struct tun_softc *tp = dev->si_drv1; 74112115Sdyson struct ifnet *ifp = &tp->tun_if; 74212115Sdyson struct mbuf *m; 74312115Sdyson int error = 0; 74412115Sdyson uint32_t family; 74512115Sdyson int isr; 74612115Sdyson 74712115Sdyson TUNDEBUG(ifp, "tunwrite\n"); 74812115Sdyson 74912115Sdyson if ((ifp->if_flags & IFF_UP) != IFF_UP) 75012115Sdyson /* ignore silently */ 75112115Sdyson return (0); 75212115Sdyson 75312115Sdyson if (uio->uio_resid == 0) 75412115Sdyson return (0); 75512115Sdyson 75612115Sdyson if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) { 75712115Sdyson TUNDEBUG(ifp, "len=%d!\n", uio->uio_resid); 75812115Sdyson return (EIO); 75912911Sphk } 76012115Sdyson 76112115Sdyson if ((m = m_uiotombuf(uio, M_DONTWAIT, 0)) == NULL) { 76212115Sdyson ifp->if_ierrors++; 76312115Sdyson return (error); 76412115Sdyson } 76512115Sdyson 76612115Sdyson m->m_pkthdr.rcvif = ifp; 76712115Sdyson#ifdef MAC 76812115Sdyson mac_create_mbuf_from_ifnet(ifp, m); 76912115Sdyson#endif 77012115Sdyson 77112115Sdyson /* Could be unlocked read? */ 77212115Sdyson mtx_lock(&tp->tun_mtx); 77312115Sdyson if (tp->tun_flags & TUN_IFHEAD) { 77412115Sdyson mtx_unlock(&tp->tun_mtx); 77512115Sdyson if (m->m_len < sizeof(family) && 77612115Sdyson (m = m_pullup(m, sizeof(family))) == NULL) 77712115Sdyson return (ENOBUFS); 77812115Sdyson family = ntohl(*mtod(m, u_int32_t *)); 77912115Sdyson m_adj(m, sizeof(family)); 78012115Sdyson } else { 78112115Sdyson mtx_unlock(&tp->tun_mtx); 78212115Sdyson family = AF_INET; 78312115Sdyson } 78412115Sdyson 78512115Sdyson BPF_MTAP2(ifp, &family, sizeof(family), m); 78612115Sdyson 78712115Sdyson switch (family) { 78812115Sdyson#ifdef INET 78912115Sdyson case AF_INET: 79012115Sdyson isr = NETISR_IP; 79112115Sdyson break; 79212115Sdyson#endif 79312115Sdyson#ifdef INET6 79412115Sdyson case AF_INET6: 79512115Sdyson isr = NETISR_IPV6; 79612115Sdyson break; 79712115Sdyson#endif 79812115Sdyson#ifdef IPX 79912115Sdyson case AF_IPX: 80012115Sdyson isr = NETISR_IPX; 80112115Sdyson break; 80212115Sdyson#endif 80312115Sdyson#ifdef NETATALK 80412115Sdyson case AF_APPLETALK: 80512115Sdyson isr = NETISR_ATALK2; 80612115Sdyson break; 80712115Sdyson#endif 80812115Sdyson default: 80912115Sdyson m_freem(m); 81012115Sdyson return (EAFNOSUPPORT); 81112115Sdyson } 81212115Sdyson /* First chunk of an mbuf contains good junk */ 81312115Sdyson if (harvest.point_to_point) 81412911Sphk random_harvest(m, 16, 3, 0, RANDOM_NET); 81512115Sdyson ifp->if_ibytes += m->m_pkthdr.len; 81612115Sdyson ifp->if_ipackets++; 81712115Sdyson netisr_dispatch(isr, m); 81812115Sdyson return (0); 81912115Sdyson} 82012115Sdyson 82112115Sdyson/* 82212115Sdyson * tunpoll - the poll interface, this is only useful on reads 82312115Sdyson * really. The write detect always returns true, write never blocks 82412115Sdyson * anyway, it either accepts the packet or drops it. 82512115Sdyson */ 82612115Sdysonstatic int 82712115Sdysontunpoll(struct cdev *dev, int events, struct thread *td) 82812115Sdyson{ 82912115Sdyson int s; 83012115Sdyson struct tun_softc *tp = dev->si_drv1; 83112115Sdyson struct ifnet *ifp = &tp->tun_if; 83212115Sdyson int revents = 0; 83312115Sdyson struct mbuf *m; 83412115Sdyson 83512115Sdyson s = splimp(); 83612115Sdyson TUNDEBUG(ifp, "tunpoll\n"); 83712115Sdyson 83812115Sdyson if (events & (POLLIN | POLLRDNORM)) { 83912115Sdyson IFQ_LOCK(&ifp->if_snd); 84012115Sdyson IFQ_POLL_NOLOCK(&ifp->if_snd, m); 84112115Sdyson if (m != NULL) { 84212115Sdyson TUNDEBUG(ifp, "tunpoll q=%d\n", ifp->if_snd.ifq_len); 84312115Sdyson revents |= events & (POLLIN | POLLRDNORM); 84412115Sdyson } else { 84512115Sdyson TUNDEBUG(ifp, "tunpoll waiting\n"); 84612115Sdyson selrecord(td, &tp->tun_rsel); 84712115Sdyson } 84812115Sdyson IFQ_UNLOCK(&ifp->if_snd); 84912115Sdyson } 85012115Sdyson if (events & (POLLOUT | POLLWRNORM)) 85112115Sdyson revents |= events & (POLLOUT | POLLWRNORM); 85212115Sdyson 85312115Sdyson splx(s); 85412115Sdyson return (revents); 85512115Sdyson} 85612115Sdyson