]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $ */ | |
23 | ||
24 | /* | |
25 | * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> | |
26 | * Nottingham University 1987. | |
27 | * | |
28 | * This source may be freely distributed, however I would be interested | |
29 | * in any changes that are made. | |
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 it's | |
33 | * roots in a similar driver written by Phil Cockcroft (formerly) at | |
34 | * UCL. This driver is based much more on read/write/poll mode of | |
35 | * operation though. | |
36 | */ | |
37 | ||
38 | #include "tun.h" | |
39 | #if NTUN > 0 | |
40 | ||
41 | #include "opt_devfs.h" | |
42 | #include "opt_inet.h" | |
43 | ||
44 | #include <sys/param.h> | |
45 | #include <sys/proc.h> | |
46 | #include <sys/systm.h> | |
47 | #include <sys/mbuf.h> | |
48 | #include <sys/socket.h> | |
49 | #include <sys/filio.h> | |
50 | #include <sys/sockio.h> | |
51 | #include <sys/ttycom.h> | |
52 | #include <sys/poll.h> | |
53 | #include <sys/signalvar.h> | |
54 | #include <sys/filedesc.h> | |
55 | #include <sys/kernel.h> | |
56 | #include <sys/sysctl.h> | |
57 | #if DEVFS | |
58 | #include <sys/devfsext.h> | |
59 | #endif /*DEVFS*/ | |
60 | #include <sys/conf.h> | |
61 | #include <sys/uio.h> | |
62 | #include <sys/vnode.h> | |
63 | ||
64 | #include <net/if.h> | |
65 | #include <net/if_types.h> | |
66 | #include <net/netisr.h> | |
67 | #include <net/route.h> | |
68 | ||
69 | #if INET | |
70 | #include <netinet/in.h> | |
71 | #include <netinet/in_var.h> | |
72 | #endif | |
73 | ||
74 | #if INET6 | |
75 | #include <netinet/ip6.h> | |
76 | #include <netinet6/ip6_var.h> | |
77 | #include <netinet6/in6_ifattach.h> | |
78 | #endif /* INET6 */ | |
79 | ||
80 | #if NS | |
81 | #include <netns/ns.h> | |
82 | #include <netns/ns_if.h> | |
83 | #endif | |
84 | ||
85 | #include "bpfilter.h" | |
86 | #if NBPFILTER > 0 | |
87 | #include <net/bpf.h> | |
88 | #endif | |
89 | ||
90 | #include <net/if_tunvar.h> | |
91 | #include <net/if_tun.h> | |
92 | ||
93 | static void tunattach __P((void *)); | |
94 | PSEUDO_SET(tunattach, if_tun); | |
95 | ||
96 | #define TUNDEBUG if (tundebug) printf | |
97 | static int tundebug = 0; | |
98 | SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, ""); | |
99 | ||
100 | static struct tun_softc tunctl[NTUN]; | |
101 | ||
102 | static int tunoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *, | |
103 | struct rtentry *rt)); | |
104 | static int tunifioctl __P((struct ifnet *, u_long, caddr_t)); | |
105 | static int tuninit __P((int, int, u_char)); | |
106 | ||
107 | static d_open_t tunopen; | |
108 | static d_close_t tunclose; | |
109 | static d_read_t tunread; | |
110 | static d_write_t tunwrite; | |
111 | static d_ioctl_t tunioctl; | |
112 | static d_poll_t tunpoll; | |
113 | ||
114 | #define CDEV_MAJOR 52 | |
115 | static struct cdevsw tun_cdevsw = { | |
116 | tunopen, tunclose, tunread, tunwrite, | |
117 | tunioctl, nullstop, noreset, nodevtotty, | |
118 | tunpoll, nommap, nostrategy, "tun", NULL, -1 | |
119 | }; | |
120 | ||
121 | ||
122 | static int tun_devsw_installed; | |
123 | #if DEVFS | |
124 | static void *tun_devfs_token[NTUN]; | |
125 | #endif | |
126 | ||
127 | #define minor_val(n) ((((n) & ~0xff) << 8) | ((n) & 0xff)) | |
128 | #define dev_val(n) (((n) >> 8) | ((n) & 0xff)) | |
129 | ||
130 | static void | |
131 | tunattach(dummy) | |
132 | void *dummy; | |
133 | { | |
134 | register int i; | |
135 | struct ifnet *ifp; | |
136 | dev_t dev; | |
137 | ||
138 | if ( tun_devsw_installed ) | |
139 | return; | |
140 | dev = makedev(CDEV_MAJOR, 0); | |
141 | cdevsw_add(&dev, &tun_cdevsw, NULL); | |
142 | tun_devsw_installed = 1; | |
143 | for ( i = 0; i < NTUN; i++ ) { | |
144 | #if DEVFS | |
145 | tun_devfs_token[i] = devfs_add_devswf(&tun_cdevsw, minor_val(i), | |
146 | DV_CHR, UID_UUCP, | |
147 | GID_DIALER, 0600, | |
148 | "tun%d", i); | |
149 | #endif | |
150 | tunctl[i].tun_flags = TUN_INITED; | |
151 | ||
152 | ifp = &tunctl[i].tun_if; | |
153 | ifp->if_unit = i; | |
154 | ifp->if_name = "tun"; | |
155 | ifp->if_family = APPLE_IF_FAM_TUN; | |
156 | ifp->if_mtu = TUNMTU; | |
157 | ifp->if_ioctl = tunifioctl; | |
158 | ifp->if_output = tunoutput; | |
159 | ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; | |
160 | ifp->if_type = IFT_PPP; /* necessary init value for IPv6 lladdr auto conf */ | |
161 | ifp->if_snd.ifq_maxlen = ifqmaxlen; | |
162 | if_attach(ifp); | |
163 | #if NBPFILTER > 0 | |
164 | bpfattach(ifp, DLT_NULL, sizeof(u_int)); | |
165 | #endif | |
166 | } | |
167 | } | |
168 | ||
169 | /* | |
170 | * tunnel open - must be superuser & the device must be | |
171 | * configured in | |
172 | */ | |
173 | static int | |
174 | tunopen(dev, flag, mode, p) | |
175 | dev_t dev; | |
176 | int flag, mode; | |
177 | struct proc *p; | |
178 | { | |
179 | struct ifnet *ifp; | |
180 | struct tun_softc *tp; | |
181 | register int unit, error; | |
182 | ||
183 | error = suser(p->p_ucred, &p->p_acflag); | |
184 | if (error) | |
185 | return (error); | |
186 | ||
187 | if ((unit = dev_val(minor(dev))) >= NTUN) | |
188 | return (ENXIO); | |
189 | tp = &tunctl[unit]; | |
190 | if (tp->tun_flags & TUN_OPEN) | |
191 | return EBUSY; | |
192 | ifp = &tp->tun_if; | |
193 | tp->tun_flags |= TUN_OPEN; | |
194 | TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit); | |
195 | return (0); | |
196 | } | |
197 | ||
198 | /* | |
199 | * tunclose - close the device - mark i/f down & delete | |
200 | * routing info | |
201 | */ | |
202 | static int | |
203 | tunclose(dev, foo, bar, p) | |
204 | dev_t dev; | |
205 | int foo; | |
206 | int bar; | |
207 | struct proc *p; | |
208 | { | |
209 | register int unit = dev_val(minor(dev)), s; | |
210 | struct tun_softc *tp = &tunctl[unit]; | |
211 | struct ifnet *ifp = &tp->tun_if; | |
212 | struct mbuf *m; | |
213 | ||
214 | tp->tun_flags &= ~TUN_OPEN; | |
215 | ||
216 | /* | |
217 | * junk all pending output | |
218 | */ | |
219 | do { | |
220 | s = splimp(); | |
221 | IF_DEQUEUE(&ifp->if_snd, m); | |
222 | splx(s); | |
223 | if (m) | |
224 | m_freem(m); | |
225 | } while (m); | |
226 | ||
227 | if (ifp->if_flags & IFF_UP) { | |
228 | s = splimp(); | |
229 | if_down(ifp); | |
230 | if (ifp->if_flags & IFF_RUNNING) { | |
231 | /* find internet addresses and delete routes */ | |
232 | register struct ifaddr *ifa; | |
233 | for (ifa = ifp->if_addrhead.tqh_first; ifa; | |
234 | ifa = ifa->ifa_link.tqe_next) { | |
235 | switch (ifa->ifa_addr->sa_family) { | |
236 | #if INET | |
237 | case AF_INET: | |
238 | #endif | |
239 | #if INET6 | |
240 | case AF_INET6: | |
241 | #endif | |
242 | rtinit(ifa, (int)RTM_DELETE, | |
243 | tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0); | |
244 | break; | |
245 | } | |
246 | } | |
247 | } | |
248 | splx(s); | |
249 | } | |
250 | ifp->if_flags &= ~IFF_RUNNING; | |
251 | funsetown(tp->tun_sigio); | |
1c79356b | 252 | selwakeup(&tp->tun_rsel); |
0b4e3aa0 | 253 | selthreadclear(&tp->tun_rsel); |
1c79356b A |
254 | |
255 | TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit); | |
256 | return (0); | |
257 | } | |
258 | ||
259 | static int | |
260 | tuninit(unit, cmd, af) | |
261 | int unit; | |
262 | int cmd; | |
263 | u_char af; | |
264 | { | |
265 | struct tun_softc *tp = &tunctl[unit]; | |
266 | struct ifnet *ifp = &tp->tun_if; | |
267 | register struct ifaddr *ifa; | |
268 | ||
269 | TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit); | |
270 | ||
271 | ifp->if_flags |= IFF_UP | IFF_RUNNING; | |
272 | getmicrotime(&ifp->if_lastchange); | |
273 | ||
274 | for (ifa = ifp->if_addrhead.tqh_first; ifa; | |
275 | ifa = ifa->ifa_link.tqe_next) { | |
276 | #if INET | |
277 | if (ifa->ifa_addr->sa_family == AF_INET) { | |
278 | struct sockaddr_in *si; | |
279 | ||
280 | si = (struct sockaddr_in *)ifa->ifa_addr; | |
281 | if (si && si->sin_addr.s_addr) | |
282 | tp->tun_flags |= TUN_IASET; | |
283 | ||
284 | si = (struct sockaddr_in *)ifa->ifa_dstaddr; | |
285 | if (si && si->sin_addr.s_addr) | |
286 | tp->tun_flags |= TUN_DSTADDR; | |
287 | } | |
288 | #endif | |
289 | } | |
290 | return 0; | |
291 | } | |
292 | ||
293 | /* | |
294 | * Process an ioctl request. | |
295 | */ | |
296 | int | |
297 | tunifioctl(ifp, cmd, data) | |
298 | struct ifnet *ifp; | |
299 | u_long cmd; | |
300 | caddr_t data; | |
301 | { | |
302 | register struct ifreq *ifr = (struct ifreq *)data; | |
303 | int error = 0, s; | |
304 | ||
305 | s = splimp(); | |
306 | switch(cmd) { | |
307 | case SIOCSIFADDR: | |
308 | tuninit(ifp->if_unit); | |
309 | TUNDEBUG("%s%d: address set\n", | |
310 | ifp->if_name, ifp->if_unit); | |
311 | break; | |
312 | case SIOCSIFDSTADDR: | |
313 | #if 0 | |
314 | #if defined(INET6) && defined(__FreeBSD__) && __FreeBSD__ >= 3 | |
315 | if (found_first_ifid == 0) | |
316 | in6_ifattach_noifid(ifp); | |
317 | #endif /* defined(INET6) && defined(__FreeBSD__) && __FreeBSD__ >= 3 */ | |
318 | #endif | |
319 | tuninit(ifp->if_unit, cmd, ifr->ifr_addr.sa_family); | |
320 | break; | |
321 | case SIOCSIFMTU: | |
322 | ifp->if_mtu = ifr->ifr_mtu; | |
323 | TUNDEBUG("%s%d: mtu set\n", | |
324 | ifp->if_name, ifp->if_unit); | |
325 | break; | |
326 | case SIOCADDMULTI: | |
327 | case SIOCDELMULTI: | |
328 | break; | |
329 | ||
330 | case SIOCSIFFLAGS: | |
331 | if ((ifp->if_flags & IFF_UP) != 0) | |
332 | ifp->if_flags |= IFF_RUNNING; | |
333 | else if ((ifp->if_flags & IFF_UP) == 0) | |
334 | ifp->if_flags &= ~IFF_RUNNING; | |
335 | break; | |
336 | ||
337 | default: | |
338 | error = EINVAL; | |
339 | } | |
340 | splx(s); | |
341 | return (error); | |
342 | } | |
343 | ||
344 | /* | |
345 | * tunoutput - queue packets from higher level ready to put out. | |
346 | */ | |
347 | /* Packet data format between tun and ppp is changed to enable checking of | |
348 | * Address Family of sending packet. When INET6 is defined, 4byte AF field | |
349 | * is appended to packet data as following. | |
350 | * | |
351 | * 0 1 2 3 4 5 6 7 8 ..... | |
352 | * ------------------------------ | |
353 | * | af | packet data ..... | |
354 | * ------------------------------ | |
355 | * ^^^^^^^^^^^^^ | |
356 | * Newly added part. The size is sizeof(u_long). | |
357 | * | |
358 | * However, this is not adopted for tun -> ppp AF_INET packet for | |
359 | * backword compatibility, because the ppp process may be an existing | |
360 | * ip only supporting one. | |
361 | * Also in ppp->tun case, when af value is unknown, (af > 255) is checked and | |
362 | * if it is true, AF_INET is assumed. (the 4byte may be the head of | |
363 | * AF_INET packet. Despite the byte order, the value must always be | |
364 | * greater than 255, because of ip_len field or (ip_v and ip_hl) | |
365 | * field. (Idea from Mr. Noritoshi Demize) | |
366 | */ | |
367 | int | |
368 | tunoutput(ifp, m0, dst, rt) | |
369 | struct ifnet *ifp; | |
370 | struct mbuf *m0; | |
371 | struct sockaddr *dst; | |
372 | struct rtentry *rt; | |
373 | { | |
374 | struct tun_softc *tp = &tunctl[ifp->if_unit]; | |
375 | int s; | |
376 | ||
377 | TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit); | |
378 | ||
379 | if ((tp->tun_flags & TUN_READY) != TUN_READY) { | |
380 | TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, | |
381 | ifp->if_unit, tp->tun_flags); | |
382 | m_freem (m0); | |
383 | return EHOSTDOWN; | |
384 | } | |
385 | ||
386 | #if NBPFILTER > 0 | |
387 | /* BPF write needs to be handled specially */ | |
388 | if (dst->sa_family == AF_UNSPEC) { | |
389 | dst->sa_family = *(mtod(m0, int *)); | |
390 | m0->m_len -= sizeof(int); | |
391 | m0->m_pkthdr.len -= sizeof(int); | |
392 | m0->m_data += sizeof(int); | |
393 | } | |
394 | ||
395 | if (ifp->if_bpf) { | |
396 | /* | |
397 | * We need to prepend the address family as | |
398 | * a four byte field. Cons up a dummy header | |
399 | * to pacify bpf. This is safe because bpf | |
400 | * will only read from the mbuf (i.e., it won't | |
401 | * try to free it or keep a pointer to it). | |
402 | */ | |
403 | struct mbuf m; | |
404 | u_int af = dst->sa_family; | |
405 | ||
406 | m.m_next = m0; | |
407 | m.m_len = 4; | |
408 | m.m_data = (char *)⁡ | |
409 | ||
410 | bpf_mtap(ifp, &m); | |
411 | } | |
412 | #endif | |
413 | ||
414 | switch(dst->sa_family) { | |
415 | #if defined(INET) || defined(INET6) | |
416 | #if INET6 | |
417 | case AF_INET6: | |
418 | M_PREPEND(m0, sizeof(u_long) /* af field passed to upper */, | |
419 | M_DONTWAIT); | |
420 | if (m0 == 0) | |
421 | return (ENOBUFS); | |
422 | *mtod(m0, u_long *) = (u_long)dst->sa_family; | |
423 | /* FALLTHROUGH */ | |
424 | #endif /* INET6 */ | |
425 | #if INET | |
426 | case AF_INET: | |
427 | #endif /* INET */ | |
428 | #endif /* INET || INET6 */ | |
429 | s = splimp(); | |
430 | if (IF_QFULL(&ifp->if_snd)) { | |
431 | IF_DROP(&ifp->if_snd); | |
432 | m_freem(m0); | |
433 | splx(s); | |
434 | ifp->if_collisions++; | |
435 | return (ENOBUFS); | |
436 | } | |
437 | ifp->if_obytes += m0->m_pkthdr.len; | |
438 | IF_ENQUEUE(&ifp->if_snd, m0); | |
439 | splx(s); | |
440 | ifp->if_opackets++; | |
441 | break; | |
442 | default: | |
443 | m_freem(m0); | |
444 | return EAFNOSUPPORT; | |
445 | } | |
446 | ||
447 | if (tp->tun_flags & TUN_RWAIT) { | |
448 | tp->tun_flags &= ~TUN_RWAIT; | |
449 | wakeup((caddr_t)tp); | |
450 | } | |
451 | if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) | |
452 | pgsigio(tp->tun_sigio, SIGIO, 0); | |
1c79356b | 453 | selwakeup(&tp->tun_rsel); |
1c79356b A |
454 | return 0; |
455 | } | |
456 | ||
457 | /* | |
458 | * the cdevsw interface is now pretty minimal. | |
459 | */ | |
460 | static int | |
461 | tunioctl(dev, cmd, data, flag, p) | |
462 | dev_t dev; | |
463 | u_long cmd; | |
464 | caddr_t data; | |
465 | int flag; | |
466 | struct proc *p; | |
467 | { | |
468 | int unit = dev_val(minor(dev)), s; | |
469 | struct tun_softc *tp = &tunctl[unit]; | |
470 | struct tuninfo *tunp; | |
471 | ||
472 | switch (cmd) { | |
473 | case TUNSIFINFO: | |
474 | tunp = (struct tuninfo *)data; | |
475 | tp->tun_if.if_mtu = tunp->mtu; | |
476 | tp->tun_if.if_type = tunp->type; | |
477 | tp->tun_if.if_baudrate = tunp->baudrate; | |
478 | break; | |
479 | case TUNGIFINFO: | |
480 | tunp = (struct tuninfo *)data; | |
481 | tunp->mtu = tp->tun_if.if_mtu; | |
482 | tunp->type = tp->tun_if.if_type; | |
483 | tunp->baudrate = tp->tun_if.if_baudrate; | |
484 | break; | |
485 | case TUNSDEBUG: | |
486 | tundebug = *(int *)data; | |
487 | break; | |
488 | case TUNGDEBUG: | |
489 | *(int *)data = tundebug; | |
490 | break; | |
491 | case FIONBIO: | |
492 | break; | |
493 | case FIOASYNC: | |
494 | if (*(int *)data) | |
495 | tp->tun_flags |= TUN_ASYNC; | |
496 | else | |
497 | tp->tun_flags &= ~TUN_ASYNC; | |
498 | break; | |
499 | case FIONREAD: | |
500 | s = splimp(); | |
501 | if (tp->tun_if.if_snd.ifq_head) { | |
502 | struct mbuf *mb = tp->tun_if.if_snd.ifq_head; | |
503 | for( *(int *)data = 0; mb != 0; mb = mb->m_next) | |
504 | *(int *)data += mb->m_len; | |
505 | } else | |
506 | *(int *)data = 0; | |
507 | splx(s); | |
508 | break; | |
509 | case FIOSETOWN: | |
510 | return (fsetown(*(int *)data, &tp->tun_sigio)); | |
511 | ||
512 | case FIOGETOWN: | |
513 | *(int *)data = fgetown(tp->tun_sigio); | |
514 | return (0); | |
515 | ||
516 | /* This is deprecated, FIOSETOWN should be used instead. */ | |
517 | case TIOCSPGRP: | |
518 | return (fsetown(-(*(int *)data), &tp->tun_sigio)); | |
519 | ||
520 | /* This is deprecated, FIOGETOWN should be used instead. */ | |
521 | case TIOCGPGRP: | |
522 | *(int *)data = -fgetown(tp->tun_sigio); | |
523 | return (0); | |
524 | ||
525 | default: | |
526 | return (ENOTTY); | |
527 | } | |
528 | return (0); | |
529 | } | |
530 | ||
531 | /* | |
532 | * The cdevsw read interface - reads a packet at a time, or at | |
533 | * least as much of a packet as can be read. | |
534 | */ | |
535 | static int | |
536 | tunread(dev, uio, flag) | |
537 | dev_t dev; | |
538 | struct uio *uio; | |
539 | int flag; | |
540 | { | |
541 | int unit = dev_val(minor(dev)); | |
542 | struct tun_softc *tp = &tunctl[unit]; | |
543 | struct ifnet *ifp = &tp->tun_if; | |
544 | struct mbuf *m, *m0; | |
545 | int error=0, len, s; | |
546 | ||
547 | TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit); | |
548 | if ((tp->tun_flags & TUN_READY) != TUN_READY) { | |
549 | TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name, | |
550 | ifp->if_unit, tp->tun_flags); | |
551 | return EHOSTDOWN; | |
552 | } | |
553 | ||
554 | tp->tun_flags &= ~TUN_RWAIT; | |
555 | ||
556 | s = splimp(); | |
557 | do { | |
558 | IF_DEQUEUE(&ifp->if_snd, m0); | |
559 | if (m0 == 0) { | |
560 | if (flag & IO_NDELAY) { | |
561 | splx(s); | |
562 | return EWOULDBLOCK; | |
563 | } | |
564 | tp->tun_flags |= TUN_RWAIT; | |
565 | if( error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1), | |
566 | "tunread", 0)) { | |
567 | splx(s); | |
568 | return error; | |
569 | } | |
570 | } | |
571 | } while (m0 == 0); | |
572 | splx(s); | |
573 | ||
574 | while (m0 && uio->uio_resid > 0 && error == 0) { | |
575 | len = min(uio->uio_resid, m0->m_len); | |
576 | if (len == 0) | |
577 | break; | |
578 | error = uiomove(mtod(m0, caddr_t), len, uio); | |
579 | MFREE(m0, m); | |
580 | m0 = m; | |
581 | } | |
582 | ||
583 | if (m0) { | |
584 | TUNDEBUG("Dropping mbuf\n"); | |
585 | m_freem(m0); | |
586 | } | |
587 | return error; | |
588 | } | |
589 | ||
590 | /* | |
591 | * the cdevsw write interface - an atomic write is a packet - or else! | |
592 | */ | |
593 | /* See top of tunoutput() about interface change between ppp process and | |
594 | * tun. */ | |
595 | static int | |
596 | tunwrite(dev, uio, flag) | |
597 | dev_t dev; | |
598 | struct uio *uio; | |
599 | int flag; | |
600 | { | |
601 | int unit = dev_val(minor(dev)); | |
602 | struct ifnet *ifp = &tunctl[unit].tun_if; | |
603 | struct mbuf *top, **mp, *m; | |
604 | int error=0, s, tlen, mlen; | |
605 | u_long af; | |
606 | u_int netisr_af; | |
607 | struct ifqueue *afintrq = NULL; | |
608 | ||
609 | TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit); | |
610 | ||
611 | if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) { | |
612 | TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit, | |
613 | uio->uio_resid); | |
614 | return EIO; | |
615 | } | |
616 | tlen = uio->uio_resid; | |
617 | ||
618 | /* get a header mbuf */ | |
619 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
620 | if (m == NULL) | |
621 | return ENOBUFS; | |
622 | if (tlen > MHLEN) { | |
623 | MCLGET(m, M_DONTWAIT); | |
624 | if ((m->m_flags & M_EXT) == 0) { | |
625 | m_free(m); | |
626 | return ENOBUFS; | |
627 | } | |
628 | mlen = m->m_ext.ext_size; | |
629 | } else | |
630 | mlen = MHLEN; | |
631 | ||
632 | top = 0; | |
633 | mp = ⊤ | |
634 | while (error == 0 && uio->uio_resid > 0) { | |
635 | m->m_len = min(mlen, uio->uio_resid); | |
636 | error = uiomove(mtod (m, caddr_t), m->m_len, uio); | |
637 | *mp = m; | |
638 | mp = &m->m_next; | |
639 | if (uio->uio_resid > 0) { | |
640 | MGET (m, M_DONTWAIT, MT_DATA); | |
641 | if (m == 0) { | |
642 | error = ENOBUFS; | |
643 | break; | |
644 | } | |
645 | mlen = MLEN; | |
646 | } | |
647 | } | |
648 | /* Change for checking Address Family of sending packet. */ | |
649 | af = *mtod(top, u_long *); | |
650 | switch (af) { | |
651 | #if INET | |
652 | case AF_INET: | |
653 | netisr_af = NETISR_IP; | |
654 | afintrq = &ipintrq; | |
655 | break; | |
656 | #endif /* INET */ | |
657 | #if INET6 | |
658 | case AF_INET6: | |
659 | netisr_af = NETISR_IPV6; | |
660 | afintrq = &ip6intrq; | |
661 | break; | |
662 | #endif /* INET6 */ | |
663 | default: | |
664 | if (af > 255) { /* see description at the top of tunoutput */ | |
665 | af = AF_INET; | |
666 | netisr_af = NETISR_IP; | |
667 | afintrq = &ipintrq; | |
668 | goto af_decided; | |
669 | } | |
670 | error = EAFNOSUPPORT; | |
671 | break; | |
672 | } | |
673 | m_adj(top, sizeof(u_long)); /* remove af field passed from upper */ | |
674 | tlen -= sizeof(u_long); | |
675 | af_decided: | |
676 | if (error) { | |
677 | if (top) | |
678 | m_freem (top); | |
679 | return error; | |
680 | } | |
681 | ||
682 | top->m_pkthdr.len = tlen; | |
683 | top->m_pkthdr.rcvif = ifp; | |
684 | ||
685 | #if NBPFILTER > 0 | |
686 | if (ifp->if_bpf) { | |
687 | /* | |
688 | * We need to prepend the address family as | |
689 | * a four byte field. Cons up a dummy header | |
690 | * to pacify bpf. This is safe because bpf | |
691 | * will only read from the mbuf (i.e., it won't | |
692 | * try to free it or keep a pointer to it). | |
693 | */ | |
694 | struct mbuf m; | |
695 | ||
696 | m.m_next = top; | |
697 | m.m_len = 4; | |
698 | m.m_data = (char *)⁡ | |
699 | ||
700 | bpf_mtap(ifp, &m); | |
701 | } | |
702 | #endif | |
703 | ||
704 | /* just for safety */ | |
705 | if (!afintrq) | |
706 | return EAFNOSUPPORT; | |
707 | ||
708 | s = splimp(); | |
709 | if (IF_QFULL (afintrq)) { | |
710 | IF_DROP(afintrq); | |
711 | splx(s); | |
712 | ifp->if_collisions++; | |
713 | m_freem(top); | |
714 | return ENOBUFS; | |
715 | } | |
716 | IF_ENQUEUE(afintrq, top); | |
717 | splx(s); | |
718 | ifp->if_ibytes += tlen; | |
719 | ifp->if_ipackets++; | |
720 | schednetisr(netisr_af); | |
721 | return error; | |
722 | } | |
723 | ||
724 | /* | |
725 | * tunpoll - the poll interface, this is only useful on reads | |
726 | * really. The write detect always returns true, write never blocks | |
727 | * anyway, it either accepts the packet or drops it. | |
728 | */ | |
729 | static int | |
0b4e3aa0 | 730 | tunpoll(dev, events, wql, p) |
1c79356b A |
731 | dev_t dev; |
732 | int events; | |
0b4e3aa0 | 733 | void * wql; |
1c79356b A |
734 | struct proc *p; |
735 | { | |
736 | int unit = dev_val(minor(dev)), s; | |
737 | struct tun_softc *tp = &tunctl[unit]; | |
738 | struct ifnet *ifp = &tp->tun_if; | |
739 | int revents = 0; | |
740 | ||
741 | s = splimp(); | |
742 | TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit); | |
743 | ||
744 | if (events & (POLLIN | POLLRDNORM)) | |
745 | if (ifp->if_snd.ifq_len > 0) { | |
746 | TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name, | |
747 | ifp->if_unit, ifp->if_snd.ifq_len); | |
748 | revents |= events & (POLLIN | POLLRDNORM); | |
749 | } else { | |
750 | TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name, | |
751 | ifp->if_unit); | |
0b4e3aa0 | 752 | selrecord(p, &tp->tun_rsel, wql); |
1c79356b A |
753 | } |
754 | ||
755 | if (events & (POLLOUT | POLLWRNORM)) | |
756 | revents |= events & (POLLOUT | POLLWRNORM); | |
757 | ||
758 | splx(s); | |
759 | return (revents); | |
760 | } | |
761 | ||
762 | ||
763 | #endif /* NTUN */ |