|
|
1.1 ! root 1: /* UNFINISHED CONVERSION TO 386BSD -wfj */ ! 2: ! 3: /* if_tun.c - tunnel interface module & driver */ ! 4: ! 5: /* ! 6: * Copyright (c) 1988, Julian Onions. ! 7: * ! 8: * This source may be freely distributed, however I would be interested ! 9: * in any changes that are made. ! 10: */ ! 11: ! 12: /* ! 13: * 90/02/06 15:03 - Fixed a bug in where TIOCGPGRP and TIOCSPGRP were ! 14: * mixed up. Anders Klemets - [email protected] ! 15: * ! 16: * $Header: if_tun.c,v 1.13 88/07/11 08:28:51 jpo Exp $ ! 17: * ! 18: * $Log: if_tun.c,v $ ! 19: * Revision 1.13 88/07/11 08:28:51 jpo ! 20: * Some tidying up ! 21: * ! 22: * Revision 1.12 87/12/10 09:16:29 jpo ! 23: * Decided the vax/mtpr was unnecessay. ! 24: * ! 25: * Revision 1.11 87/12/10 09:10:36 jpo ! 26: * Fixed some minor things & 1 major bug. ! 27: * ! 28: * Revision 1.10 87/11/04 14:27:41 jpo ! 29: * A few sanity checks added. ! 30: * ! 31: * Revision 1.9 87/11/04 14:13:45 jpo ! 32: * Added some ioctls for non-blocking & async I/O ! 33: * ! 34: * Revision 1.8 87/10/19 10:28:14 jpo ! 35: * Another touch up (sigh) ! 36: * ! 37: * Revision 1.7 87/10/19 10:25:48 jpo ! 38: * Touch up. ! 39: * ! 40: * Revision 1.6 87/10/19 09:15:14 jpo ! 41: * Touch up. ! 42: * ! 43: * Revision 1.5 87/10/19 08:34:51 jpo ! 44: * General clean up - plus sun specific fixes ! 45: * ! 46: * Revision 1.4 87/10/16 17:10:12 jpo ! 47: * Purged all ioctl read/writes and non-standard routing stuff. ! 48: * ! 49: * Revision 1.3 87/10/05 11:57:09 jpo ! 50: * More debugging - in error mainly. ! 51: * ! 52: * Revision 1.2 87/10/04 18:29:45 jpo ! 53: * Select & read/write working. ! 54: */ ! 55: ! 56: #include "tun.h" ! 57: #if NTUN > 0 ! 58: ! 59: /* ! 60: * Tunnel driver. ! 61: * ! 62: * This driver takes packets off the IP i/f and hands them up to a ! 63: * user process to have it's wicked way with. This driver has it's ! 64: * roots in a similar driver written by Phil Cockcroft (formerly) at ! 65: * UCL. This driver is based much more on read/write/select mode of ! 66: * operation though. ! 67: * ! 68: * Julian Onions <[email protected]> ! 69: * Nottingham University 1987. ! 70: */ ! 71: ! 72: #include "param.h" ! 73: #include "systm.h" ! 74: #include "mbuf.h" ! 75: #include "buf.h" ! 76: #include "protosw.h" ! 77: #include "socket.h" ! 78: #include "ioctl.h" ! 79: #include "errno.h" ! 80: #include "syslog.h" ! 81: ! 82: #include "net/if.h" ! 83: #include "net/netisr.h" ! 84: #include "net/route.h" ! 85: ! 86: #ifdef INET ! 87: #include "netinet/in.h" ! 88: #include "netinet/in_systm.h" ! 89: #include "netinet/in_var.h" ! 90: #include "netinet/ip.h" ! 91: #include "netinet/if_ether.h" ! 92: #endif ! 93: ! 94: #ifdef NS ! 95: #include "netns/ns.h" ! 96: #include "netns/ns_if.h" ! 97: #endif ! 98: ! 99: #define TUNDEBUG if (tundebug) printf ! 100: ! 101: int tundebug = 0; ! 102: struct tunctl ! 103: { ! 104: u_short tun_flags; /* misc flags */ ! 105: struct ifnet tun_if; /* the interface */ ! 106: int tun_pgrp; /* the process group - if any */ ! 107: struct proc *tun_rsel; /* read select */ ! 108: struct proc *tun_wsel; /* write select (not used) */ ! 109: } tunctl[NTUN]; ! 110: ! 111: extern int ifqmaxlen; ! 112: ! 113: int tunoutput (), tunioctl (), tuninit (); ! 114: ! 115: /* tunnel open - must be superuser & the device must be configured in */ ! 116: tunopen (dev, flag) ! 117: dev_t dev; ! 118: { ! 119: register int unit; ! 120: struct tunctl *tp; ! 121: register struct ifnet *ifp; ! 122: ! 123: if (!suser ()) ! 124: return EACCES; ! 125: if ((unit = minor (dev)) >= NTUN) ! 126: return (ENXIO); ! 127: tp = &tunctl[unit]; ! 128: if (tp->tun_flags & TUN_OPEN) ! 129: return ENXIO; ! 130: if ((tp->tun_flags & TUN_INITED) == 0) { ! 131: tp->tun_flags = TUN_INITED; ! 132: tunattach (unit); ! 133: } ! 134: ifp = &tp->tun_if; ! 135: tp->tun_flags |= TUN_OPEN; ! 136: TUNDEBUG ("%s%d: open\n", ifp->if_name, ifp->if_unit); ! 137: return (0); ! 138: } ! 139: ! 140: /* tunclose - close the device - mark i/f down & delete routing info */ ! 141: tunclose (dev, flag) ! 142: dev_t dev; ! 143: { ! 144: int s; ! 145: int rcoll; ! 146: register int unit = minor (dev); ! 147: register struct tunctl *tp = &tunctl[unit]; ! 148: register struct ifnet *ifp = &tp->tun_if; ! 149: register struct mbuf *m; ! 150: ! 151: rcoll = tp->tun_flags & TUN_RCOLL; ! 152: tp->tun_flags &= TUN_INITED; ! 153: ! 154: /* ! 155: * junk all pending output ! 156: */ ! 157: do { ! 158: s = splimp (); ! 159: IF_DEQUEUE (&ifp->if_snd, m); ! 160: splx (s); ! 161: if (m) /* actually - m_freem checks this - but what the hell */ ! 162: m_freem (m); ! 163: } while (m != 0); ! 164: if (ifp->if_flags & IFF_UP) { ! 165: s = splimp (); ! 166: if_down (ifp); ! 167: if (ifp->if_flags & IFF_RUNNING) ! 168: rtinit (ifp->if_addrlist, (int)SIOCDELRT, RTF_HOST); ! 169: splx (s); ! 170: } ! 171: tp -> tun_pgrp = 0; ! 172: if (tp -> tun_rsel) ! 173: selwakeup (tp->tun_rsel, rcoll); ! 174: ! 175: tp -> tun_rsel = tp -> tun_wsel = (struct proc *)0; ! 176: ! 177: TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit); ! 178: return (0); ! 179: } ! 180: ! 181: /* ! 182: * attach an interface N.B. argument is not same as other drivers ! 183: */ ! 184: int ! 185: tunattach (unit) ! 186: int unit; ! 187: { ! 188: register struct ifnet *ifp = &tunctl[unit].tun_if; ! 189: register struct sockaddr_in *sin; ! 190: ! 191: ifp->if_unit = unit; ! 192: ifp->if_name = "tun"; ! 193: ifp->if_mtu = TUNMTU; ! 194: ifp->if_ioctl = tunioctl; ! 195: ifp->if_output = tunoutput; ! 196: ifp->if_init = tuninit; ! 197: #ifndef BSD4_3 ! 198: sin = (struct sockaddr_in *) & ifp->if_addr; ! 199: sin->sin_family = AF_INET; ! 200: #endif ! 201: ifp->if_flags = IFF_POINTOPOINT; ! 202: ifp->if_snd.ifq_maxlen = ifqmaxlen; ! 203: ifp->if_collisions = ifp->if_ierrors = ifp->if_oerrors = 0; ! 204: ifp->if_ipackets = ifp->if_opackets = 0; ! 205: if_attach (ifp); ! 206: TUNDEBUG ("%s%d: tunattach\n", ifp->if_name, ifp->if_unit); ! 207: return 0; ! 208: } ! 209: ! 210: int ! 211: tuninit (unit) ! 212: int unit; ! 213: { ! 214: register struct tunctl *tp = &tunctl[unit]; ! 215: register struct ifnet *ifp = &tp->tun_if; ! 216: #ifndef BSD4_3 ! 217: register struct sockaddr_in *sin; ! 218: ! 219: sin = (struct sockaddr_in *) & ifp->if_addr; ! 220: if (sin->sin_addr.s_addr == 0) /* if address still unknown */ ! 221: return; ! 222: if_rtinit (ifp, RTF_UP); ! 223: #endif ! 224: ifp->if_flags |= IFF_UP | IFF_RUNNING; ! 225: tp->tun_flags |= TUN_IASET; ! 226: TUNDEBUG ("%s%d: tuninit\n", ifp->if_name, ifp->if_unit); ! 227: return 0; ! 228: } ! 229: ! 230: /* ! 231: * Process an ioctl request. ! 232: * The problem here is 4.2 pass a struct ifreq * to this routine, ! 233: * sun only passes a struct sockaddr * since 3.2 at least. This is ! 234: * rather upsetting! Also, sun doesn't pass the SIOCDSTADDR ioctl through ! 235: * so we can't detect this being set directly. This is the reason for ! 236: * tuncheckready. ! 237: * Under 4.3 and SunOs 4.0 we now get the SIOCSIFDSTADDR ioctl, and we get a ! 238: * struct in_ifaddr * for data. (tte) ! 239: */ ! 240: ! 241: #if !defined(BSD4_3) && defined(sun) ! 242: ! 243: /* ! 244: * workaround for not being able to detect DSTADDR being set. ! 245: */ ! 246: ! 247: tuncheckready (ifp) ! 248: struct ifnet *ifp; ! 249: { ! 250: struct tunctl *tp = &tunctl[ifp->if_unit]; ! 251: struct sockaddr_in *sin; ! 252: ! 253: sin = (struct sockaddr_in *) &ifp->if_dstaddr; ! 254: if (sin->sin_addr.s_addr == 0) ! 255: return 0; ! 256: tp -> tun_flags |= TUN_DSTADDR; ! 257: return 1; ! 258: } ! 259: #else ! 260: #define tuncheckready(dummy) 1 ! 261: #endif /* !defined(BSD4_3) && defined(sun) */ ! 262: ! 263: int ! 264: tunioctl (ifp, cmd, data) ! 265: register struct ifnet *ifp; ! 266: int cmd; ! 267: caddr_t data; ! 268: { ! 269: #ifndef BSD4_3 ! 270: #ifdef sun ! 271: struct sockaddr_in *sin = (struct sockaddr_in *) data; ! 272: #else ! 273: struct sockaddr_in *sin; ! 274: struct ifreq *ifr = (struct ifreq *) data; ! 275: #endif ! 276: #endif /* BSD4_3 */ ! 277: ! 278: int s = splimp (), error = 0; ! 279: struct tunctl *tp = &tunctl[ifp->if_unit]; ! 280: ! 281: switch (cmd) ! 282: { ! 283: case SIOCSIFADDR: ! 284: #ifndef BSD4_3 ! 285: if (ifp->if_flags & IFF_RUNNING) ! 286: if_rtinit (ifp, -1); /* delete previous route */ ! 287: #ifndef sun ! 288: sin = (struct sockaddr_in *)&ifr -> ifr_addr; ! 289: #endif ! 290: ifp->if_addr = *((struct sockaddr *) sin); ! 291: ifp->if_net = in_netof (sin->sin_addr); ! 292: ifp->if_host[0] = in_lnaof (sin->sin_addr); ! 293: #endif ! 294: tuninit (ifp->if_unit); ! 295: break; ! 296: case SIOCSIFDSTADDR: ! 297: tp->tun_flags |= TUN_DSTADDR; ! 298: #ifndef BSD4_3 ! 299: #ifndef sun ! 300: sin = (struct sockaddr_in *)&ifr -> ifr_addr; ! 301: #endif ! 302: ifp->if_dstaddr = *((struct sockaddr *)sin); ! 303: #endif BSD4_3 ! 304: TUNDEBUG ("%s%d: destination addres set\n", ifp->if_name, ! 305: ifp -> if_unit); ! 306: break; ! 307: default: ! 308: error = EINVAL; ! 309: } ! 310: splx (s); ! 311: return (error); ! 312: } ! 313: ! 314: /* ! 315: * tunoutput - queue packets from higher level ready to put out. ! 316: */ ! 317: tunoutput (ifp, m0, dst) ! 318: struct ifnet *ifp; ! 319: struct mbuf *m0; ! 320: struct sockaddr *dst; ! 321: { ! 322: struct tunctl *tp; ! 323: struct proc *p; ! 324: int s; ! 325: ! 326: TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit); ! 327: tp = &tunctl[ifp->if_unit]; ! 328: if ((tp->tun_flags & TUN_READY) != TUN_READY) { ! 329: if(tuncheckready(ifp) == 0) { ! 330: TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, ! 331: ifp->if_unit, tp->tun_flags); ! 332: m_freem (m0); ! 333: return EHOSTDOWN; ! 334: } ! 335: } ! 336: ! 337: switch (dst->sa_family) { ! 338: #ifdef INET ! 339: case AF_INET: ! 340: s = splimp (); ! 341: if (IF_QFULL (&ifp->if_snd)) ! 342: { ! 343: IF_DROP (&ifp->if_snd); ! 344: m_freem (m0); ! 345: splx (s); ! 346: ifp->if_collisions++; ! 347: return (ENOBUFS); ! 348: } ! 349: IF_ENQUEUE (&ifp->if_snd, m0); ! 350: splx (s); ! 351: ifp->if_opackets++; ! 352: break; ! 353: #endif ! 354: default: ! 355: m_freem (m0); ! 356: return EAFNOSUPPORT; ! 357: } ! 358: ! 359: if (tp->tun_flags & TUN_RWAIT) { ! 360: tp->tun_flags &= ~TUN_RWAIT; ! 361: wakeup ((caddr_t) tp); ! 362: } ! 363: if (tp->tun_flags & TUN_ASYNC && tp -> tun_pgrp != 0) { ! 364: if (tp->tun_pgrp > 0) ! 365: gsignal (tp->tun_pgrp, SIGIO); ! 366: else if ((p = pfind (-tp->tun_pgrp)) != 0) ! 367: psignal (p, SIGIO); ! 368: } ! 369: if (tp->tun_rsel) { ! 370: selwakeup (tp->tun_rsel, tp->tun_flags & TUN_RCOLL); ! 371: tp->tun_flags &= ~TUN_RCOLL; ! 372: tp->tun_rsel = (struct proc *) 0; ! 373: } ! 374: return 0; ! 375: } ! 376: ! 377: /* ! 378: * the cdevsw interface is now pretty minimal. ! 379: */ ! 380: ! 381: tuncioctl (dev, cmd, data, flag) ! 382: dev_t dev; ! 383: caddr_t data; ! 384: { ! 385: int unit = minor(dev); ! 386: struct tunctl *tp = &tunctl[unit]; ! 387: int s; ! 388: ! 389: switch (cmd) { ! 390: case TUNSDEBUG: ! 391: tundebug = *(int *)data; ! 392: break; ! 393: ! 394: case TUNGDEBUG: ! 395: *(int *)data = tundebug; ! 396: break; ! 397: ! 398: case FIONBIO: ! 399: if (*(int *)data) ! 400: tp->tun_flags |= TUN_NBIO; ! 401: else ! 402: tp->tun_flags &= ~TUN_NBIO; ! 403: break; ! 404: ! 405: case FIOASYNC: ! 406: if (*(int *)data) ! 407: tp->tun_flags |= TUN_ASYNC; ! 408: else ! 409: tp->tun_flags &= ~TUN_ASYNC; ! 410: break; ! 411: ! 412: case FIONREAD: ! 413: s = splimp (); ! 414: if (tp->tun_if.if_snd.ifq_head) ! 415: *(int *)data = tp->tun_if.if_snd.ifq_head->m_len; ! 416: else *(int *)data = 0; ! 417: splx (s); ! 418: break; ! 419: ! 420: case TIOCSPGRP: ! 421: tp->tun_pgrp = *(int *)data; ! 422: break; ! 423: ! 424: case TIOCGPGRP: ! 425: *(int *)data = tp->tun_pgrp; ! 426: break; ! 427: ! 428: default: ! 429: return (ENOTTY); ! 430: } ! 431: return (0); ! 432: } ! 433: ! 434: /* ! 435: * The cdevsw read interface - reads a packet at a time, or at least as much ! 436: * of a packet as can be read. ! 437: */ ! 438: tunread (dev, uio) ! 439: dev_t dev; ! 440: struct uio *uio; ! 441: { ! 442: register struct ifnet *ifp; ! 443: register struct mbuf *m, *m0; ! 444: int unit = minor (dev); ! 445: int len, s; ! 446: int error = 0; ! 447: struct tunctl *tp; ! 448: ! 449: tp = &tunctl[unit]; ! 450: ifp = &tp->tun_if; ! 451: TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit); ! 452: if ((tp->tun_flags & TUN_READY) != TUN_READY) { ! 453: if(tuncheckready(ifp) == 0) { ! 454: TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, ! 455: ifp->if_unit, tp->tun_flags); ! 456: return EHOSTDOWN; ! 457: } ! 458: } ! 459: ! 460: tp->tun_flags &= ~TUN_RWAIT; ! 461: ! 462: s = splimp (); ! 463: do { ! 464: IF_DEQUEUE (&ifp->if_snd, m0); ! 465: if (m0 == 0) { ! 466: if (tp -> tun_flags & TUN_NBIO) { ! 467: splx (s); ! 468: return EWOULDBLOCK; ! 469: } ! 470: tp->tun_flags |= TUN_RWAIT; ! 471: sleep ((caddr_t) tp, PZERO + 1); ! 472: } ! 473: } while (m0 == 0); ! 474: splx (s); ! 475: ! 476: while (m0 && uio->uio_resid > 0 && error == 0) { ! 477: len = MIN (uio->uio_resid, m0->m_len); ! 478: if (len == 0) ! 479: break; ! 480: error = uiomove (mtod (m0, caddr_t), len, ! 481: UIO_READ, uio); ! 482: MFREE (m0, m); ! 483: m0 = m; ! 484: } ! 485: ! 486: if (m0 != 0) { ! 487: TUNDEBUG ("Dropping mbuf\n"); ! 488: m_freem (m0); ! 489: } ! 490: return error; ! 491: } ! 492: ! 493: /* ! 494: * the cdevsw write interface - an atomic write is a packet - or else! ! 495: */ ! 496: ! 497: tunwrite (dev, uio) ! 498: int dev; ! 499: struct uio *uio; ! 500: { ! 501: int error = 0; ! 502: int unit = minor (dev); ! 503: struct mbuf *top, **mp, *m; ! 504: struct ifnet *ifp = &(tunctl[unit].tun_if); ! 505: int s; ! 506: ! 507: TUNDEBUG ("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit); ! 508: ! 509: if (uio->uio_resid < 0 || uio->uio_resid > TUNMTU) { ! 510: TUNDEBUG ("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit, ! 511: uio->uio_resid); ! 512: return EIO; ! 513: } ! 514: top = 0; ! 515: mp = ⊤ ! 516: while (error == 0 && uio->uio_resid > 0) { ! 517: MGET (m, M_DONTWAIT, MT_DATA); ! 518: if (m == 0) { ! 519: error = ENOBUFS; ! 520: break; ! 521: } ! 522: m->m_len = MIN (MLEN, uio->uio_resid); ! 523: error = uiomove (mtod (m, caddr_t), m->m_len, UIO_WRITE, uio); ! 524: *mp = m; ! 525: mp = &m->m_next; ! 526: } ! 527: if (error) { ! 528: if (top) ! 529: m_freem (top); ! 530: return error; ! 531: } ! 532: ! 533: #ifdef BSD4_3 ! 534: /* ! 535: * Place interface pointer before the data ! 536: * for the receiving protocol. ! 537: */ ! 538: if (top->m_off <= MMAXOFF && ! 539: top->m_off >= MMINOFF + sizeof(struct ifnet *)) { ! 540: top->m_off -= sizeof(struct ifnet *); ! 541: top->m_len += sizeof(struct ifnet *); ! 542: } else { ! 543: MGET(m, M_DONTWAIT, MT_HEADER); ! 544: if (m == (struct mbuf *)0) ! 545: return (ENOBUFS); ! 546: m->m_len = sizeof(struct ifnet *); ! 547: m->m_next = top; ! 548: top = m; ! 549: } ! 550: *(mtod(top, struct ifnet **)) = ifp; ! 551: #endif /* BSD4_3 */ ! 552: ! 553: s = splimp (); ! 554: if (IF_QFULL (&ipintrq)) { ! 555: IF_DROP (&ipintrq); ! 556: splx (s); ! 557: ifp->if_collisions++; ! 558: m_freem (top); ! 559: return ENOBUFS; ! 560: } ! 561: IF_ENQUEUE (&ipintrq, top); ! 562: splx (s); ! 563: ifp->if_ipackets++; ! 564: schednetisr (NETISR_IP); ! 565: return error; ! 566: } ! 567: ! 568: /* ! 569: * tunselect - the select interface, this is only useful on reads really. ! 570: * The write detect always returns true, write never blocks anyway, it either ! 571: * accepts the packet or drops it. ! 572: */ ! 573: tunselect (dev, rw) ! 574: dev_t dev; ! 575: int rw; ! 576: { ! 577: int unit = minor (dev); ! 578: register struct tunctl *tp = &tunctl[unit]; ! 579: struct ifnet *ifp = &tp->tun_if; ! 580: int s = splimp (); ! 581: ! 582: TUNDEBUG ("%s%d: tunselect\n", ifp->if_name, ifp->if_unit); ! 583: switch (rw) { ! 584: case FREAD: ! 585: if (ifp->if_snd.ifq_len > 0) { ! 586: splx (s); ! 587: TUNDEBUG ("%s%d: tunselect q=%d\n", ifp->if_name, ! 588: ifp->if_unit, ifp->if_snd.ifq_len); ! 589: return 1; ! 590: } ! 591: if (tp->tun_rsel && tp->tun_rsel->p_wchan == ! 592: (caddr_t) & selwait) ! 593: tp->tun_flags |= TUN_RCOLL; ! 594: else ! 595: tp->tun_rsel = u.u_procp; ! 596: break; ! 597: case FWRITE: ! 598: splx (s); ! 599: return 1; ! 600: } ! 601: splx (s); ! 602: TUNDEBUG ("%s%d: tunselect waiting\n", ifp->if_name, ifp->if_unit); ! 603: return 0; ! 604: } ! 605: #endif NTUN
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.