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