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