if_tun.c revision 71959
1199989Srdivacky/* $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $ */ 2199989Srdivacky 3199989Srdivacky/* 4199989Srdivacky * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 5199989Srdivacky * Nottingham University 1987. 6199989Srdivacky * 7199989Srdivacky * This source may be freely distributed, however I would be interested 8199989Srdivacky * in any changes that are made. 9199989Srdivacky * 10199989Srdivacky * This driver takes packets off the IP i/f and hands them up to a 11199989Srdivacky * user process to have its wicked way with. This driver has it's 12199989Srdivacky * roots in a similar driver written by Phil Cockcroft (formerly) at 13199989Srdivacky * UCL. This driver is based much more on read/write/poll mode of 14199989Srdivacky * operation though. 15199989Srdivacky * 16249423Sdim * $FreeBSD: head/sys/net/if_tun.c 71959 2001-02-03 11:46:35Z phk $ 17234353Sdim */ 18207618Srdivacky 19249423Sdim#include "opt_inet.h" 20199989Srdivacky 21199989Srdivacky#include <sys/param.h> 22199989Srdivacky#include <sys/proc.h> 23199989Srdivacky#include <sys/systm.h> 24249423Sdim#include <sys/mbuf.h> 25249423Sdim#include <sys/module.h> 26249423Sdim#include <sys/socket.h> 27249423Sdim#include <sys/filio.h> 28249423Sdim#include <sys/sockio.h> 29249423Sdim#include <sys/ttycom.h> 30249423Sdim#include <sys/poll.h> 31249423Sdim#include <sys/signalvar.h> 32249423Sdim#include <sys/filedesc.h> 33249423Sdim#include <sys/kernel.h> 34249423Sdim#include <sys/sysctl.h> 35199989Srdivacky#include <sys/conf.h> 36199989Srdivacky#include <sys/uio.h> 37199989Srdivacky#include <sys/vnode.h> 38249423Sdim#include <sys/malloc.h> 39199989Srdivacky 40199989Srdivacky#include <net/if.h> 41199989Srdivacky#include <net/if_types.h> 42199989Srdivacky#include <net/route.h> 43199989Srdivacky#include <net/intrq.h> 44199989Srdivacky 45207618Srdivacky#ifdef INET 46207618Srdivacky#include <netinet/in.h> 47199989Srdivacky#endif 48207618Srdivacky 49207618Srdivacky#include <net/bpf.h> 50210299Sed 51210299Sed#include <net/if_tunvar.h> 52210299Sed#include <net/if_tun.h> 53199989Srdivacky 54210299Sedstatic MALLOC_DEFINE(M_TUN, "tun", "Tunnel Interface"); 55199989Srdivacky 56199989Srdivackystatic void tuncreate __P((dev_t dev)); 57199989Srdivacky 58263508Sdim#define TUNDEBUG if (tundebug) printf 59263508Sdimstatic int tundebug = 0; 60199989SrdivackySYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); 61199989Srdivacky 62199989Srdivackystatic int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, 63199989Srdivacky struct rtentry *rt)); 64199989Srdivackystatic int tunifioctl __P((struct ifnet *, u_long, caddr_t)); 65210299Sedstatic int tuninit __P((struct ifnet *)); 66210299Sedstatic void tunstart __P((struct ifnet *)); 67263508Sdim 68263508Sdimstatic d_open_t tunopen; 69263508Sdimstatic d_close_t tunclose; 70263508Sdimstatic d_read_t tunread; 71210299Sedstatic d_write_t tunwrite; 72199989Srdivackystatic d_ioctl_t tunioctl; 73199989Srdivackystatic d_poll_t tunpoll; 74199989Srdivacky 75207618Srdivacky#define CDEV_MAJOR 52 76207618Srdivackystatic struct cdevsw tun_cdevsw = { 77207618Srdivacky /* open */ tunopen, 78207618Srdivacky /* close */ tunclose, 79226633Sdim /* read */ tunread, 80263508Sdim /* write */ tunwrite, 81199989Srdivacky /* ioctl */ tunioctl, 82263508Sdim /* poll */ tunpoll, 83199989Srdivacky /* mmap */ nommap, 84199989Srdivacky /* strategy */ nostrategy, 85199989Srdivacky /* name */ "tun", 86199989Srdivacky /* maj */ CDEV_MAJOR, 87212904Sdim /* dump */ nodump, 88212904Sdim /* psize */ nopsize, 89212904Sdim /* flags */ 0, 90212904Sdim /* bmaj */ -1 91212904Sdim}; 92212904Sdim 93234353Sdimstatic void tun_clone __P((void *arg, char *name, int namelen, dev_t *dev)); 94212904Sdim 95199989Srdivackystatic void 96234353Sdimtun_clone(arg, name, namelen, dev) 97243830Sdim void *arg; 98199989Srdivacky char *name; 99199989Srdivacky int namelen; 100199989Srdivacky dev_t *dev; 101234353Sdim{ 102234353Sdim int u; 103212904Sdim 104212904Sdim if (*dev != NODEV) 105207618Srdivacky return; 106199989Srdivacky if (dev_stdclone(name, NULL, "tun", &u) != 1) 107199989Srdivacky return; 108199989Srdivacky *dev = make_dev(&tun_cdevsw, unit2minor(u), 109199989Srdivacky UID_ROOT, GID_WHEEL, 0600, "tun%d", u); 110212904Sdim 111212904Sdim} 112212904Sdim 113212904Sdimstatic int 114212904Sdimtun_modevent(module_t mod, int type, void *data) 115263508Sdim{ 116263508Sdim switch (type) { 117263508Sdim case MOD_LOAD: 118212904Sdim EVENTHANDLER_REGISTER(dev_clone, tun_clone, 0, 1000); 119263508Sdim cdevsw_add(&tun_cdevsw); 120212904Sdim break; 121212904Sdim case MOD_UNLOAD: 122212904Sdim printf("if_tun module unload - not possible for this module type\n"); 123212904Sdim return EINVAL; 124212904Sdim } 125212904Sdim return 0; 126212904Sdim} 127212904Sdim 128212904Sdimstatic moduledata_t tun_mod = { 129212904Sdim "if_tun", 130212904Sdim tun_modevent, 131212904Sdim 0 132212904Sdim}; 133212904Sdim 134212904SdimDECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 135212904Sdim 136212904Sdimstatic void 137212904Sdimtunstart(ifp) 138212904Sdim struct ifnet *ifp; 139212904Sdim{ 140212904Sdim struct tun_softc *tp = ifp->if_softc; 141212904Sdim 142199989Srdivacky if (tp->tun_flags & TUN_RWAIT) { 143199989Srdivacky tp->tun_flags &= ~TUN_RWAIT; 144199989Srdivacky wakeup((caddr_t)tp); 145207618Srdivacky } 146199989Srdivacky if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) 147199989Srdivacky pgsigio(tp->tun_sigio, SIGIO, 0); 148199989Srdivacky selwakeup(&tp->tun_rsel); 149199989Srdivacky} 150199989Srdivacky 151199989Srdivackystatic void 152199989Srdivackytuncreate(dev) 153199989Srdivacky dev_t dev; 154199989Srdivacky{ 155199989Srdivacky struct tun_softc *sc; 156199989Srdivacky struct ifnet *ifp; 157199989Srdivacky 158207618Srdivacky dev = make_dev(&tun_cdevsw, minor(dev), 159207618Srdivacky UID_UUCP, GID_DIALER, 0600, "tun%d", dev2unit(dev)); 160207618Srdivacky 161199989Srdivacky MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO); 162223017Sdim sc->tun_flags = TUN_INITED; 163223017Sdim 164223017Sdim ifp = &sc->tun_if; 165223017Sdim ifp->if_unit = dev2unit(dev); 166207618Srdivacky ifp->if_name = "tun"; 167199989Srdivacky ifp->if_mtu = TUNMTU; 168199989Srdivacky ifp->if_ioctl = tunifioctl; 169199989Srdivacky ifp->if_output = tunoutput; 170199989Srdivacky ifp->if_start = tunstart; 171263508Sdim ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; 172199989Srdivacky ifp->if_type = IFT_PPP; 173199989Srdivacky ifp->if_snd.ifq_maxlen = ifqmaxlen; 174263508Sdim ifp->if_softc = sc; 175199989Srdivacky if_attach(ifp); 176199989Srdivacky bpfattach(ifp, DLT_NULL, sizeof(u_int)); 177203954Srdivacky dev->si_drv1 = sc; 178199989Srdivacky} 179199989Srdivacky 180199989Srdivacky/* 181199989Srdivacky * tunnel open - must be superuser & the device must be 182207618Srdivacky * configured in 183207618Srdivacky */ 184207618Srdivackystatic int 185207618Srdivackytunopen(dev, flag, mode, p) 186207618Srdivacky dev_t dev; 187199989Srdivacky int flag, mode; 188199989Srdivacky struct proc *p; 189199989Srdivacky{ 190199989Srdivacky struct ifnet *ifp; 191199989Srdivacky struct tun_softc *tp; 192199989Srdivacky 193207618Srdivacky tp = dev->si_drv1; 194207618Srdivacky if (!tp) { 195207618Srdivacky tuncreate(dev); 196199989Srdivacky tp = dev->si_drv1; 197199989Srdivacky } 198199989Srdivacky if (tp->tun_flags & TUN_OPEN) 199199989Srdivacky return EBUSY; 200199989Srdivacky tp->tun_pid = p->p_pid; 201199989Srdivacky ifp = &tp->tun_if; 202199989Srdivacky tp->tun_flags |= TUN_OPEN; 203199989Srdivacky TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit); 204219077Sdim return (0); 205207618Srdivacky} 206212904Sdim 207210299Sed/* 208199989Srdivacky * tunclose - close the device - mark i/f down & delete 209199989Srdivacky * routing info 210210299Sed */ 211249423Sdimstatic int 212263508Sdimtunclose(dev, foo, bar, p) 213263508Sdim dev_t dev; 214199989Srdivacky int foo; 215199989Srdivacky int bar; 216210299Sed struct proc *p; 217199989Srdivacky{ 218199989Srdivacky register int s; 219199989Srdivacky struct tun_softc *tp; 220199989Srdivacky struct ifnet *ifp; 221199989Srdivacky 222199989Srdivacky tp = dev->si_drv1; 223226633Sdim ifp = &tp->tun_if; 224263508Sdim 225263508Sdim tp->tun_flags &= ~TUN_OPEN; 226199989Srdivacky tp->tun_pid = 0; 227263508Sdim 228199989Srdivacky /* 229199989Srdivacky * junk all pending output 230199989Srdivacky */ 231199989Srdivacky IF_DRAIN(&ifp->if_snd); 232263508Sdim 233199989Srdivacky if (ifp->if_flags & IFF_UP) { 234263508Sdim s = splimp(); 235199989Srdivacky if_down(ifp); 236210299Sed splx(s); 237199989Srdivacky } 238199989Srdivacky 239199989Srdivacky if (ifp->if_flags & IFF_RUNNING) { 240199989Srdivacky register struct ifaddr *ifa; 241199989Srdivacky 242199989Srdivacky s = splimp(); 243219077Sdim /* find internet addresses and delete routes */ 244219077Sdim for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 245219077Sdim ifa = TAILQ_NEXT(ifa, ifa_link)) 246219077Sdim if (ifa->ifa_addr->sa_family == AF_INET) 247219077Sdim rtinit(ifa, (int)RTM_DELETE, 248219077Sdim tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0); 249219077Sdim ifp->if_flags &= ~IFF_RUNNING; 250219077Sdim splx(s); 251219077Sdim } 252219077Sdim 253219077Sdim funsetown(tp->tun_sigio); 254219077Sdim selwakeup(&tp->tun_rsel); 255219077Sdim 256219077Sdim TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit); 257219077Sdim return (0); 258219077Sdim} 259219077Sdim 260219077Sdimstatic int 261219077Sdimtuninit(ifp) 262219077Sdim struct ifnet *ifp; 263219077Sdim{ 264219077Sdim struct tun_softc *tp = ifp->if_softc; 265219077Sdim register struct ifaddr *ifa; 266219077Sdim int error = 0; 267219077Sdim 268219077Sdim TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit); 269226633Sdim 270219077Sdim ifp->if_flags |= IFF_UP | IFF_RUNNING; 271219077Sdim getmicrotime(&ifp->if_lastchange); 272219077Sdim 273263508Sdim for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 274263508Sdim ifa = TAILQ_NEXT(ifa, ifa_link)) { 275219077Sdim if (ifa->ifa_addr == NULL) 276263508Sdim error = EFAULT; 277219077Sdim /* XXX: Should maybe return straight off? */ 278219077Sdim else { 279219077Sdim#ifdef INET 280219077Sdim if (ifa->ifa_addr->sa_family == AF_INET) { 281263508Sdim struct sockaddr_in *si; 282219077Sdim 283263508Sdim si = (struct sockaddr_in *)ifa->ifa_addr; 284219077Sdim if (si->sin_addr.s_addr) 285219077Sdim tp->tun_flags |= TUN_IASET; 286219077Sdim 287219077Sdim si = (struct sockaddr_in *)ifa->ifa_dstaddr; 288219077Sdim if (si && si->sin_addr.s_addr) 289219077Sdim tp->tun_flags |= TUN_DSTADDR; 290219077Sdim } 291219077Sdim#endif 292219077Sdim } 293219077Sdim } 294219077Sdim return (error); 295219077Sdim} 296219077Sdim 297219077Sdim/* 298219077Sdim * Process an ioctl request. 299219077Sdim */ 300219077Sdimint 301219077Sdimtunifioctl(ifp, cmd, data) 302219077Sdim struct ifnet *ifp; 303219077Sdim u_long cmd; 304219077Sdim caddr_t data; 305219077Sdim{ 306219077Sdim struct ifreq *ifr = (struct ifreq *)data; 307219077Sdim struct tun_softc *tp = ifp->if_softc; 308219077Sdim struct ifstat *ifs; 309219077Sdim int error = 0, s; 310219077Sdim 311219077Sdim s = splimp(); 312219077Sdim switch(cmd) { 313219077Sdim case SIOCGIFSTATUS: 314219077Sdim ifs = (struct ifstat *)data; 315219077Sdim if (tp->tun_pid) 316219077Sdim sprintf(ifs->ascii + strlen(ifs->ascii), 317219077Sdim "\tOpened by PID %d\n", tp->tun_pid); 318219077Sdim break; 319219077Sdim case SIOCSIFADDR: 320219077Sdim error = tuninit(ifp); 321219077Sdim TUNDEBUG("%s%d: address set, error=%d\n", 322219077Sdim ifp->if_name, ifp->if_unit, error); 323219077Sdim break; 324219077Sdim case SIOCSIFDSTADDR: 325219077Sdim error = tuninit(ifp); 326219077Sdim TUNDEBUG("%s%d: destination address set, error=%d\n", 327219077Sdim ifp->if_name, ifp->if_unit, error); 328219077Sdim break; 329219077Sdim case SIOCSIFMTU: 330219077Sdim ifp->if_mtu = ifr->ifr_mtu; 331219077Sdim TUNDEBUG("%s%d: mtu set\n", ifp->if_name, ifp->if_unit); 332219077Sdim break; 333223017Sdim case SIOCADDMULTI: 334219077Sdim case SIOCDELMULTI: 335219077Sdim break; 336219077Sdim default: 337219077Sdim error = EINVAL; 338219077Sdim } 339219077Sdim splx(s); 340219077Sdim return (error); 341219077Sdim} 342219077Sdim 343219077Sdim/* 344219077Sdim * tunoutput - queue packets from higher level ready to put out. 345219077Sdim */ 346219077Sdimint 347219077Sdimtunoutput(ifp, m0, dst, rt) 348219077Sdim struct ifnet *ifp; 349219077Sdim struct mbuf *m0; 350219077Sdim struct sockaddr *dst; 351219077Sdim struct rtentry *rt; 352219077Sdim{ 353219077Sdim struct tun_softc *tp = ifp->if_softc; 354219077Sdim 355219077Sdim TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit); 356219077Sdim 357219077Sdim if ((tp->tun_flags & TUN_READY) != TUN_READY) { 358219077Sdim TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, 359219077Sdim ifp->if_unit, tp->tun_flags); 360219077Sdim m_freem (m0); 361219077Sdim return EHOSTDOWN; 362226633Sdim } 363212904Sdim 364212904Sdim /* BPF write needs to be handled specially */ 365226633Sdim if (dst->sa_family == AF_UNSPEC) { 366234353Sdim dst->sa_family = *(mtod(m0, int *)); 367212904Sdim m0->m_len -= sizeof(int); 368212904Sdim m0->m_pkthdr.len -= sizeof(int); 369223017Sdim m0->m_data += sizeof(int); 370226633Sdim } 371212904Sdim 372212904Sdim if (ifp->if_bpf) { 373226633Sdim /* 374223017Sdim * We need to prepend the address family as 375212904Sdim * a four byte field. Cons up a dummy header 376212904Sdim * to pacify bpf. This is safe because bpf 377212904Sdim * will only read from the mbuf (i.e., it won't 378234353Sdim * try to free it or keep a pointer to it). 379212904Sdim */ 380212904Sdim struct mbuf m; 381212904Sdim uint32_t af = dst->sa_family; 382234353Sdim 383234353Sdim m.m_next = m0; 384234353Sdim m.m_len = 4; 385234353Sdim m.m_data = (char *)⁡ 386234353Sdim 387234353Sdim bpf_mtap(ifp, &m); 388234353Sdim } 389234353Sdim 390234353Sdim /* prepend sockaddr? this may abort if the mbuf allocation fails */ 391234353Sdim if (tp->tun_flags & TUN_LMODE) { 392234353Sdim /* allocate space for sockaddr */ 393234353Sdim M_PREPEND(m0, dst->sa_len, M_DONTWAIT); 394234353Sdim 395234353Sdim /* if allocation failed drop packet */ 396234353Sdim if (m0 == NULL) { 397234353Sdim ifp->if_iqdrops++; 398234353Sdim ifp->if_oerrors++; 399234353Sdim return (ENOBUFS); 400234353Sdim } else { 401234353Sdim bcopy(dst, m0->m_data, dst->sa_len); 402234353Sdim } 403234353Sdim } 404234353Sdim 405234353Sdim if (tp->tun_flags & TUN_IFHEAD) { 406199989Srdivacky /* Prepend the address family */ 407199989Srdivacky M_PREPEND(m0, 4, M_DONTWAIT); 408207618Srdivacky 409199989Srdivacky /* if allocation failed drop packet */ 410199989Srdivacky if (m0 == NULL) { 411210299Sed ifp->if_iqdrops++; 412199989Srdivacky ifp->if_oerrors++; 413199989Srdivacky return ENOBUFS; 414199989Srdivacky } else 415199989Srdivacky *(u_int32_t *)m0->m_data = htonl(dst->sa_family); 416199989Srdivacky } else { 417199989Srdivacky#ifdef INET 418199989Srdivacky if (dst->sa_family != AF_INET) 419207618Srdivacky#endif 420210299Sed { 421199989Srdivacky m_freem(m0); 422210299Sed return EAFNOSUPPORT; 423210299Sed } 424199989Srdivacky } 425199989Srdivacky 426210299Sed if (! IF_HANDOFF(&ifp->if_snd, m0, ifp)) { 427199989Srdivacky ifp->if_collisions++; 428199989Srdivacky return ENOBUFS; 429199989Srdivacky } 430199989Srdivacky ifp->if_opackets++; 431210299Sed return 0; 432199989Srdivacky} 433199989Srdivacky 434199989Srdivacky/* 435199989Srdivacky * the cdevsw interface is now pretty minimal. 436199989Srdivacky */ 437199989Srdivackystatic int 438199989Srdivackytunioctl(dev, cmd, data, flag, p) 439199989Srdivacky dev_t dev; 440199989Srdivacky u_long cmd; 441199989Srdivacky caddr_t data; 442199989Srdivacky int flag; 443210299Sed struct proc *p; 444199989Srdivacky{ 445199989Srdivacky int s; 446199989Srdivacky int error; 447199989Srdivacky struct tun_softc *tp = dev->si_drv1; 448199989Srdivacky struct tuninfo *tunp; 449199989Srdivacky 450199989Srdivacky switch (cmd) { 451199989Srdivacky case TUNSIFINFO: 452210299Sed tunp = (struct tuninfo *)data; 453210299Sed if (tunp->mtu < IF_MINMTU) 454210299Sed return (EINVAL); 455210299Sed if (tp->tun_if.if_mtu != tunp->mtu && (error = suser(p)) != 0) 456199989Srdivacky return (error); 457199989Srdivacky tp->tun_if.if_mtu = tunp->mtu; 458199989Srdivacky tp->tun_if.if_type = tunp->type; 459199989Srdivacky tp->tun_if.if_baudrate = tunp->baudrate; 460226633Sdim break; 461226633Sdim case TUNGIFINFO: 462226633Sdim tunp = (struct tuninfo *)data; 463226633Sdim tunp->mtu = tp->tun_if.if_mtu; 464226633Sdim tunp->type = tp->tun_if.if_type; 465226633Sdim tunp->baudrate = tp->tun_if.if_baudrate; 466226633Sdim break; 467226633Sdim case TUNSDEBUG: 468226633Sdim tundebug = *(int *)data; 469226633Sdim break; 470226633Sdim case TUNGDEBUG: 471226633Sdim *(int *)data = tundebug; 472226633Sdim break; 473226633Sdim case TUNSLMODE: 474226633Sdim if (*(int *)data) { 475226633Sdim tp->tun_flags |= TUN_LMODE; 476226633Sdim tp->tun_flags &= ~TUN_IFHEAD; 477226633Sdim } else 478226633Sdim tp->tun_flags &= ~TUN_LMODE; 479226633Sdim break; 480226633Sdim case TUNSIFHEAD: 481226633Sdim if (*(int *)data) { 482226633Sdim tp->tun_flags |= TUN_IFHEAD; 483226633Sdim tp->tun_flags &= ~TUN_LMODE; 484226633Sdim } else 485226633Sdim tp->tun_flags &= ~TUN_IFHEAD; 486226633Sdim break; 487226633Sdim case TUNGIFHEAD: 488226633Sdim *(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0; 489226633Sdim break; 490 case TUNSIFMODE: 491 /* deny this if UP */ 492 if (tp->tun_if.if_flags & IFF_UP) 493 return(EBUSY); 494 495 switch (*(int *)data) { 496 case IFF_POINTOPOINT: 497 tp->tun_if.if_flags |= IFF_POINTOPOINT; 498 tp->tun_if.if_flags &= ~IFF_BROADCAST; 499 break; 500 case IFF_BROADCAST: 501 tp->tun_if.if_flags &= ~IFF_POINTOPOINT; 502 tp->tun_if.if_flags |= IFF_BROADCAST; 503 break; 504 default: 505 return(EINVAL); 506 } 507 break; 508 case TUNSIFPID: 509 tp->tun_pid = curproc->p_pid; 510 break; 511 case FIONBIO: 512 break; 513 case FIOASYNC: 514 if (*(int *)data) 515 tp->tun_flags |= TUN_ASYNC; 516 else 517 tp->tun_flags &= ~TUN_ASYNC; 518 break; 519 case FIONREAD: 520 s = splimp(); 521 if (tp->tun_if.if_snd.ifq_head) { 522 struct mbuf *mb = tp->tun_if.if_snd.ifq_head; 523 for( *(int *)data = 0; mb != 0; mb = mb->m_next) 524 *(int *)data += mb->m_len; 525 } else 526 *(int *)data = 0; 527 splx(s); 528 break; 529 case FIOSETOWN: 530 return (fsetown(*(int *)data, &tp->tun_sigio)); 531 532 case FIOGETOWN: 533 *(int *)data = fgetown(tp->tun_sigio); 534 return (0); 535 536 /* This is deprecated, FIOSETOWN should be used instead. */ 537 case TIOCSPGRP: 538 return (fsetown(-(*(int *)data), &tp->tun_sigio)); 539 540 /* This is deprecated, FIOGETOWN should be used instead. */ 541 case TIOCGPGRP: 542 *(int *)data = -fgetown(tp->tun_sigio); 543 return (0); 544 545 default: 546 return (ENOTTY); 547 } 548 return (0); 549} 550 551/* 552 * The cdevsw read interface - reads a packet at a time, or at 553 * least as much of a packet as can be read. 554 */ 555static int 556tunread(dev, uio, flag) 557 dev_t dev; 558 struct uio *uio; 559 int flag; 560{ 561 struct tun_softc *tp = dev->si_drv1; 562 struct ifnet *ifp = &tp->tun_if; 563 struct mbuf *m, *m0; 564 int error=0, len, s; 565 566 TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit); 567 if ((tp->tun_flags & TUN_READY) != TUN_READY) { 568 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, 569 ifp->if_unit, tp->tun_flags); 570 return EHOSTDOWN; 571 } 572 573 tp->tun_flags &= ~TUN_RWAIT; 574 575 s = splimp(); 576 do { 577 IF_DEQUEUE(&ifp->if_snd, m0); 578 if (m0 == 0) { 579 if (flag & IO_NDELAY) { 580 splx(s); 581 return EWOULDBLOCK; 582 } 583 tp->tun_flags |= TUN_RWAIT; 584 if((error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1), 585 "tunread", 0)) != 0) { 586 splx(s); 587 return error; 588 } 589 } 590 } while (m0 == 0); 591 splx(s); 592 593 while (m0 && uio->uio_resid > 0 && error == 0) { 594 len = min(uio->uio_resid, m0->m_len); 595 if (len == 0) 596 break; 597 error = uiomove(mtod(m0, caddr_t), len, uio); 598 MFREE(m0, m); 599 m0 = m; 600 } 601 602 if (m0) { 603 TUNDEBUG("Dropping mbuf\n"); 604 m_freem(m0); 605 } 606 return error; 607} 608 609/* 610 * the cdevsw write interface - an atomic write is a packet - or else! 611 */ 612static int 613tunwrite(dev, uio, flag) 614 dev_t dev; 615 struct uio *uio; 616 int flag; 617{ 618 struct tun_softc *tp = dev->si_drv1; 619 struct ifnet *ifp = &tp->tun_if; 620 struct mbuf *top, **mp, *m; 621 int error=0, tlen, mlen; 622 uint32_t family; 623 624 TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit); 625 626 if (uio->uio_resid == 0) 627 return 0; 628 629 if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) { 630 TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit, 631 uio->uio_resid); 632 return EIO; 633 } 634 tlen = uio->uio_resid; 635 636 /* get a header mbuf */ 637 MGETHDR(m, M_DONTWAIT, MT_DATA); 638 if (m == NULL) 639 return ENOBUFS; 640 mlen = MHLEN; 641 642 top = 0; 643 mp = ⊤ 644 while (error == 0 && uio->uio_resid > 0) { 645 m->m_len = min(mlen, uio->uio_resid); 646 error = uiomove(mtod (m, caddr_t), m->m_len, uio); 647 *mp = m; 648 mp = &m->m_next; 649 if (uio->uio_resid > 0) { 650 MGET (m, M_DONTWAIT, MT_DATA); 651 if (m == 0) { 652 error = ENOBUFS; 653 break; 654 } 655 mlen = MLEN; 656 } 657 } 658 if (error) { 659 if (top) 660 m_freem (top); 661 ifp->if_ierrors++; 662 return error; 663 } 664 665 top->m_pkthdr.len = tlen; 666 top->m_pkthdr.rcvif = ifp; 667 668 if (ifp->if_bpf) { 669 if (tp->tun_flags & TUN_IFHEAD) { 670 /* 671 * Conveniently, we already have a 4-byte address 672 * family prepended to our packet ! 673 * Inconveniently, it's in the wrong byte order ! 674 */ 675 if ((top = m_pullup(top, sizeof(family))) == NULL) 676 return ENOBUFS; 677 *mtod(top, u_int32_t *) = 678 ntohl(*mtod(top, u_int32_t *)); 679 bpf_mtap(ifp, top); 680 *mtod(top, u_int32_t *) = 681 htonl(*mtod(top, u_int32_t *)); 682 } else { 683 /* 684 * We need to prepend the address family as 685 * a four byte field. Cons up a dummy header 686 * to pacify bpf. This is safe because bpf 687 * will only read from the mbuf (i.e., it won't 688 * try to free it or keep a pointer to it). 689 */ 690 struct mbuf m; 691 uint32_t af = AF_INET; 692 693 m.m_next = top; 694 m.m_len = 4; 695 m.m_data = (char *)⁡ 696 697 bpf_mtap(ifp, &m); 698 } 699 } 700 701 if (tp->tun_flags & TUN_IFHEAD) { 702 if (top->m_len < sizeof(family) && 703 (top = m_pullup(top, sizeof(family))) == NULL) 704 return ENOBUFS; 705 family = ntohl(*mtod(top, u_int32_t *)); 706 m_adj(top, sizeof(family)); 707 } else 708 family = AF_INET; 709 710 ifp->if_ibytes += top->m_pkthdr.len; 711 ifp->if_ipackets++; 712 713 return family_enqueue(family, top); 714} 715 716/* 717 * tunpoll - the poll interface, this is only useful on reads 718 * really. The write detect always returns true, write never blocks 719 * anyway, it either accepts the packet or drops it. 720 */ 721static int 722tunpoll(dev, events, p) 723 dev_t dev; 724 int events; 725 struct proc *p; 726{ 727 int s; 728 struct tun_softc *tp = dev->si_drv1; 729 struct ifnet *ifp = &tp->tun_if; 730 int revents = 0; 731 732 s = splimp(); 733 TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit); 734 735 if (events & (POLLIN | POLLRDNORM)) { 736 if (ifp->if_snd.ifq_len > 0) { 737 TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name, 738 ifp->if_unit, ifp->if_snd.ifq_len); 739 revents |= events & (POLLIN | POLLRDNORM); 740 } else { 741 TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name, 742 ifp->if_unit); 743 selrecord(p, &tp->tun_rsel); 744 } 745 } 746 if (events & (POLLOUT | POLLWRNORM)) 747 revents |= events & (POLLOUT | POLLWRNORM); 748 749 splx(s); 750 return (revents); 751} 752