Annotation of src/sys/net/if_tun.c, Revision 1.82.2.5
1.82.2.5! yamt 1: /* $NetBSD: if_tun.c,v 1.82.2.4 2006/08/11 15:46:16 yamt Exp $ */
1.14 cgd 2:
1.1 cgd 3: /*
1.8 deraadt 4: * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
5: * Nottingham University 1987.
1.1 cgd 6: *
7: * This source may be freely distributed, however I would be interested
8: * in any changes that are made.
1.6 deraadt 9: *
1.1 cgd 10: * This driver takes packets off the IP i/f and hands them up to a
1.21 scottr 11: * user process to have its wicked way with. This driver has its
1.1 cgd 12: * roots in a similar driver written by Phil Cockcroft (formerly) at
1.27 mycroft 13: * UCL. This driver is based much more on read/write/poll mode of
1.1 cgd 14: * operation though.
15: */
1.48 lukem 16:
17: #include <sys/cdefs.h>
1.82.2.5! yamt 18: __KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.82.2.4 2006/08/11 15:46:16 yamt Exp $");
1.33 jonathan 19:
20: #include "opt_inet.h"
1.34 jonathan 21: #include "opt_ns.h"
1.8 deraadt 22:
1.6 deraadt 23: #include <sys/param.h>
1.8 deraadt 24: #include <sys/proc.h>
1.6 deraadt 25: #include <sys/systm.h>
26: #include <sys/mbuf.h>
27: #include <sys/buf.h>
28: #include <sys/protosw.h>
29: #include <sys/socket.h>
30: #include <sys/ioctl.h>
31: #include <sys/errno.h>
32: #include <sys/syslog.h>
33: #include <sys/select.h>
1.27 mycroft 34: #include <sys/poll.h>
1.8 deraadt 35: #include <sys/file.h>
1.22 christos 36: #include <sys/signalvar.h>
1.23 christos 37: #include <sys/conf.h>
1.82.2.3 yamt 38: #include <sys/kauth.h>
1.9 deraadt 39:
40: #include <machine/cpu.h>
1.6 deraadt 41:
42: #include <net/if.h>
1.69 tron 43: #include <net/if_types.h>
1.6 deraadt 44: #include <net/netisr.h>
45: #include <net/route.h>
1.1 cgd 46:
1.30 is 47:
1.1 cgd 48: #ifdef INET
1.6 deraadt 49: #include <netinet/in.h>
50: #include <netinet/in_systm.h>
51: #include <netinet/in_var.h>
52: #include <netinet/ip.h>
1.30 is 53: #include <netinet/if_inarp.h>
1.1 cgd 54: #endif
55:
56: #ifdef NS
1.6 deraadt 57: #include <netns/ns.h>
58: #include <netns/ns_if.h>
1.1 cgd 59: #endif
60:
1.8 deraadt 61: #include "bpfilter.h"
62: #if NBPFILTER > 0
63: #include <sys/time.h>
64: #include <net/bpf.h>
65: #endif
66:
67: #include <net/if_tun.h>
68:
1.29 christos 69: #define TUNDEBUG if (tundebug) printf
1.6 deraadt 70: int tundebug = 0;
1.1 cgd 71:
1.6 deraadt 72: extern int ifqmaxlen;
1.78 thorpej 73: void tunattach(int);
74:
75: static LIST_HEAD(, tun_softc) tun_softc_list;
76: static LIST_HEAD(, tun_softc) tunz_softc_list;
1.46 atatat 77: static struct simplelock tun_softc_lock;
1.6 deraadt 78:
1.78 thorpej 79: static int tun_ioctl(struct ifnet *, u_long, caddr_t);
80: static int tun_output(struct ifnet *, struct mbuf *, struct sockaddr *,
81: struct rtentry *rt);
82: static int tun_clone_create(struct if_clone *, int);
83: static int tun_clone_destroy(struct ifnet *);
1.6 deraadt 84:
1.78 thorpej 85: static struct if_clone tun_cloner =
1.46 atatat 86: IF_CLONE_INITIALIZER("tun", tun_clone_create, tun_clone_destroy);
87:
1.78 thorpej 88: static void tunattach0(struct tun_softc *);
89: static void tuninit(struct tun_softc *);
1.50 itojun 90: #ifdef ALTQ
1.78 thorpej 91: static void tunstart(struct ifnet *);
1.50 itojun 92: #endif
1.78 thorpej 93: static struct tun_softc *tun_find_unit(dev_t);
94: static struct tun_softc *tun_find_zunit(int);
1.53 gehenna 95:
1.78 thorpej 96: static dev_type_open(tunopen);
97: static dev_type_close(tunclose);
98: static dev_type_read(tunread);
99: static dev_type_write(tunwrite);
100: static dev_type_ioctl(tunioctl);
101: static dev_type_poll(tunpoll);
102: static dev_type_kqfilter(tunkqfilter);
1.53 gehenna 103:
104: const struct cdevsw tun_cdevsw = {
105: tunopen, tunclose, tunread, tunwrite, tunioctl,
1.82.2.5! yamt 106: nostop, notty, tunpoll, nommap, tunkqfilter, D_OTHER,
1.53 gehenna 107: };
1.6 deraadt 108:
1.8 deraadt 109: void
1.78 thorpej 110: tunattach(int unused)
1.8 deraadt 111: {
1.46 atatat 112:
113: simple_lock_init(&tun_softc_lock);
114: LIST_INIT(&tun_softc_list);
1.70 pk 115: LIST_INIT(&tunz_softc_list);
1.46 atatat 116: if_clone_attach(&tun_cloner);
117: }
118:
1.70 pk 119: /*
120: * Find driver instance from dev_t.
121: * Call at splnet().
122: * Returns with tp locked (if found).
123: */
124: static struct tun_softc *
1.78 thorpej 125: tun_find_unit(dev_t dev)
1.70 pk 126: {
127: struct tun_softc *tp;
128: int unit = minor(dev);
129:
130: simple_lock(&tun_softc_lock);
131: LIST_FOREACH(tp, &tun_softc_list, tun_list)
132: if (unit == tp->tun_unit)
133: break;
134: if (tp)
135: simple_lock(&tp->tun_lock);
136: simple_unlock(&tun_softc_lock);
137:
138: return (tp);
139: }
140:
141: /*
142: * Find zombie driver instance by unit number.
143: * Call at splnet().
144: * Remove tp from list and return it unlocked (if found).
145: */
146: static struct tun_softc *
1.78 thorpej 147: tun_find_zunit(int unit)
1.70 pk 148: {
149: struct tun_softc *tp;
150:
151: simple_lock(&tun_softc_lock);
152: LIST_FOREACH(tp, &tunz_softc_list, tun_list)
153: if (unit == tp->tun_unit)
154: break;
155: if (tp)
156: LIST_REMOVE(tp, tun_list);
157: simple_unlock(&tun_softc_lock);
158: #ifdef DIAGNOSTIC
159: if (tp != NULL && (tp->tun_flags & (TUN_INITED|TUN_OPEN)) != TUN_OPEN)
160: printf("tun%d: inconsistent flags: %x\n", unit, tp->tun_flags);
161: #endif
162:
163: return (tp);
164: }
165:
1.78 thorpej 166: static int
167: tun_clone_create(struct if_clone *ifc, int unit)
1.46 atatat 168: {
1.70 pk 169: struct tun_softc *tp;
1.46 atatat 170:
1.70 pk 171: if ((tp = tun_find_zunit(unit)) == NULL) {
172: /* Allocate a new instance */
173: tp = malloc(sizeof(struct tun_softc), M_DEVBUF, M_WAITOK);
174: (void)memset(tp, 0, sizeof(struct tun_softc));
1.46 atatat 175:
1.70 pk 176: tp->tun_unit = unit;
177: simple_lock_init(&tp->tun_lock);
178: } else {
179: /* Revive tunnel instance; clear ifp part */
180: (void)memset(&tp->tun_if, 0, sizeof(struct ifnet));
181: }
1.46 atatat 182:
1.70 pk 183: (void)snprintf(tp->tun_if.if_xname, sizeof(tp->tun_if.if_xname),
184: "%s%d", ifc->ifc_name, unit);
185: tunattach0(tp);
186: tp->tun_flags |= TUN_INITED;
1.46 atatat 187:
188: simple_lock(&tun_softc_lock);
1.70 pk 189: LIST_INSERT_HEAD(&tun_softc_list, tp, tun_list);
1.46 atatat 190: simple_unlock(&tun_softc_lock);
191:
192: return (0);
193: }
194:
1.78 thorpej 195: static void
196: tunattach0(struct tun_softc *tp)
1.46 atatat 197: {
1.70 pk 198: struct ifnet *ifp;
1.46 atatat 199:
1.70 pk 200: ifp = &tp->tun_if;
201: ifp->if_softc = tp;
1.46 atatat 202: ifp->if_mtu = TUNMTU;
203: ifp->if_ioctl = tun_ioctl;
204: ifp->if_output = tun_output;
1.50 itojun 205: #ifdef ALTQ
206: ifp->if_start = tunstart;
207: #endif
1.46 atatat 208: ifp->if_flags = IFF_POINTOPOINT;
1.69 tron 209: ifp->if_type = IFT_TUNNEL;
1.46 atatat 210: ifp->if_snd.ifq_maxlen = ifqmaxlen;
211: ifp->if_collisions = 0;
212: ifp->if_ierrors = 0;
213: ifp->if_oerrors = 0;
214: ifp->if_ipackets = 0;
215: ifp->if_opackets = 0;
1.58 jdolecek 216: ifp->if_ibytes = 0;
217: ifp->if_obytes = 0;
1.46 atatat 218: ifp->if_dlt = DLT_NULL;
1.50 itojun 219: IFQ_SET_READY(&ifp->if_snd);
1.46 atatat 220: if_attach(ifp);
221: if_alloc_sadl(ifp);
222: #if NBPFILTER > 0
223: bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
224: #endif
225: }
226:
1.78 thorpej 227: static int
228: tun_clone_destroy(struct ifnet *ifp)
1.46 atatat 229: {
230: struct tun_softc *tp = (void *)ifp;
1.70 pk 231: int s, zombie = 0;
1.8 deraadt 232:
1.70 pk 233: s = splnet();
1.46 atatat 234: simple_lock(&tun_softc_lock);
235: simple_lock(&tp->tun_lock);
236: LIST_REMOVE(tp, tun_list);
1.70 pk 237: if (tp->tun_flags & TUN_OPEN) {
238: /* Hang on to storage until last close */
239: zombie = 1;
240: tp->tun_flags &= ~TUN_INITED;
241: LIST_INSERT_HEAD(&tunz_softc_list, tp, tun_list);
242: }
1.46 atatat 243: simple_unlock(&tun_softc_lock);
244:
1.70 pk 245: IF_PURGE(&ifp->if_snd);
246: ifp->if_flags &= ~IFF_RUNNING;
247:
1.46 atatat 248: if (tp->tun_flags & TUN_RWAIT) {
249: tp->tun_flags &= ~TUN_RWAIT;
250: wakeup((caddr_t)tp);
251: }
1.64 jdolecek 252: if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
1.66 christos 253: fownsignal(tp->tun_pgid, SIGIO, POLL_HUP, 0, NULL);
1.64 jdolecek 254:
1.46 atatat 255: selwakeup(&tp->tun_rsel);
1.8 deraadt 256:
1.70 pk 257: simple_unlock(&tp->tun_lock);
258: splx(s);
259:
1.8 deraadt 260: #if NBPFILTER > 0
1.46 atatat 261: bpfdetach(ifp);
1.8 deraadt 262: #endif
1.46 atatat 263: if_detach(ifp);
264:
1.70 pk 265: if (!zombie)
266: free(tp, M_DEVBUF);
1.73 peter 267:
268: return (0);
1.8 deraadt 269: }
270:
1.6 deraadt 271: /*
272: * tunnel open - must be superuser & the device must be
273: * configured in
274: */
1.78 thorpej 275: static int
276: tunopen(dev_t dev, int flag, int mode, struct lwp *l)
1.6 deraadt 277: {
278: struct ifnet *ifp;
1.8 deraadt 279: struct tun_softc *tp;
1.70 pk 280: int s, error;
1.1 cgd 281:
1.82.2.4 yamt 282: if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
283: &l->l_acflag)) != 0)
1.5 deraadt 284: return (error);
285:
1.70 pk 286: s = splnet();
1.46 atatat 287: tp = tun_find_unit(dev);
1.52 atatat 288:
1.70 pk 289: if (tp == NULL) {
1.52 atatat 290: (void)tun_clone_create(&tun_cloner, minor(dev));
291: tp = tun_find_unit(dev);
1.70 pk 292: if (tp == NULL) {
293: error = ENXIO;
294: goto out_nolock;
295: }
1.52 atatat 296: }
1.46 atatat 297:
298: if (tp->tun_flags & TUN_OPEN) {
1.70 pk 299: error = EBUSY;
300: goto out;
1.46 atatat 301: }
302:
1.6 deraadt 303: ifp = &tp->tun_if;
304: tp->tun_flags |= TUN_OPEN;
1.24 thorpej 305: TUNDEBUG("%s: open\n", ifp->if_xname);
1.70 pk 306: out:
1.46 atatat 307: simple_unlock(&tp->tun_lock);
1.70 pk 308: out_nolock:
309: splx(s);
310: return (error);
1.1 cgd 311: }
312:
1.6 deraadt 313: /*
314: * tunclose - close the device - mark i/f down & delete
315: * routing info
316: */
317: int
1.78 thorpej 318: tunclose(dev_t dev, int flag, int mode, struct lwp *l)
1.6 deraadt 319: {
1.46 atatat 320: int s;
321: struct tun_softc *tp;
322: struct ifnet *ifp;
1.6 deraadt 323:
1.70 pk 324: s = splnet();
325: if ((tp = tun_find_zunit(minor(dev))) != NULL) {
326: /* interface was "destroyed" before the close */
327: free(tp, M_DEVBUF);
328: goto out_nolock;
329: }
1.46 atatat 330:
1.70 pk 331: if ((tp = tun_find_unit(dev)) == NULL)
332: goto out_nolock;
1.46 atatat 333:
334: ifp = &tp->tun_if;
335:
1.10 andrew 336: tp->tun_flags &= ~TUN_OPEN;
1.6 deraadt 337:
338: /*
339: * junk all pending output
340: */
1.50 itojun 341: IFQ_PURGE(&ifp->if_snd);
1.6 deraadt 342:
343: if (ifp->if_flags & IFF_UP) {
344: if_down(ifp);
1.8 deraadt 345: if (ifp->if_flags & IFF_RUNNING) {
1.17 mycroft 346: /* find internet addresses and delete routes */
1.39 augustss 347: struct ifaddr *ifa;
1.76 matt 348: IFADDR_FOREACH(ifa, ifp) {
1.80 rpaulo 349: #if defined(INET) || defined(INET6)
350: if (ifa->ifa_addr->sa_family == AF_INET ||
351: ifa->ifa_addr->sa_family == AF_INET6) {
1.18 mycroft 352: rtinit(ifa, (int)RTM_DELETE,
1.26 pk 353: tp->tun_flags & TUN_DSTADDR
354: ? RTF_HOST
355: : 0);
1.18 mycroft 356: }
1.38 itojun 357: #endif
1.11 deraadt 358: }
1.8 deraadt 359: }
1.6 deraadt 360: }
1.64 jdolecek 361: tp->tun_pgid = 0;
1.56 jdolecek 362: selnotify(&tp->tun_rsel, 0);
1.70 pk 363:
1.24 thorpej 364: TUNDEBUG ("%s: closed\n", ifp->if_xname);
1.46 atatat 365: simple_unlock(&tp->tun_lock);
1.70 pk 366: out_nolock:
367: splx(s);
1.6 deraadt 368: return (0);
1.1 cgd 369: }
370:
1.70 pk 371: /*
372: * Call at splnet() with tp locked.
373: */
1.26 pk 374: static void
1.78 thorpej 375: tuninit(struct tun_softc *tp)
1.6 deraadt 376: {
377: struct ifnet *ifp = &tp->tun_if;
1.46 atatat 378: struct ifaddr *ifa;
1.8 deraadt 379:
1.24 thorpej 380: TUNDEBUG("%s: tuninit\n", ifp->if_xname);
1.6 deraadt 381:
382: ifp->if_flags |= IFF_UP | IFF_RUNNING;
1.8 deraadt 383:
1.26 pk 384: tp->tun_flags &= ~(TUN_IASET|TUN_DSTADDR);
1.76 matt 385: IFADDR_FOREACH(ifa, ifp) {
1.38 itojun 386: #ifdef INET
1.11 deraadt 387: if (ifa->ifa_addr->sa_family == AF_INET) {
1.17 mycroft 388: struct sockaddr_in *sin;
1.11 deraadt 389:
1.17 mycroft 390: sin = satosin(ifa->ifa_addr);
391: if (sin && sin->sin_addr.s_addr)
392: tp->tun_flags |= TUN_IASET;
393:
1.26 pk 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: }
1.11 deraadt 399: }
1.38 itojun 400: #endif
1.80 rpaulo 401: #ifdef INET6
402: if (ifa->ifa_addr->sa_family == AF_INET6) {
403: struct sockaddr_in6 *sin;
404:
405: sin = (struct sockaddr_in6 *)ifa->ifa_addr;
406: if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
407: tp->tun_flags |= TUN_IASET;
408:
409: if (ifp->if_flags & IFF_POINTOPOINT) {
410: sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
411: if (sin &&
412: !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
413: tp->tun_flags |= TUN_DSTADDR;
414: } else
415: tp->tun_flags &= ~TUN_DSTADDR;
416: }
417: #endif /* INET6 */
1.18 mycroft 418: }
1.8 deraadt 419:
1.26 pk 420: return;
1.1 cgd 421: }
422:
423: /*
424: * Process an ioctl request.
425: */
1.78 thorpej 426: static int
427: tun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1.6 deraadt 428: {
429: int error = 0, s;
1.46 atatat 430: struct tun_softc *tp = (struct tun_softc *)(ifp->if_softc);
431:
1.70 pk 432: s = splnet();
1.46 atatat 433: simple_lock(&tp->tun_lock);
1.6 deraadt 434:
1.61 itojun 435: switch (cmd) {
1.6 deraadt 436: case SIOCSIFADDR:
1.70 pk 437: tuninit(tp);
1.24 thorpej 438: TUNDEBUG("%s: address set\n", ifp->if_xname);
1.6 deraadt 439: break;
440: case SIOCSIFDSTADDR:
1.70 pk 441: tuninit(tp);
1.24 thorpej 442: TUNDEBUG("%s: destination address set\n", ifp->if_xname);
1.6 deraadt 443: break;
1.26 pk 444: case SIOCSIFBRDADDR:
445: TUNDEBUG("%s: broadcast address set\n", ifp->if_xname);
446: break;
1.31 matt 447: case SIOCSIFMTU: {
448: struct ifreq *ifr = (struct ifreq *) data;
449: if (ifr->ifr_mtu > TUNMTU || ifr->ifr_mtu < 576) {
450: error = EINVAL;
451: break;
452: }
453: TUNDEBUG("%s: interface mtu set\n", ifp->if_xname);
454: ifp->if_mtu = ifr->ifr_mtu;
1.32 matt 455: break;
456: }
457: case SIOCADDMULTI:
458: case SIOCDELMULTI: {
459: struct ifreq *ifr = (struct ifreq *) data;
460: if (ifr == 0) {
461: error = EAFNOSUPPORT; /* XXX */
462: break;
463: }
464: switch (ifr->ifr_addr.sa_family) {
465: #ifdef INET
466: case AF_INET:
467: break;
468: #endif
1.80 rpaulo 469: #ifdef INET6
470: case AF_INET6:
471: break;
472: #endif
1.32 matt 473: default:
474: error = EAFNOSUPPORT;
475: break;
476: }
1.31 matt 477: break;
478: }
1.38 itojun 479: case SIOCSIFFLAGS:
480: break;
1.6 deraadt 481: default:
482: error = EINVAL;
483: }
1.70 pk 484:
485: simple_unlock(&tp->tun_lock);
1.6 deraadt 486: splx(s);
487: return (error);
1.1 cgd 488: }
489:
490: /*
1.22 christos 491: * tun_output - queue packets from higher level ready to put out.
1.1 cgd 492: */
1.78 thorpej 493: static int
494: tun_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
495: struct rtentry *rt)
1.6 deraadt 496: {
1.24 thorpej 497: struct tun_softc *tp = ifp->if_softc;
1.6 deraadt 498: int s;
1.51 itojun 499: int error;
1.80 rpaulo 500: #if defined(INET) || defined(INET6)
1.75 christos 501: int mlen;
1.80 rpaulo 502: uint32_t *af;
1.38 itojun 503: #endif
1.50 itojun 504: ALTQ_DECL(struct altq_pktattr pktattr;)
1.6 deraadt 505:
1.70 pk 506: s = splnet();
1.46 atatat 507: simple_lock(&tp->tun_lock);
1.24 thorpej 508: TUNDEBUG ("%s: tun_output\n", ifp->if_xname);
1.1 cgd 509:
1.8 deraadt 510: if ((tp->tun_flags & TUN_READY) != TUN_READY) {
1.24 thorpej 511: TUNDEBUG ("%s: not ready 0%o\n", ifp->if_xname,
512: tp->tun_flags);
1.8 deraadt 513: m_freem (m0);
1.70 pk 514: error = EHOSTDOWN;
515: goto out;
1.8 deraadt 516: }
517:
1.50 itojun 518: /*
519: * if the queueing discipline needs packet classification,
520: * do it before prepending link headers.
521: */
522: IFQ_CLASSIFY(&ifp->if_snd, m0, dst->sa_family, &pktattr);
1.70 pk 523:
1.8 deraadt 524: #if NBPFILTER > 0
1.72 christos 525: if (ifp->if_bpf)
526: bpf_mtap_af(ifp->if_bpf, dst->sa_family, m0);
1.8 deraadt 527: #endif
528:
1.6 deraadt 529: switch(dst->sa_family) {
1.79 rpaulo 530: #ifdef INET6
531: case AF_INET6:
532: #endif
1.1 cgd 533: #ifdef INET
1.6 deraadt 534: case AF_INET:
1.79 rpaulo 535: #endif
536: #if defined(INET) || defined(INET6)
1.26 pk 537: if (tp->tun_flags & TUN_PREPADDR) {
538: /* Simple link-layer header */
539: M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
540: if (m0 == NULL) {
541: IF_DROP(&ifp->if_snd);
1.70 pk 542: error = ENOBUFS;
543: goto out;
1.26 pk 544: }
545: bcopy(dst, mtod(m0, char *), dst->sa_len);
1.82.2.2 yamt 546: }
547:
548: if (tp->tun_flags & TUN_IFHEAD) {
1.81 rpaulo 549: /* Prepend the address family */
1.82 rpaulo 550: M_PREPEND(m0, sizeof(*af), M_DONTWAIT);
1.80 rpaulo 551: if (m0 == NULL) {
552: IF_DROP(&ifp->if_snd);
553: error = ENOBUFS;
554: goto out;
555: }
556: af = mtod(m0,uint32_t *);
557: *af = htonl(dst->sa_family);
1.82.2.2 yamt 558: } else {
559: #ifdef INET
560: if (dst->sa_family != AF_INET)
561: #endif
562: {
563: m_freem(m0);
564: error = EAFNOSUPPORT;
565: goto out;
566: }
1.26 pk 567: }
1.36 sommerfe 568: /* FALLTHROUGH */
569: case AF_UNSPEC:
1.50 itojun 570: IFQ_ENQUEUE(&ifp->if_snd, m0, &pktattr, error);
571: if (error) {
1.6 deraadt 572: ifp->if_collisions++;
1.70 pk 573: error = EAFNOSUPPORT;
574: goto out;
1.6 deraadt 575: }
1.58 jdolecek 576: mlen = m0->m_pkthdr.len;
1.6 deraadt 577: ifp->if_opackets++;
1.58 jdolecek 578: ifp->if_obytes += mlen;
1.6 deraadt 579: break;
1.1 cgd 580: #endif
1.6 deraadt 581: default:
582: m_freem(m0);
1.70 pk 583: error = EAFNOSUPPORT;
584: goto out;
1.6 deraadt 585: }
586:
587: if (tp->tun_flags & TUN_RWAIT) {
588: tp->tun_flags &= ~TUN_RWAIT;
589: wakeup((caddr_t)tp);
590: }
1.64 jdolecek 591: if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
1.66 christos 592: fownsignal(tp->tun_pgid, SIGIO, POLL_IN, POLLIN|POLLRDNORM,
593: NULL);
1.64 jdolecek 594:
1.56 jdolecek 595: selnotify(&tp->tun_rsel, 0);
1.70 pk 596: out:
1.46 atatat 597: simple_unlock(&tp->tun_lock);
1.70 pk 598: splx(s);
1.26 pk 599: return (0);
1.1 cgd 600: }
601:
602: /*
603: * the cdevsw interface is now pretty minimal.
604: */
1.6 deraadt 605: int
1.78 thorpej 606: tunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
1.6 deraadt 607: {
1.46 atatat 608: struct tun_softc *tp;
1.70 pk 609: int s, error = 0;
1.46 atatat 610:
1.70 pk 611: s = splnet();
1.46 atatat 612: tp = tun_find_unit(dev);
613:
614: /* interface was "destroyed" already */
1.70 pk 615: if (tp == NULL) {
616: error = ENXIO;
617: goto out_nolock;
618: }
1.6 deraadt 619:
620: switch (cmd) {
621: case TUNSDEBUG:
622: tundebug = *(int *)data;
623: break;
1.26 pk 624:
1.6 deraadt 625: case TUNGDEBUG:
626: *(int *)data = tundebug;
627: break;
1.26 pk 628:
629: case TUNSIFMODE:
1.31 matt 630: switch (*(int *)data & (IFF_POINTOPOINT|IFF_BROADCAST)) {
1.26 pk 631: case IFF_POINTOPOINT:
632: case IFF_BROADCAST:
633: if (tp->tun_if.if_flags & IFF_UP) {
1.70 pk 634: error = EBUSY;
635: goto out;
1.26 pk 636: }
637: tp->tun_if.if_flags &=
1.31 matt 638: ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST);
1.26 pk 639: tp->tun_if.if_flags |= *(int *)data;
640: break;
641: default:
1.70 pk 642: error = EINVAL;
643: goto out;
1.26 pk 644: }
645: break;
646:
647: case TUNSLMODE:
1.82.2.2 yamt 648: if (*(int *)data) {
1.26 pk 649: tp->tun_flags |= TUN_PREPADDR;
1.82.2.2 yamt 650: tp->tun_flags &= ~TUN_IFHEAD;
651: } else
1.26 pk 652: tp->tun_flags &= ~TUN_PREPADDR;
653: break;
654:
1.82.2.2 yamt 655: case TUNSIFHEAD:
656: if (*(int *)data) {
657: tp->tun_flags |= TUN_IFHEAD;
1.82.2.3 yamt 658: tp->tun_flags &= ~TUN_PREPADDR;
1.82.2.2 yamt 659: } else
660: tp->tun_flags &= ~TUN_IFHEAD;
661: break;
662:
663: case TUNGIFHEAD:
664: *(int *)data = (tp->tun_flags & TUN_IFHEAD);
665: break;
666:
1.6 deraadt 667: case FIONBIO:
668: if (*(int *)data)
669: tp->tun_flags |= TUN_NBIO;
670: else
671: tp->tun_flags &= ~TUN_NBIO;
672: break;
1.26 pk 673:
1.6 deraadt 674: case FIOASYNC:
675: if (*(int *)data)
676: tp->tun_flags |= TUN_ASYNC;
677: else
678: tp->tun_flags &= ~TUN_ASYNC;
679: break;
1.26 pk 680:
1.6 deraadt 681: case FIONREAD:
682: if (tp->tun_if.if_snd.ifq_head)
1.19 pk 683: *(int *)data = tp->tun_if.if_snd.ifq_head->m_pkthdr.len;
1.70 pk 684: else
1.6 deraadt 685: *(int *)data = 0;
686: break;
1.26 pk 687:
1.6 deraadt 688: case TIOCSPGRP:
1.64 jdolecek 689: case FIOSETOWN:
1.77 christos 690: error = fsetown(l->l_proc, &tp->tun_pgid, cmd, data);
1.6 deraadt 691: break;
1.26 pk 692:
1.6 deraadt 693: case TIOCGPGRP:
1.64 jdolecek 694: case FIOGETOWN:
1.77 christos 695: error = fgetown(l->l_proc, tp->tun_pgid, cmd, data);
1.6 deraadt 696: break;
1.26 pk 697:
1.6 deraadt 698: default:
1.70 pk 699: error = ENOTTY;
1.6 deraadt 700: }
1.70 pk 701:
702: out:
1.46 atatat 703: simple_unlock(&tp->tun_lock);
1.70 pk 704: out_nolock:
705: splx(s);
1.64 jdolecek 706: return (error);
1.1 cgd 707: }
708:
709: /*
1.6 deraadt 710: * The cdevsw read interface - reads a packet at a time, or at
711: * least as much of a packet as can be read.
1.1 cgd 712: */
1.6 deraadt 713: int
1.78 thorpej 714: tunread(dev_t dev, struct uio *uio, int ioflag)
1.6 deraadt 715: {
1.46 atatat 716: struct tun_softc *tp;
717: struct ifnet *ifp;
1.6 deraadt 718: struct mbuf *m, *m0;
1.70 pk 719: int error = 0, len, s, index;
1.46 atatat 720:
1.70 pk 721: s = splnet();
1.46 atatat 722: tp = tun_find_unit(dev);
723:
724: /* interface was "destroyed" already */
1.70 pk 725: if (tp == NULL) {
726: error = ENXIO;
727: goto out_nolock;
728: }
1.46 atatat 729:
730: index = tp->tun_if.if_index;
731: ifp = &tp->tun_if;
1.6 deraadt 732:
1.24 thorpej 733: TUNDEBUG ("%s: read\n", ifp->if_xname);
1.8 deraadt 734: if ((tp->tun_flags & TUN_READY) != TUN_READY) {
1.26 pk 735: TUNDEBUG ("%s: not ready 0%o\n", ifp->if_xname, tp->tun_flags);
1.70 pk 736: error = EHOSTDOWN;
737: goto out;
1.8 deraadt 738: }
739:
1.6 deraadt 740: tp->tun_flags &= ~TUN_RWAIT;
741:
742: do {
1.50 itojun 743: IFQ_DEQUEUE(&ifp->if_snd, m0);
1.6 deraadt 744: if (m0 == 0) {
745: if (tp->tun_flags & TUN_NBIO) {
1.70 pk 746: error = EWOULDBLOCK;
747: goto out;
1.6 deraadt 748: }
749: tp->tun_flags |= TUN_RWAIT;
1.70 pk 750: if (ltsleep((caddr_t)tp, PZERO|PCATCH|PNORELOCK,
751: "tunread", 0, &tp->tun_lock) != 0) {
752: error = EINTR;
753: goto out_nolock;
1.46 atatat 754: } else {
755: /*
756: * Maybe the interface was destroyed while
757: * we were sleeping, so let's ensure that
758: * we're looking at the same (valid) tun
759: * interface before looping.
760: */
761: tp = tun_find_unit(dev);
1.70 pk 762: if (tp == NULL) {
763: error = ENXIO;
764: goto out_nolock;
765: }
766: if (tp->tun_if.if_index != index) {
767: error = ENXIO;
768: goto out;
1.46 atatat 769: }
1.26 pk 770: }
1.6 deraadt 771: }
772: } while (m0 == 0);
1.70 pk 773:
774: simple_unlock(&tp->tun_lock);
1.6 deraadt 775: splx(s);
776:
1.70 pk 777: /* Copy the mbuf chain */
1.6 deraadt 778: while (m0 && uio->uio_resid > 0 && error == 0) {
1.13 deraadt 779: len = min(uio->uio_resid, m0->m_len);
1.45 itojun 780: if (len != 0)
781: error = uiomove(mtod(m0, caddr_t), len, uio);
1.6 deraadt 782: MFREE(m0, m);
783: m0 = m;
784: }
785:
786: if (m0) {
787: TUNDEBUG("Dropping mbuf\n");
788: m_freem(m0);
789: }
1.19 pk 790: if (error)
791: ifp->if_ierrors++;
1.70 pk 792:
793: return (error);
794:
795: out:
1.46 atatat 796: simple_unlock(&tp->tun_lock);
1.70 pk 797: out_nolock:
798: splx(s);
1.26 pk 799: return (error);
1.1 cgd 800: }
801:
802: /*
803: * the cdevsw write interface - an atomic write is a packet - or else!
804: */
1.6 deraadt 805: int
1.78 thorpej 806: tunwrite(dev_t dev, struct uio *uio, int ioflag)
1.6 deraadt 807: {
1.46 atatat 808: struct tun_softc *tp;
809: struct ifnet *ifp;
1.6 deraadt 810: struct mbuf *top, **mp, *m;
1.26 pk 811: struct ifqueue *ifq;
812: struct sockaddr dst;
1.70 pk 813: int isr, error = 0, s, tlen, mlen;
1.80 rpaulo 814: uint32_t family;
1.6 deraadt 815:
1.70 pk 816: s = splnet();
1.46 atatat 817: tp = tun_find_unit(dev);
818:
819: /* interface was "destroyed" already */
1.70 pk 820: if (tp == NULL) {
821: error = ENXIO;
822: goto out_nolock;
823: }
824:
825: /* Unlock until we've got the data */
826: simple_unlock(&tp->tun_lock);
827: splx(s);
1.46 atatat 828:
829: ifp = &tp->tun_if;
830:
1.24 thorpej 831: TUNDEBUG("%s: tunwrite\n", ifp->if_xname);
1.6 deraadt 832:
1.26 pk 833: if (tp->tun_flags & TUN_PREPADDR) {
1.46 atatat 834: if (uio->uio_resid < sizeof(dst)) {
1.70 pk 835: error = EIO;
836: goto out0;
1.46 atatat 837: }
1.26 pk 838: error = uiomove((caddr_t)&dst, sizeof(dst), uio);
839: if (dst.sa_len > sizeof(dst)) {
840: /* Duh.. */
841: char discard;
842: int n = dst.sa_len - sizeof(dst);
843: while (n--)
1.46 atatat 844: if ((error = uiomove(&discard, 1, uio)) != 0) {
1.70 pk 845: goto out0;
1.46 atatat 846: }
1.26 pk 847: }
1.82.2.2 yamt 848: } else if (tp->tun_flags & TUN_IFHEAD) {
1.80 rpaulo 849: if (uio->uio_resid < sizeof(family)){
850: error = EIO;
851: goto out0;
852: }
1.82 rpaulo 853: error = uiomove((caddr_t)&family, sizeof(family), uio);
1.80 rpaulo 854: dst.sa_family = ntohl(family);
1.82.2.2 yamt 855: } else {
856: #ifdef INET
857: dst.sa_family = AF_INET;
858: #endif
1.26 pk 859: }
860:
1.54 simonb 861: if (uio->uio_resid > TUNMTU) {
1.37 mjacob 862: TUNDEBUG("%s: len=%lu!\n", ifp->if_xname,
863: (unsigned long)uio->uio_resid);
1.70 pk 864: error = EIO;
865: goto out0;
1.6 deraadt 866: }
1.26 pk 867:
868: switch (dst.sa_family) {
869: #ifdef INET
870: case AF_INET:
871: ifq = &ipintrq;
872: isr = NETISR_IP;
873: break;
874: #endif
1.79 rpaulo 875: #ifdef INET6
876: case AF_INET6:
877: ifq = &ip6intrq;
878: isr = NETISR_IPV6;
1.82.2.1 yamt 879: break;
1.79 rpaulo 880: #endif
1.26 pk 881: default:
1.70 pk 882: error = EAFNOSUPPORT;
883: goto out0;
1.26 pk 884: }
885:
1.8 deraadt 886: tlen = uio->uio_resid;
887:
888: /* get a header mbuf */
889: MGETHDR(m, M_DONTWAIT, MT_DATA);
1.46 atatat 890: if (m == NULL) {
1.70 pk 891: error = ENOBUFS;
892: goto out0;
1.46 atatat 893: }
1.8 deraadt 894: mlen = MHLEN;
895:
1.68 tron 896: top = NULL;
1.6 deraadt 897: mp = ⊤
898: while (error == 0 && uio->uio_resid > 0) {
1.13 deraadt 899: m->m_len = min(mlen, uio->uio_resid);
1.68 tron 900: error = uiomove(mtod(m, caddr_t), m->m_len, uio);
1.6 deraadt 901: *mp = m;
902: mp = &m->m_next;
1.68 tron 903: if (error == 0 && uio->uio_resid > 0) {
904: MGET(m, M_DONTWAIT, MT_DATA);
905: if (m == NULL) {
1.8 deraadt 906: error = ENOBUFS;
907: break;
908: }
909: mlen = MLEN;
910: }
1.6 deraadt 911: }
912: if (error) {
1.68 tron 913: if (top != NULL)
1.8 deraadt 914: m_freem (top);
1.19 pk 915: ifp->if_ierrors++;
1.70 pk 916: goto out0;
1.6 deraadt 917: }
918:
1.8 deraadt 919: top->m_pkthdr.len = tlen;
920: top->m_pkthdr.rcvif = ifp;
921:
922: #if NBPFILTER > 0
1.72 christos 923: if (ifp->if_bpf)
1.80 rpaulo 924: bpf_mtap_af(ifp->if_bpf, dst.sa_family, top);
1.8 deraadt 925: #endif
1.6 deraadt 926:
1.43 thorpej 927: s = splnet();
1.70 pk 928: simple_lock(&tp->tun_lock);
929: if ((tp->tun_flags & TUN_INITED) == 0) {
930: /* Interface was destroyed */
931: error = ENXIO;
932: goto out;
933: }
1.26 pk 934: if (IF_QFULL(ifq)) {
935: IF_DROP(ifq);
1.6 deraadt 936: ifp->if_collisions++;
937: m_freem(top);
1.70 pk 938: error = ENOBUFS;
939: goto out;
1.6 deraadt 940: }
1.70 pk 941:
1.26 pk 942: IF_ENQUEUE(ifq, top);
1.6 deraadt 943: ifp->if_ipackets++;
1.58 jdolecek 944: ifp->if_ibytes += tlen;
1.26 pk 945: schednetisr(isr);
1.70 pk 946: out:
1.46 atatat 947: simple_unlock(&tp->tun_lock);
1.70 pk 948: out_nolock:
949: splx(s);
950: out0:
1.26 pk 951: return (error);
1.1 cgd 952: }
953:
1.50 itojun 954: #ifdef ALTQ
955: /*
956: * Start packet transmission on the interface.
957: * when the interface queue is rate-limited by ALTQ or TBR,
958: * if_start is needed to drain packets from the queue in order
959: * to notify readers when outgoing packets become ready.
1.70 pk 960: *
961: * Should be called at splnet.
1.50 itojun 962: */
963: static void
1.78 thorpej 964: tunstart(struct ifnet *ifp)
1.50 itojun 965: {
966: struct tun_softc *tp = ifp->if_softc;
967:
968: if (!ALTQ_IS_ENABLED(&ifp->if_snd) && !TBR_IS_ENABLED(&ifp->if_snd))
969: return;
970:
1.70 pk 971: simple_lock(&tp->tun_lock);
972: if (!IF_IS_EMPTY(&ifp->if_snd)) {
1.50 itojun 973: if (tp->tun_flags & TUN_RWAIT) {
974: tp->tun_flags &= ~TUN_RWAIT;
975: wakeup((caddr_t)tp);
976: }
1.64 jdolecek 977: if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
1.67 cl 978: fownsignal(tp->tun_pgid, SIGIO, POLL_OUT,
979: POLLOUT|POLLWRNORM, NULL);
1.70 pk 980:
1.50 itojun 981: selwakeup(&tp->tun_rsel);
982: }
1.70 pk 983: simple_unlock(&tp->tun_lock);
1.50 itojun 984: }
985: #endif /* ALTQ */
1.1 cgd 986: /*
1.27 mycroft 987: * tunpoll - the poll interface, this is only useful on reads
1.6 deraadt 988: * really. The write detect always returns true, write never blocks
989: * anyway, it either accepts the packet or drops it.
990: */
991: int
1.78 thorpej 992: tunpoll(dev_t dev, int events, struct lwp *l)
1.6 deraadt 993: {
1.46 atatat 994: struct tun_softc *tp;
995: struct ifnet *ifp;
996: int s, revents = 0;
997:
1.70 pk 998: s = splnet();
1.46 atatat 999: tp = tun_find_unit(dev);
1000:
1001: /* interface was "destroyed" already */
1002: if (tp == NULL)
1.70 pk 1003: goto out_nolock;
1.46 atatat 1004:
1005: ifp = &tp->tun_if;
1.6 deraadt 1006:
1.27 mycroft 1007: TUNDEBUG("%s: tunpoll\n", ifp->if_xname);
1.6 deraadt 1008:
1.35 veego 1009: if (events & (POLLIN | POLLRDNORM)) {
1.70 pk 1010: if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
1.27 mycroft 1011: TUNDEBUG("%s: tunpoll q=%d\n", ifp->if_xname,
1.24 thorpej 1012: ifp->if_snd.ifq_len);
1.27 mycroft 1013: revents |= events & (POLLIN | POLLRDNORM);
1014: } else {
1015: TUNDEBUG("%s: tunpoll waiting\n", ifp->if_xname);
1.77 christos 1016: selrecord(l, &tp->tun_rsel);
1.6 deraadt 1017: }
1.35 veego 1018: }
1.27 mycroft 1019:
1020: if (events & (POLLOUT | POLLWRNORM))
1021: revents |= events & (POLLOUT | POLLWRNORM);
1022:
1.70 pk 1023: simple_unlock(&tp->tun_lock);
1024: out_nolock:
1.6 deraadt 1025: splx(s);
1.27 mycroft 1026: return (revents);
1.56 jdolecek 1027: }
1028:
1029: static void
1030: filt_tunrdetach(struct knote *kn)
1031: {
1032: struct tun_softc *tp = kn->kn_hook;
1033: int s;
1034:
1035: s = splnet();
1.57 christos 1036: SLIST_REMOVE(&tp->tun_rsel.sel_klist, kn, knote, kn_selnext);
1.56 jdolecek 1037: splx(s);
1038: }
1039:
1040: static int
1041: filt_tunread(struct knote *kn, long hint)
1042: {
1043: struct tun_softc *tp = kn->kn_hook;
1044: struct ifnet *ifp = &tp->tun_if;
1045: struct mbuf *m;
1046: int s;
1047:
1048: s = splnet();
1049: IF_POLL(&ifp->if_snd, m);
1050: if (m == NULL) {
1051: splx(s);
1052: return (0);
1053: }
1054:
1055: for (kn->kn_data = 0; m != NULL; m = m->m_next)
1056: kn->kn_data += m->m_len;
1057:
1058: splx(s);
1059: return (1);
1060: }
1061:
1062: static const struct filterops tunread_filtops =
1063: { 1, NULL, filt_tunrdetach, filt_tunread };
1064:
1065: static const struct filterops tun_seltrue_filtops =
1066: { 1, NULL, filt_tunrdetach, filt_seltrue };
1067:
1068: int
1069: tunkqfilter(dev_t dev, struct knote *kn)
1070: {
1.70 pk 1071: struct tun_softc *tp;
1.56 jdolecek 1072: struct klist *klist;
1.70 pk 1073: int rv = 0, s;
1074:
1075: s = splnet();
1076: tp = tun_find_unit(dev);
1077: if (tp == NULL)
1078: goto out_nolock;
1.56 jdolecek 1079:
1080: switch (kn->kn_filter) {
1081: case EVFILT_READ:
1.57 christos 1082: klist = &tp->tun_rsel.sel_klist;
1.56 jdolecek 1083: kn->kn_fop = &tunread_filtops;
1084: break;
1085:
1086: case EVFILT_WRITE:
1.57 christos 1087: klist = &tp->tun_rsel.sel_klist;
1.56 jdolecek 1088: kn->kn_fop = &tun_seltrue_filtops;
1089: break;
1090:
1091: default:
1.70 pk 1092: rv = 1;
1093: goto out;
1.56 jdolecek 1094: }
1095:
1096: kn->kn_hook = tp;
1097:
1098: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1.70 pk 1099:
1100: out:
1101: simple_unlock(&tp->tun_lock);
1102: out_nolock:
1.56 jdolecek 1103: splx(s);
1.70 pk 1104: return (rv);
1.1 cgd 1105: }
CVSweb <webmaster@jp.NetBSD.org>