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