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