386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / net / if_tun.c
CommitLineData
672837a0
WJ
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@sics.se
15 *
16 * $Header: if_tun.c,v 1.13 88/07/11 08:28:51 jpo Exp $
17 *
18 * $Log: if_tun.c,v $
19 * Revision 1.13 88/07/11 08:28:51 jpo
20 * Some tidying up
21 *
22 * Revision 1.12 87/12/10 09:16:29 jpo
23 * Decided the vax/mtpr was unnecessay.
24 *
25 * Revision 1.11 87/12/10 09:10:36 jpo
26 * Fixed some minor things & 1 major bug.
27 *
28 * Revision 1.10 87/11/04 14:27:41 jpo
29 * A few sanity checks added.
30 *
31 * Revision 1.9 87/11/04 14:13:45 jpo
32 * Added some ioctls for non-blocking & async I/O
33 *
34 * Revision 1.8 87/10/19 10:28:14 jpo
35 * Another touch up (sigh)
36 *
37 * Revision 1.7 87/10/19 10:25:48 jpo
38 * Touch up.
39 *
40 * Revision 1.6 87/10/19 09:15:14 jpo
41 * Touch up.
42 *
43 * Revision 1.5 87/10/19 08:34:51 jpo
44 * General clean up - plus sun specific fixes
45 *
46 * Revision 1.4 87/10/16 17:10:12 jpo
47 * Purged all ioctl read/writes and non-standard routing stuff.
48 *
49 * Revision 1.3 87/10/05 11:57:09 jpo
50 * More debugging - in error mainly.
51 *
52 * Revision 1.2 87/10/04 18:29:45 jpo
53 * Select & read/write working.
54 */
55
56#include "tun.h"
57#if NTUN > 0
58
59/*
60 * Tunnel driver.
61 *
62 * This driver takes packets off the IP i/f and hands them up to a
63 * user process to have it's wicked way with. This driver has it's
64 * roots in a similar driver written by Phil Cockcroft (formerly) at
65 * UCL. This driver is based much more on read/write/select mode of
66 * operation though.
67 *
68 * Julian Onions <jpo@cs.nott.ac.uk>
69 * Nottingham University 1987.
70 */
71
72#include "param.h"
73#include "systm.h"
74#include "mbuf.h"
75#include "buf.h"
76#include "protosw.h"
77#include "socket.h"
78#include "ioctl.h"
79#include "errno.h"
80#include "syslog.h"
81
82#include "net/if.h"
83#include "net/netisr.h"
84#include "net/route.h"
85
86#ifdef INET
87#include "netinet/in.h"
88#include "netinet/in_systm.h"
89#include "netinet/in_var.h"
90#include "netinet/ip.h"
91#include "netinet/if_ether.h"
92#endif
93
94#ifdef NS
95#include "netns/ns.h"
96#include "netns/ns_if.h"
97#endif
98
99#define TUNDEBUG if (tundebug) printf
100
101int tundebug = 0;
102struct tunctl
103{
104 u_short tun_flags; /* misc flags */
105 struct ifnet tun_if; /* the interface */
106 int tun_pgrp; /* the process group - if any */
107 struct proc *tun_rsel; /* read select */
108 struct proc *tun_wsel; /* write select (not used) */
109} tunctl[NTUN];
110
111extern int ifqmaxlen;
112
113int tunoutput (), tunioctl (), tuninit ();
114
115/* tunnel open - must be superuser & the device must be configured in */
116tunopen (dev, flag)
117dev_t dev;
118{
119 register int unit;
120 struct tunctl *tp;
121 register struct ifnet *ifp;
122
123 if (!suser ())
124 return EACCES;
125 if ((unit = minor (dev)) >= NTUN)
126 return (ENXIO);
127 tp = &tunctl[unit];
128 if (tp->tun_flags & TUN_OPEN)
129 return ENXIO;
130 if ((tp->tun_flags & TUN_INITED) == 0) {
131 tp->tun_flags = TUN_INITED;
132 tunattach (unit);
133 }
134 ifp = &tp->tun_if;
135 tp->tun_flags |= TUN_OPEN;
136 TUNDEBUG ("%s%d: open\n", ifp->if_name, ifp->if_unit);
137 return (0);
138}
139
140/* tunclose - close the device - mark i/f down & delete routing info */
141tunclose (dev, flag)
142dev_t dev;
143{
144 int s;
145 int rcoll;
146 register int unit = minor (dev);
147 register struct tunctl *tp = &tunctl[unit];
148 register struct ifnet *ifp = &tp->tun_if;
149 register struct mbuf *m;
150
151 rcoll = tp->tun_flags & TUN_RCOLL;
152 tp->tun_flags &= TUN_INITED;
153
154 /*
155 * junk all pending output
156 */
157 do {
158 s = splimp ();
159 IF_DEQUEUE (&ifp->if_snd, m);
160 splx (s);
161 if (m) /* actually - m_freem checks this - but what the hell */
162 m_freem (m);
163 } while (m != 0);
164 if (ifp->if_flags & IFF_UP) {
165 s = splimp ();
166 if_down (ifp);
167 if (ifp->if_flags & IFF_RUNNING)
168 rtinit (ifp->if_addrlist, (int)SIOCDELRT, RTF_HOST);
169 splx (s);
170 }
171 tp -> tun_pgrp = 0;
172 if (tp -> tun_rsel)
173 selwakeup (tp->tun_rsel, rcoll);
174
175 tp -> tun_rsel = tp -> tun_wsel = (struct proc *)0;
176
177 TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
178 return (0);
179}
180
181/*
182 * attach an interface N.B. argument is not same as other drivers
183 */
184int
185tunattach (unit)
186int unit;
187{
188 register struct ifnet *ifp = &tunctl[unit].tun_if;
189 register struct sockaddr_in *sin;
190
191 ifp->if_unit = unit;
192 ifp->if_name = "tun";
193 ifp->if_mtu = TUNMTU;
194 ifp->if_ioctl = tunioctl;
195 ifp->if_output = tunoutput;
196 ifp->if_init = tuninit;
197#ifndef BSD4_3
198 sin = (struct sockaddr_in *) & ifp->if_addr;
199 sin->sin_family = AF_INET;
200#endif
201 ifp->if_flags = IFF_POINTOPOINT;
202 ifp->if_snd.ifq_maxlen = ifqmaxlen;
203 ifp->if_collisions = ifp->if_ierrors = ifp->if_oerrors = 0;
204 ifp->if_ipackets = ifp->if_opackets = 0;
205 if_attach (ifp);
206 TUNDEBUG ("%s%d: tunattach\n", ifp->if_name, ifp->if_unit);
207 return 0;
208}
209
210int
211tuninit (unit)
212int unit;
213{
214 register struct tunctl *tp = &tunctl[unit];
215 register struct ifnet *ifp = &tp->tun_if;
216#ifndef BSD4_3
217 register struct sockaddr_in *sin;
218
219 sin = (struct sockaddr_in *) & ifp->if_addr;
220 if (sin->sin_addr.s_addr == 0) /* if address still unknown */
221 return;
222 if_rtinit (ifp, RTF_UP);
223#endif
224 ifp->if_flags |= IFF_UP | IFF_RUNNING;
225 tp->tun_flags |= TUN_IASET;
226 TUNDEBUG ("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
227 return 0;
228}
229
230/*
231 * Process an ioctl request.
232 * The problem here is 4.2 pass a struct ifreq * to this routine,
233 * sun only passes a struct sockaddr * since 3.2 at least. This is
234 * rather upsetting! Also, sun doesn't pass the SIOCDSTADDR ioctl through
235 * so we can't detect this being set directly. This is the reason for
236 * tuncheckready.
237 * Under 4.3 and SunOs 4.0 we now get the SIOCSIFDSTADDR ioctl, and we get a
238 * struct in_ifaddr * for data. (tte)
239 */
240
241#if !defined(BSD4_3) && defined(sun)
242
243/*
244 * workaround for not being able to detect DSTADDR being set.
245 */
246
247tuncheckready (ifp)
248struct ifnet *ifp;
249{
250 struct tunctl *tp = &tunctl[ifp->if_unit];
251 struct sockaddr_in *sin;
252
253 sin = (struct sockaddr_in *) &ifp->if_dstaddr;
254 if (sin->sin_addr.s_addr == 0)
255 return 0;
256 tp -> tun_flags |= TUN_DSTADDR;
257 return 1;
258}
259#else
260#define tuncheckready(dummy) 1
261#endif /* !defined(BSD4_3) && defined(sun) */
262
263int
264tunioctl (ifp, cmd, data)
265register struct ifnet *ifp;
266int cmd;
267caddr_t data;
268{
269#ifndef BSD4_3
270#ifdef sun
271 struct sockaddr_in *sin = (struct sockaddr_in *) data;
272#else
273 struct sockaddr_in *sin;
274 struct ifreq *ifr = (struct ifreq *) data;
275#endif
276#endif /* BSD4_3 */
277
278 int s = splimp (), error = 0;
279 struct tunctl *tp = &tunctl[ifp->if_unit];
280
281 switch (cmd)
282 {
283 case SIOCSIFADDR:
284#ifndef BSD4_3
285 if (ifp->if_flags & IFF_RUNNING)
286 if_rtinit (ifp, -1); /* delete previous route */
287#ifndef sun
288 sin = (struct sockaddr_in *)&ifr -> ifr_addr;
289#endif
290 ifp->if_addr = *((struct sockaddr *) sin);
291 ifp->if_net = in_netof (sin->sin_addr);
292 ifp->if_host[0] = in_lnaof (sin->sin_addr);
293#endif
294 tuninit (ifp->if_unit);
295 break;
296 case SIOCSIFDSTADDR:
297 tp->tun_flags |= TUN_DSTADDR;
298#ifndef BSD4_3
299#ifndef sun
300 sin = (struct sockaddr_in *)&ifr -> ifr_addr;
301#endif
302 ifp->if_dstaddr = *((struct sockaddr *)sin);
303#endif BSD4_3
304 TUNDEBUG ("%s%d: destination addres set\n", ifp->if_name,
305 ifp -> if_unit);
306 break;
307 default:
308 error = EINVAL;
309 }
310 splx (s);
311 return (error);
312}
313
314/*
315 * tunoutput - queue packets from higher level ready to put out.
316 */
317tunoutput (ifp, m0, dst)
318struct ifnet *ifp;
319struct mbuf *m0;
320struct sockaddr *dst;
321{
322 struct tunctl *tp;
323 struct proc *p;
324 int s;
325
326 TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
327 tp = &tunctl[ifp->if_unit];
328 if ((tp->tun_flags & TUN_READY) != TUN_READY) {
329 if(tuncheckready(ifp) == 0) {
330 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
331 ifp->if_unit, tp->tun_flags);
332 m_freem (m0);
333 return EHOSTDOWN;
334 }
335 }
336
337 switch (dst->sa_family) {
338#ifdef INET
339 case AF_INET:
340 s = splimp ();
341 if (IF_QFULL (&ifp->if_snd))
342 {
343 IF_DROP (&ifp->if_snd);
344 m_freem (m0);
345 splx (s);
346 ifp->if_collisions++;
347 return (ENOBUFS);
348 }
349 IF_ENQUEUE (&ifp->if_snd, m0);
350 splx (s);
351 ifp->if_opackets++;
352 break;
353#endif
354 default:
355 m_freem (m0);
356 return EAFNOSUPPORT;
357 }
358
359 if (tp->tun_flags & TUN_RWAIT) {
360 tp->tun_flags &= ~TUN_RWAIT;
361 wakeup ((caddr_t) tp);
362 }
363 if (tp->tun_flags & TUN_ASYNC && tp -> tun_pgrp != 0) {
364 if (tp->tun_pgrp > 0)
365 gsignal (tp->tun_pgrp, SIGIO);
366 else if ((p = pfind (-tp->tun_pgrp)) != 0)
367 psignal (p, SIGIO);
368 }
369 if (tp->tun_rsel) {
370 selwakeup (tp->tun_rsel, tp->tun_flags & TUN_RCOLL);
371 tp->tun_flags &= ~TUN_RCOLL;
372 tp->tun_rsel = (struct proc *) 0;
373 }
374 return 0;
375}
376
377/*
378 * the cdevsw interface is now pretty minimal.
379 */
380
381tuncioctl (dev, cmd, data, flag)
382dev_t dev;
383caddr_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 */
438tunread (dev, uio)
439dev_t dev;
440struct 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
497tunwrite (dev, uio)
498int dev;
499struct 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 = &top;
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 */
573tunselect (dev, rw)
574dev_t dev;
575int 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 if (tp->tun_rsel && tp->tun_rsel->p_wchan ==
592 (caddr_t) & selwait)
593 tp->tun_flags |= TUN_RCOLL;
594 else
595 tp->tun_rsel = u.u_procp;
596 break;
597 case FWRITE:
598 splx (s);
599 return 1;
600 }
601 splx (s);
602 TUNDEBUG ("%s%d: tunselect waiting\n", ifp->if_name, ifp->if_unit);
603 return 0;
604}
605#endif NTUN