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