Annotation of sys/net/if_tun.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_tun.c,v 1.89 2007/06/06 10:04:36 henning Exp $ */
! 2: /* $NetBSD: if_tun.c,v 1.24 1996/05/07 02:40:48 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1988, Julian Onions <Julian.Onions@nexor.co.uk>
! 6: * Nottingham University 1987.
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: /*
! 31: * This driver takes packets off the IP i/f and hands them up to a
! 32: * user process to have its wicked way with. This driver has its
! 33: * roots in a similar driver written by Phil Cockcroft (formerly) at
! 34: * UCL. This driver is based much more on read/write/select mode of
! 35: * operation though.
! 36: */
! 37:
! 38: /* #define TUN_DEBUG 9 */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/proc.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/mbuf.h>
! 45: #include <sys/protosw.h>
! 46: #include <sys/socket.h>
! 47: #include <sys/ioctl.h>
! 48: #include <sys/errno.h>
! 49: #include <sys/syslog.h>
! 50: #include <sys/selinfo.h>
! 51: #include <sys/file.h>
! 52: #include <sys/time.h>
! 53: #include <sys/device.h>
! 54: #include <sys/vnode.h>
! 55: #include <sys/signalvar.h>
! 56: #include <sys/poll.h>
! 57: #include <sys/conf.h>
! 58:
! 59: #include <machine/cpu.h>
! 60:
! 61: #include <net/if.h>
! 62: #include <net/if_types.h>
! 63: #include <net/netisr.h>
! 64: #include <net/route.h>
! 65:
! 66: #ifdef INET
! 67: #include <netinet/in.h>
! 68: #include <netinet/in_systm.h>
! 69: #include <netinet/in_var.h>
! 70: #include <netinet/ip.h>
! 71: #include <netinet/if_ether.h>
! 72: #endif
! 73:
! 74: #ifdef NETATALK
! 75: #include <netatalk/at.h>
! 76: #include <netatalk/at_var.h>
! 77: #endif
! 78:
! 79: #include "bpfilter.h"
! 80: #if NBPFILTER > 0
! 81: #include <net/bpf.h>
! 82: #endif
! 83:
! 84: /* for arc4random() */
! 85: #include <dev/rndvar.h>
! 86:
! 87: #include <net/if_tun.h>
! 88:
! 89: struct tun_softc {
! 90: struct arpcom arpcom; /* ethernet common data */
! 91: u_short tun_flags; /* misc flags */
! 92: pid_t tun_pgid; /* the process group - if any */
! 93: uid_t tun_siguid; /* uid for process that set tun_pgid */
! 94: uid_t tun_sigeuid; /* euid for process that set tun_pgid */
! 95: struct selinfo tun_rsel; /* read select */
! 96: struct selinfo tun_wsel; /* write select (not used) */
! 97: int tun_unit;
! 98: LIST_ENTRY(tun_softc) tun_list; /* all tunnel interfaces */
! 99: #define tun_if arpcom.ac_if
! 100: };
! 101:
! 102: #ifdef TUN_DEBUG
! 103: int tundebug = TUN_DEBUG;
! 104: #define TUNDEBUG(a) (tundebug? printf a : 0)
! 105: #else
! 106: #define TUNDEBUG(a) /* (tundebug? printf a : 0) */
! 107: #endif
! 108:
! 109: /* Only these IFF flags are changeable by TUNSIFINFO */
! 110: #define TUN_IFF_FLAGS (IFF_UP|IFF_POINTOPOINT|IFF_MULTICAST|IFF_BROADCAST)
! 111:
! 112: void tunattach(int);
! 113: int tunopen(dev_t, int, int, struct proc *);
! 114: int tunclose(dev_t, int, int, struct proc *);
! 115: int tun_ioctl(struct ifnet *, u_long, caddr_t);
! 116: int tun_output(struct ifnet *, struct mbuf *, struct sockaddr *,
! 117: struct rtentry *);
! 118: int tunioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 119: int tunread(dev_t, struct uio *, int);
! 120: int tunwrite(dev_t, struct uio *, int);
! 121: int tunpoll(dev_t, int, struct proc *);
! 122: int tunkqfilter(dev_t, struct knote *);
! 123: int tun_clone_create(struct if_clone *, int);
! 124: int tun_create(struct if_clone *, int, int);
! 125: int tun_clone_destroy(struct ifnet *);
! 126: struct tun_softc *tun_lookup(int);
! 127: void tun_wakeup(struct tun_softc *);
! 128: int tun_switch(struct tun_softc *, int);
! 129:
! 130: static int tuninit(struct tun_softc *);
! 131: static void tunstart(struct ifnet *);
! 132: int filt_tunread(struct knote *, long);
! 133: int filt_tunwrite(struct knote *, long);
! 134: void filt_tunrdetach(struct knote *);
! 135: void filt_tunwdetach(struct knote *);
! 136:
! 137: struct filterops tunread_filtops =
! 138: { 1, NULL, filt_tunrdetach, filt_tunread};
! 139:
! 140: struct filterops tunwrite_filtops =
! 141: { 1, NULL, filt_tunwdetach, filt_tunwrite};
! 142:
! 143: LIST_HEAD(, tun_softc) tun_softc_list;
! 144:
! 145: struct if_clone tun_cloner =
! 146: IF_CLONE_INITIALIZER("tun", tun_clone_create, tun_clone_destroy);
! 147:
! 148: void
! 149: tunattach(int n)
! 150: {
! 151: LIST_INIT(&tun_softc_list);
! 152: if_clone_attach(&tun_cloner);
! 153: }
! 154:
! 155: int
! 156: tun_clone_create(struct if_clone *ifc, int unit)
! 157: {
! 158: return (tun_create(ifc, unit, 0));
! 159: }
! 160:
! 161: int
! 162: tun_create(struct if_clone *ifc, int unit, int flags)
! 163: {
! 164: struct tun_softc *tp;
! 165: struct ifnet *ifp;
! 166: u_int32_t macaddr_rnd;
! 167: int s;
! 168:
! 169: tp = malloc(sizeof(*tp), M_DEVBUF, M_NOWAIT);
! 170: if (!tp)
! 171: return (ENOMEM);
! 172: bzero(tp, sizeof(*tp));
! 173:
! 174: tp->tun_unit = unit;
! 175: tp->tun_flags = TUN_INITED|TUN_STAYUP;
! 176:
! 177: /* generate fake MAC address: 00 bd xx xx xx unit_no */
! 178: tp->arpcom.ac_enaddr[0] = 0x00;
! 179: tp->arpcom.ac_enaddr[1] = 0xbd;
! 180: /*
! 181: * This no longer happens pre-scheduler so let's use the real
! 182: * random subsystem instead of random().
! 183: */
! 184: macaddr_rnd = arc4random();
! 185: bcopy(&macaddr_rnd, &tp->arpcom.ac_enaddr[2], sizeof(u_int32_t));
! 186: tp->arpcom.ac_enaddr[5] = (u_char)unit + 1;
! 187:
! 188: ifp = &tp->tun_if;
! 189: snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
! 190: unit);
! 191: ifp->if_softc = tp;
! 192: ifp->if_ioctl = tun_ioctl;
! 193: ifp->if_output = tun_output;
! 194: ifp->if_start = tunstart;
! 195: IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
! 196: IFQ_SET_READY(&ifp->if_snd);
! 197: if ((flags & TUN_LAYER2) == 0) {
! 198: tp->tun_flags &= ~TUN_LAYER2;
! 199: ifp->if_mtu = ETHERMTU;
! 200: ifp->if_flags = IFF_POINTOPOINT;
! 201: ifp->if_type = IFT_TUNNEL;
! 202: ifp->if_hdrlen = sizeof(u_int32_t);
! 203: if_attach(ifp);
! 204: if_alloc_sadl(ifp);
! 205: #if NBPFILTER > 0
! 206: bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
! 207: #endif
! 208: } else {
! 209: tp->tun_flags |= TUN_LAYER2;
! 210: ifp->if_flags =
! 211: (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST|IFF_LINK0);
! 212: if_attach(ifp);
! 213: ether_ifattach(ifp);
! 214: }
! 215: /* force output function to our function */
! 216: ifp->if_output = tun_output;
! 217:
! 218: s = splnet();
! 219: LIST_INSERT_HEAD(&tun_softc_list, tp, tun_list);
! 220: splx(s);
! 221:
! 222: return (0);
! 223: }
! 224:
! 225: int
! 226: tun_clone_destroy(struct ifnet *ifp)
! 227: {
! 228: struct tun_softc *tp = ifp->if_softc;
! 229: int s;
! 230:
! 231: tun_wakeup(tp);
! 232:
! 233: s = splhigh();
! 234: klist_invalidate(&tp->tun_rsel.si_note);
! 235: klist_invalidate(&tp->tun_wsel.si_note);
! 236: splx(s);
! 237:
! 238: s = splnet();
! 239: LIST_REMOVE(tp, tun_list);
! 240: splx(s);
! 241:
! 242: if (tp->tun_flags & TUN_LAYER2)
! 243: ether_ifdetach(ifp);
! 244:
! 245: if_detach(ifp);
! 246:
! 247: free(tp, M_DEVBUF);
! 248: return (0);
! 249: }
! 250:
! 251: struct tun_softc *
! 252: tun_lookup(int unit)
! 253: {
! 254: struct tun_softc *tp;
! 255:
! 256: LIST_FOREACH(tp, &tun_softc_list, tun_list)
! 257: if (tp->tun_unit == unit)
! 258: return (tp);
! 259: return (NULL);
! 260: }
! 261:
! 262: int
! 263: tun_switch(struct tun_softc *tp, int flags)
! 264: {
! 265: struct ifnet *ifp = &tp->tun_if;
! 266: int unit, open, r;
! 267:
! 268: if ((tp->tun_flags & TUN_LAYER2) == (flags & TUN_LAYER2))
! 269: return (0);
! 270:
! 271: /* tp will be removed so store unit number */
! 272: unit = tp->tun_unit;
! 273: open = tp->tun_flags & (TUN_OPEN|TUN_NBIO|TUN_ASYNC);
! 274: TUNDEBUG(("%s: switching to layer %d\n", ifp->if_xname,
! 275: flags & TUN_LAYER2 ? 2 : 3));
! 276:
! 277: /* remove old device and ... */
! 278: tun_clone_destroy(ifp);
! 279: /* attach new interface */
! 280: r = tun_create(&tun_cloner, unit, flags);
! 281:
! 282: if (open && r == 0) {
! 283: /* already opened before ifconfig tunX link0 */
! 284: if ((tp = tun_lookup(unit)) == NULL)
! 285: /* this should never fail */
! 286: return (ENXIO);
! 287: tp->tun_flags |= open;
! 288: TUNDEBUG(("%s: already open\n", tp->tun_if.if_xname));
! 289: }
! 290: return (r);
! 291: }
! 292:
! 293: /*
! 294: * tunnel open - must be superuser & the device must be
! 295: * configured in
! 296: */
! 297: int
! 298: tunopen(dev_t dev, int flag, int mode, struct proc *p)
! 299: {
! 300: struct tun_softc *tp;
! 301: struct ifnet *ifp;
! 302: int error, s;
! 303:
! 304: if ((error = suser(p, 0)) != 0)
! 305: return (error);
! 306:
! 307: if ((tp = tun_lookup(minor(dev))) == NULL) { /* create on demand */
! 308: char xname[IFNAMSIZ];
! 309:
! 310: snprintf(xname, sizeof(xname), "%s%d", "tun", minor(dev));
! 311: if ((error = if_clone_create(xname)) != 0)
! 312: return (error);
! 313:
! 314: if ((tp = tun_lookup(minor(dev))) == NULL)
! 315: return (ENXIO);
! 316: tp->tun_flags &= ~TUN_STAYUP;
! 317: }
! 318:
! 319: if (tp->tun_flags & TUN_OPEN)
! 320: return (EBUSY);
! 321:
! 322: ifp = &tp->tun_if;
! 323: tp->tun_flags |= TUN_OPEN;
! 324:
! 325: /* automatically UP the interface on open */
! 326: s = splnet();
! 327: if_up(ifp);
! 328: ifp->if_flags |= IFF_RUNNING;
! 329: splx(s);
! 330:
! 331: TUNDEBUG(("%s: open\n", ifp->if_xname));
! 332: return (0);
! 333: }
! 334:
! 335: /*
! 336: * tunclose - close the device; if closing the real device, flush pending
! 337: * output and unless STAYUP bring down and destroy the interface.
! 338: */
! 339: int
! 340: tunclose(dev_t dev, int flag, int mode, struct proc *p)
! 341: {
! 342: int s;
! 343: struct tun_softc *tp;
! 344: struct ifnet *ifp;
! 345:
! 346: if ((tp = tun_lookup(minor(dev))) == NULL)
! 347: return (ENXIO);
! 348:
! 349: ifp = &tp->tun_if;
! 350: tp->tun_flags &= ~(TUN_OPEN|TUN_NBIO|TUN_ASYNC);
! 351: ifp->if_flags &= ~IFF_RUNNING;
! 352:
! 353: /*
! 354: * junk all pending output
! 355: */
! 356: s = splnet();
! 357: IFQ_PURGE(&ifp->if_snd);
! 358: splx(s);
! 359:
! 360: TUNDEBUG(("%s: closed\n", ifp->if_xname));
! 361:
! 362: if (!(tp->tun_flags & TUN_STAYUP))
! 363: return (if_clone_destroy(ifp->if_xname));
! 364: else {
! 365: tp->tun_pgid = 0;
! 366: selwakeup(&tp->tun_rsel);
! 367: KNOTE(&tp->tun_rsel.si_note, 0);
! 368: }
! 369:
! 370: return (0);
! 371: }
! 372:
! 373: static int
! 374: tuninit(struct tun_softc *tp)
! 375: {
! 376: struct ifnet *ifp = &tp->tun_if;
! 377: struct ifaddr *ifa;
! 378:
! 379: TUNDEBUG(("%s: tuninit\n", ifp->if_xname));
! 380:
! 381: ifp->if_flags |= IFF_UP | IFF_RUNNING;
! 382: ifp->if_flags &= ~IFF_OACTIVE; /* we are never active */
! 383:
! 384: tp->tun_flags &= ~(TUN_IASET|TUN_DSTADDR|TUN_BRDADDR);
! 385: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
! 386: #ifdef INET
! 387: if (ifa->ifa_addr->sa_family == AF_INET) {
! 388: struct sockaddr_in *sin;
! 389:
! 390: sin = satosin(ifa->ifa_addr);
! 391: if (sin && sin->sin_addr.s_addr)
! 392: tp->tun_flags |= TUN_IASET;
! 393:
! 394: if (ifp->if_flags & IFF_POINTOPOINT) {
! 395: sin = satosin(ifa->ifa_dstaddr);
! 396: if (sin && sin->sin_addr.s_addr)
! 397: tp->tun_flags |= TUN_DSTADDR;
! 398: } else
! 399: tp->tun_flags &= ~TUN_DSTADDR;
! 400:
! 401: if (ifp->if_flags & IFF_BROADCAST) {
! 402: sin = satosin(ifa->ifa_broadaddr);
! 403: if (sin && sin->sin_addr.s_addr)
! 404: tp->tun_flags |= TUN_BRDADDR;
! 405: } else
! 406: tp->tun_flags &= ~TUN_BRDADDR;
! 407: }
! 408: #endif
! 409: #ifdef INET6
! 410: if (ifa->ifa_addr->sa_family == AF_INET6) {
! 411: struct sockaddr_in6 *sin;
! 412:
! 413: sin = (struct sockaddr_in6 *)ifa->ifa_addr;
! 414: if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
! 415: tp->tun_flags |= TUN_IASET;
! 416:
! 417: if (ifp->if_flags & IFF_POINTOPOINT) {
! 418: sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
! 419: if (sin &&
! 420: !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
! 421: tp->tun_flags |= TUN_DSTADDR;
! 422: } else
! 423: tp->tun_flags &= ~TUN_DSTADDR;
! 424: }
! 425: #endif /* INET6 */
! 426: }
! 427:
! 428: return (0);
! 429: }
! 430:
! 431: /*
! 432: * Process an ioctl request.
! 433: */
! 434: int
! 435: tun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
! 436: {
! 437: struct tun_softc *tp = (struct tun_softc *)(ifp->if_softc);
! 438: struct ifreq *ifr = (struct ifreq *)data;
! 439: int error = 0, s;
! 440:
! 441: s = splnet();
! 442: if (tp->tun_flags & TUN_LAYER2)
! 443: if ((error = ether_ioctl(ifp, &tp->arpcom, cmd, data)) > 0) {
! 444: splx(s);
! 445: return (error);
! 446: }
! 447: switch (cmd) {
! 448: case SIOCSIFADDR:
! 449: tuninit(tp);
! 450: TUNDEBUG(("%s: address set\n", ifp->if_xname));
! 451: if (tp->tun_flags & TUN_LAYER2)
! 452: switch (((struct ifaddr *)data)->ifa_addr->sa_family) {
! 453: #ifdef INET
! 454: case AF_INET:
! 455: arp_ifinit(&tp->arpcom, (struct ifaddr *)data);
! 456: break;
! 457: #endif
! 458: default:
! 459: break;
! 460: }
! 461: break;
! 462: case SIOCSIFDSTADDR:
! 463: tuninit(tp);
! 464: TUNDEBUG(("%s: destination address set\n", ifp->if_xname));
! 465: break;
! 466: case SIOCSIFBRDADDR:
! 467: tuninit(tp);
! 468: TUNDEBUG(("%s: broadcast address set\n", ifp->if_xname));
! 469: break;
! 470: case SIOCSIFMTU:
! 471: if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > TUNMRU)
! 472: error = EINVAL;
! 473: else
! 474: ifp->if_mtu = ifr->ifr_mtu;
! 475: break;
! 476: case SIOCADDMULTI:
! 477: case SIOCDELMULTI: {
! 478: if (ifr == 0) {
! 479: error = EAFNOSUPPORT; /* XXX */
! 480: break;
! 481: }
! 482:
! 483: if (tp->tun_flags & TUN_LAYER2) {
! 484: error = (cmd == SIOCADDMULTI) ?
! 485: ether_addmulti(ifr, &tp->arpcom) :
! 486: ether_delmulti(ifr, &tp->arpcom);
! 487: if (error == ENETRESET) {
! 488: /*
! 489: * Multicast list has changed; set the hardware
! 490: * filter accordingly. The good thing is we do
! 491: * not have a hardware filter (:
! 492: */
! 493: error = 0;
! 494: }
! 495: break;
! 496: }
! 497:
! 498: switch (ifr->ifr_addr.sa_family) {
! 499: #ifdef INET
! 500: case AF_INET:
! 501: break;
! 502: #endif
! 503: #ifdef INET6
! 504: case AF_INET6:
! 505: break;
! 506: #endif
! 507: default:
! 508: error = EAFNOSUPPORT;
! 509: break;
! 510: }
! 511: break;
! 512: }
! 513:
! 514: case SIOCSIFFLAGS:
! 515: error = tun_switch(tp,
! 516: ifp->if_flags & IFF_LINK0 ? TUN_LAYER2 : 0);
! 517: break;
! 518: default:
! 519: error = EINVAL;
! 520: }
! 521: splx(s);
! 522: return (error);
! 523: }
! 524:
! 525: /*
! 526: * tun_output - queue packets from higher level ready to put out.
! 527: */
! 528: int
! 529: tun_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
! 530: struct rtentry *rt)
! 531: {
! 532: struct tun_softc *tp = ifp->if_softc;
! 533: int s, len, error;
! 534: u_int32_t *af;
! 535:
! 536: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
! 537: m_freem(m0);
! 538: return (EHOSTDOWN);
! 539: }
! 540:
! 541: TUNDEBUG(("%s: tun_output\n", ifp->if_xname));
! 542:
! 543: if ((tp->tun_flags & TUN_READY) != TUN_READY) {
! 544: TUNDEBUG(("%s: not ready %#x\n", ifp->if_xname,
! 545: tp->tun_flags));
! 546: m_freem(m0);
! 547: return (EHOSTDOWN);
! 548: }
! 549:
! 550: if (tp->tun_flags & TUN_LAYER2)
! 551: /* call ether_output and that will call tunstart at the end */
! 552: return (ether_output(ifp, m0, dst, rt));
! 553:
! 554: M_PREPEND(m0, sizeof(*af), M_DONTWAIT);
! 555: af = mtod(m0, u_int32_t *);
! 556: *af = htonl(dst->sa_family);
! 557:
! 558: #if NBPFILTER > 0
! 559: if (ifp->if_bpf)
! 560: bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
! 561: #endif
! 562:
! 563: len = m0->m_pkthdr.len + sizeof(*af);
! 564: s = splnet();
! 565: IFQ_ENQUEUE(&ifp->if_snd, m0, NULL, error);
! 566: if (error) {
! 567: splx(s);
! 568: ifp->if_collisions++;
! 569: return (error);
! 570: }
! 571: splx(s);
! 572: ifp->if_opackets++;
! 573: ifp->if_obytes += len;
! 574:
! 575: tun_wakeup(tp);
! 576: return (0);
! 577: }
! 578:
! 579: void
! 580: tun_wakeup(struct tun_softc *tp)
! 581: {
! 582: if (tp->tun_flags & TUN_RWAIT) {
! 583: tp->tun_flags &= ~TUN_RWAIT;
! 584: wakeup((caddr_t)tp);
! 585: }
! 586: if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
! 587: csignal(tp->tun_pgid, SIGIO,
! 588: tp->tun_siguid, tp->tun_sigeuid);
! 589: selwakeup(&tp->tun_rsel);
! 590: KNOTE(&tp->tun_rsel.si_note, 0);
! 591: }
! 592:
! 593: /*
! 594: * the cdevsw interface is now pretty minimal.
! 595: */
! 596: int
! 597: tunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 598: {
! 599: int s;
! 600: struct tun_softc *tp;
! 601: struct tuninfo *tunp;
! 602: struct mbuf *m;
! 603:
! 604: if ((tp = tun_lookup(minor(dev))) == NULL)
! 605: return (ENXIO);
! 606:
! 607: s = splnet();
! 608: switch (cmd) {
! 609: case TUNSIFINFO:
! 610: tunp = (struct tuninfo *)data;
! 611: if (tunp->mtu < ETHERMIN || tunp->mtu > TUNMRU) {
! 612: splx(s);
! 613: return (EINVAL);
! 614: }
! 615: tp->tun_if.if_mtu = tunp->mtu;
! 616: tp->tun_if.if_type = tunp->type;
! 617: tp->tun_if.if_flags =
! 618: (tunp->flags & TUN_IFF_FLAGS) |
! 619: (tp->tun_if.if_flags & ~TUN_IFF_FLAGS);
! 620: tp->tun_if.if_baudrate = tunp->baudrate;
! 621: break;
! 622: case TUNGIFINFO:
! 623: tunp = (struct tuninfo *)data;
! 624: tunp->mtu = tp->tun_if.if_mtu;
! 625: tunp->type = tp->tun_if.if_type;
! 626: tunp->flags = tp->tun_if.if_flags;
! 627: tunp->baudrate = tp->tun_if.if_baudrate;
! 628: break;
! 629: #ifdef TUN_DEBUG
! 630: case TUNSDEBUG:
! 631: tundebug = *(int *)data;
! 632: break;
! 633: case TUNGDEBUG:
! 634: *(int *)data = tundebug;
! 635: break;
! 636: #endif
! 637: case TUNSIFMODE:
! 638: switch (*(int *)data & (IFF_POINTOPOINT|IFF_BROADCAST)) {
! 639: case IFF_POINTOPOINT:
! 640: case IFF_BROADCAST:
! 641: tp->tun_if.if_flags &= ~TUN_IFF_FLAGS;
! 642: tp->tun_if.if_flags |= *(int *)data & TUN_IFF_FLAGS;
! 643: break;
! 644: default:
! 645: splx(s);
! 646: return (EINVAL);
! 647: }
! 648: break;
! 649:
! 650: case FIONBIO:
! 651: if (*(int *)data)
! 652: tp->tun_flags |= TUN_NBIO;
! 653: else
! 654: tp->tun_flags &= ~TUN_NBIO;
! 655: break;
! 656: case FIOASYNC:
! 657: if (*(int *)data)
! 658: tp->tun_flags |= TUN_ASYNC;
! 659: else
! 660: tp->tun_flags &= ~TUN_ASYNC;
! 661: break;
! 662: case FIONREAD:
! 663: IFQ_POLL(&tp->tun_if.if_snd, m);
! 664: if (m != NULL)
! 665: *(int *)data = m->m_pkthdr.len;
! 666: else
! 667: *(int *)data = 0;
! 668: break;
! 669: case TIOCSPGRP:
! 670: tp->tun_pgid = *(int *)data;
! 671: tp->tun_siguid = p->p_cred->p_ruid;
! 672: tp->tun_sigeuid = p->p_ucred->cr_uid;
! 673: break;
! 674: case TIOCGPGRP:
! 675: *(int *)data = tp->tun_pgid;
! 676: break;
! 677: case OSIOCGIFADDR:
! 678: case SIOCGIFADDR:
! 679: if (!(tp->tun_flags & TUN_LAYER2)) {
! 680: splx(s);
! 681: return (EINVAL);
! 682: }
! 683: bcopy(tp->arpcom.ac_enaddr, data,
! 684: sizeof(tp->arpcom.ac_enaddr));
! 685: break;
! 686:
! 687: case SIOCSIFADDR:
! 688: if (!(tp->tun_flags & TUN_LAYER2)) {
! 689: splx(s);
! 690: return (EINVAL);
! 691: }
! 692: bcopy(data, tp->arpcom.ac_enaddr,
! 693: sizeof(tp->arpcom.ac_enaddr));
! 694: break;
! 695: default:
! 696: splx(s);
! 697: return (ENOTTY);
! 698: }
! 699: splx(s);
! 700: return (0);
! 701: }
! 702:
! 703: /*
! 704: * The cdevsw read interface - reads a packet at a time, or at
! 705: * least as much of a packet as can be read.
! 706: */
! 707: int
! 708: tunread(dev_t dev, struct uio *uio, int ioflag)
! 709: {
! 710: struct tun_softc *tp;
! 711: struct ifnet *ifp;
! 712: struct mbuf *m, *m0;
! 713: int error = 0, len, s;
! 714:
! 715: if ((tp = tun_lookup(minor(dev))) == NULL)
! 716: return (ENXIO);
! 717:
! 718: ifp = &tp->tun_if;
! 719: TUNDEBUG(("%s: read\n", ifp->if_xname));
! 720: if ((tp->tun_flags & TUN_READY) != TUN_READY) {
! 721: TUNDEBUG(("%s: not ready %#x\n", ifp->if_xname, tp->tun_flags));
! 722: return (EHOSTDOWN);
! 723: }
! 724:
! 725: tp->tun_flags &= ~TUN_RWAIT;
! 726:
! 727: s = splnet();
! 728: do {
! 729: while ((tp->tun_flags & TUN_READY) != TUN_READY)
! 730: if ((error = tsleep((caddr_t)tp,
! 731: (PZERO + 1)|PCATCH, "tunread", 0)) != 0) {
! 732: splx(s);
! 733: return (error);
! 734: }
! 735: IFQ_DEQUEUE(&ifp->if_snd, m0);
! 736: if (m0 == NULL) {
! 737: if (tp->tun_flags & TUN_NBIO && ioflag & IO_NDELAY) {
! 738: splx(s);
! 739: return (EWOULDBLOCK);
! 740: }
! 741: tp->tun_flags |= TUN_RWAIT;
! 742: if ((error = tsleep((caddr_t)tp,
! 743: (PZERO + 1)|PCATCH, "tunread", 0)) != 0) {
! 744: splx(s);
! 745: return (error);
! 746: }
! 747: }
! 748: } while (m0 == NULL);
! 749: splx(s);
! 750:
! 751: while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
! 752: len = min(uio->uio_resid, m0->m_len);
! 753: if (len != 0)
! 754: error = uiomove(mtod(m0, caddr_t), len, uio);
! 755: MFREE(m0, m);
! 756: m0 = m;
! 757: }
! 758:
! 759: if (m0 != NULL) {
! 760: TUNDEBUG(("Dropping mbuf\n"));
! 761: m_freem(m0);
! 762: }
! 763: if (error)
! 764: ifp->if_ierrors++;
! 765:
! 766: return (error);
! 767: }
! 768:
! 769: /*
! 770: * the cdevsw write interface - an atomic write is a packet - or else!
! 771: */
! 772: int
! 773: tunwrite(dev_t dev, struct uio *uio, int ioflag)
! 774: {
! 775: struct tun_softc *tp;
! 776: struct ifnet *ifp;
! 777: struct ifqueue *ifq;
! 778: u_int32_t *th;
! 779: struct mbuf *top, **mp, *m;
! 780: int isr;
! 781: int error=0, s, tlen, mlen;
! 782:
! 783: if ((tp = tun_lookup(minor(dev))) == NULL)
! 784: return (ENXIO);
! 785:
! 786: ifp = &tp->tun_if;
! 787: TUNDEBUG(("%s: tunwrite\n", ifp->if_xname));
! 788:
! 789: if (uio->uio_resid == 0 || uio->uio_resid > ifp->if_mtu +
! 790: (tp->tun_flags & TUN_LAYER2 ? ETHER_HDR_LEN : sizeof(*th))) {
! 791: TUNDEBUG(("%s: len=%d!\n", ifp->if_xname, uio->uio_resid));
! 792: return (EMSGSIZE);
! 793: }
! 794: tlen = uio->uio_resid;
! 795:
! 796: /* get a header mbuf */
! 797: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 798: if (m == NULL)
! 799: return (ENOBUFS);
! 800: mlen = MHLEN;
! 801: if (uio->uio_resid >= MINCLSIZE) {
! 802: MCLGET(m, M_DONTWAIT);
! 803: if (!(m->m_flags & M_EXT)) {
! 804: m_free(m);
! 805: return (ENOBUFS);
! 806: }
! 807: mlen = MCLBYTES;
! 808: }
! 809:
! 810: top = NULL;
! 811: mp = ⊤
! 812: if (tp->tun_flags & TUN_LAYER2) {
! 813: /*
! 814: * Pad so that IP header is correctly aligned
! 815: * this is necessary for all strict aligned architectures.
! 816: */
! 817: mlen -= ETHER_ALIGN;
! 818: m->m_data += ETHER_ALIGN;
! 819: }
! 820: while (error == 0 && uio->uio_resid > 0) {
! 821: m->m_len = min(mlen, uio->uio_resid);
! 822: error = uiomove(mtod (m, caddr_t), m->m_len, uio);
! 823: *mp = m;
! 824: mp = &m->m_next;
! 825: if (error == 0 && uio->uio_resid > 0) {
! 826: MGET(m, M_DONTWAIT, MT_DATA);
! 827: if (m == NULL) {
! 828: error = ENOBUFS;
! 829: break;
! 830: }
! 831: mlen = MLEN;
! 832: if (uio->uio_resid >= MINCLSIZE) {
! 833: MCLGET(m, M_DONTWAIT);
! 834: if (!(m->m_flags & M_EXT)) {
! 835: error = ENOBUFS;
! 836: m_free(m);
! 837: break;
! 838: }
! 839: mlen = MCLBYTES;
! 840: }
! 841: }
! 842: }
! 843: if (error) {
! 844: if (top != NULL)
! 845: m_freem(top);
! 846: ifp->if_ierrors++;
! 847: return (error);
! 848: }
! 849:
! 850: top->m_pkthdr.len = tlen;
! 851: top->m_pkthdr.rcvif = ifp;
! 852:
! 853: #if NBPFILTER > 0
! 854: if (ifp->if_bpf)
! 855: bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_IN);
! 856: #endif
! 857:
! 858: if (tp->tun_flags & TUN_LAYER2) {
! 859: ether_input_mbuf(ifp, top);
! 860: ifp->if_ipackets++; /* ibytes are counted in ether_input */
! 861: return (0);
! 862: }
! 863:
! 864: th = mtod(top, u_int32_t *);
! 865: /* strip the tunnel header */
! 866: top->m_data += sizeof(*th);
! 867: top->m_len -= sizeof(*th);
! 868: top->m_pkthdr.len -= sizeof(*th);
! 869:
! 870: switch (ntohl(*th)) {
! 871: #ifdef INET
! 872: case AF_INET:
! 873: ifq = &ipintrq;
! 874: isr = NETISR_IP;
! 875: break;
! 876: #endif
! 877: #ifdef INET6
! 878: case AF_INET6:
! 879: ifq = &ip6intrq;
! 880: isr = NETISR_IPV6;
! 881: break;
! 882: #endif
! 883: #ifdef NETATALK
! 884: case AF_APPLETALK:
! 885: ifq = &atintrq2;
! 886: isr = NETISR_ATALK;
! 887: break;
! 888: #endif
! 889: default:
! 890: m_freem(top);
! 891: return (EAFNOSUPPORT);
! 892: }
! 893:
! 894: s = splnet();
! 895: if (IF_QFULL(ifq)) {
! 896: IF_DROP(ifq);
! 897: splx(s);
! 898: ifp->if_collisions++;
! 899: m_freem(top);
! 900: if (!ifq->ifq_congestion)
! 901: if_congestion(ifq);
! 902: return (ENOBUFS);
! 903: }
! 904: IF_ENQUEUE(ifq, top);
! 905: schednetisr(isr);
! 906: ifp->if_ipackets++;
! 907: ifp->if_ibytes += top->m_pkthdr.len;
! 908: splx(s);
! 909: return (error);
! 910: }
! 911:
! 912: /*
! 913: * tunpoll - the poll interface, this is only useful on reads
! 914: * really. The write detect always returns true, write never blocks
! 915: * anyway, it either accepts the packet or drops it.
! 916: */
! 917: int
! 918: tunpoll(dev_t dev, int events, struct proc *p)
! 919: {
! 920: int revents, s;
! 921: struct tun_softc *tp;
! 922: struct ifnet *ifp;
! 923: struct mbuf *m;
! 924:
! 925: if ((tp = tun_lookup(minor(dev))) == NULL)
! 926: return (POLLERR);
! 927:
! 928: ifp = &tp->tun_if;
! 929: revents = 0;
! 930: s = splnet();
! 931: TUNDEBUG(("%s: tunpoll\n", ifp->if_xname));
! 932:
! 933: if (events & (POLLIN | POLLRDNORM)) {
! 934: IFQ_POLL(&ifp->if_snd, m);
! 935: if (m != NULL) {
! 936: TUNDEBUG(("%s: tunselect q=%d\n", ifp->if_xname,
! 937: ifp->if_snd.ifq_len));
! 938: revents |= events & (POLLIN | POLLRDNORM);
! 939: } else {
! 940: TUNDEBUG(("%s: tunpoll waiting\n", ifp->if_xname));
! 941: selrecord(p, &tp->tun_rsel);
! 942: }
! 943: }
! 944: if (events & (POLLOUT | POLLWRNORM))
! 945: revents |= events & (POLLOUT | POLLWRNORM);
! 946: splx(s);
! 947: return (revents);
! 948: }
! 949:
! 950: /*
! 951: * kqueue(2) support.
! 952: *
! 953: * The tun driver uses an array of tun_softc's based on the minor number
! 954: * of the device. kn->kn_hook gets set to the specific tun_softc.
! 955: *
! 956: * filt_tunread() sets kn->kn_data to the iface qsize
! 957: * filt_tunwrite() sets kn->kn_data to the MTU size
! 958: */
! 959: int
! 960: tunkqfilter(dev_t dev, struct knote *kn)
! 961: {
! 962: int s;
! 963: struct klist *klist;
! 964: struct tun_softc *tp;
! 965: struct ifnet *ifp;
! 966:
! 967: if ((tp = tun_lookup(minor(dev))) == NULL)
! 968: return (ENXIO);
! 969:
! 970: ifp = &tp->tun_if;
! 971:
! 972: s = splnet();
! 973: TUNDEBUG(("%s: tunkqfilter\n", ifp->if_xname));
! 974: splx(s);
! 975:
! 976: switch (kn->kn_filter) {
! 977: case EVFILT_READ:
! 978: klist = &tp->tun_rsel.si_note;
! 979: kn->kn_fop = &tunread_filtops;
! 980: break;
! 981: case EVFILT_WRITE:
! 982: klist = &tp->tun_wsel.si_note;
! 983: kn->kn_fop = &tunwrite_filtops;
! 984: break;
! 985: default:
! 986: return (EPERM); /* 1 */
! 987: }
! 988:
! 989: kn->kn_hook = (caddr_t)tp;
! 990:
! 991: s = splhigh();
! 992: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
! 993: splx(s);
! 994:
! 995: return (0);
! 996: }
! 997:
! 998: void
! 999: filt_tunrdetach(struct knote *kn)
! 1000: {
! 1001: int s;
! 1002: struct tun_softc *tp;
! 1003:
! 1004: tp = (struct tun_softc *)kn->kn_hook;
! 1005: s = splhigh();
! 1006: if (!(kn->kn_status & KN_DETACHED))
! 1007: SLIST_REMOVE(&tp->tun_rsel.si_note, kn, knote, kn_selnext);
! 1008: splx(s);
! 1009: }
! 1010:
! 1011: int
! 1012: filt_tunread(struct knote *kn, long hint)
! 1013: {
! 1014: int s;
! 1015: struct tun_softc *tp;
! 1016: struct ifnet *ifp;
! 1017: struct mbuf *m;
! 1018:
! 1019: if (kn->kn_status & KN_DETACHED) {
! 1020: kn->kn_data = 0;
! 1021: return (1);
! 1022: }
! 1023:
! 1024: tp = (struct tun_softc *)kn->kn_hook;
! 1025: ifp = &tp->tun_if;
! 1026:
! 1027: s = splnet();
! 1028: IFQ_POLL(&ifp->if_snd, m);
! 1029: if (m != NULL) {
! 1030: splx(s);
! 1031: kn->kn_data = ifp->if_snd.ifq_len;
! 1032:
! 1033: TUNDEBUG(("%s: tunkqread q=%d\n", ifp->if_xname,
! 1034: ifp->if_snd.ifq_len));
! 1035: return (1);
! 1036: }
! 1037: splx(s);
! 1038: TUNDEBUG(("%s: tunkqread waiting\n", ifp->if_xname));
! 1039: return (0);
! 1040: }
! 1041:
! 1042: void
! 1043: filt_tunwdetach(struct knote *kn)
! 1044: {
! 1045: int s;
! 1046: struct tun_softc *tp;
! 1047:
! 1048: tp = (struct tun_softc *)kn->kn_hook;
! 1049: s = splhigh();
! 1050: if (!(kn->kn_status & KN_DETACHED))
! 1051: SLIST_REMOVE(&tp->tun_wsel.si_note, kn, knote, kn_selnext);
! 1052: splx(s);
! 1053: }
! 1054:
! 1055: int
! 1056: filt_tunwrite(struct knote *kn, long hint)
! 1057: {
! 1058: struct tun_softc *tp;
! 1059: struct ifnet *ifp;
! 1060:
! 1061: if (kn->kn_status & KN_DETACHED) {
! 1062: kn->kn_data = 0;
! 1063: return (1);
! 1064: }
! 1065:
! 1066: tp = (struct tun_softc *)kn->kn_hook;
! 1067: ifp = &tp->tun_if;
! 1068:
! 1069: kn->kn_data = ifp->if_mtu;
! 1070:
! 1071: return (1);
! 1072: }
! 1073:
! 1074: /*
! 1075: * Start packet transmission on the interface.
! 1076: * when the interface queue is rate-limited by ALTQ or TBR,
! 1077: * if_start is needed to drain packets from the queue in order
! 1078: * to notify readers when outgoing packets become ready.
! 1079: * In layer 2 mode this function is called from ether_output.
! 1080: */
! 1081: static void
! 1082: tunstart(struct ifnet *ifp)
! 1083: {
! 1084: struct tun_softc *tp = ifp->if_softc;
! 1085: struct mbuf *m;
! 1086:
! 1087: if (!(tp->tun_flags & TUN_LAYER2) &&
! 1088: !ALTQ_IS_ENABLED(&ifp->if_snd) &&
! 1089: !TBR_IS_ENABLED(&ifp->if_snd))
! 1090: return;
! 1091:
! 1092: IFQ_POLL(&ifp->if_snd, m);
! 1093: if (m != NULL) {
! 1094: if (tp->tun_flags & TUN_LAYER2) {
! 1095: #if NBPFILTER > 0
! 1096: if (ifp->if_bpf)
! 1097: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
! 1098: #endif
! 1099: ifp->if_opackets++;
! 1100: }
! 1101: tun_wakeup(tp);
! 1102: }
! 1103: }
CVSweb