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