if_gif.c revision 57903
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/net/if_gif.c 57903 2000-03-11 11:17:24Z shin $
30 */
31
32/*
33 * gif.c
34 */
35
36#include "opt_inet.h"
37#include "opt_inet6.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/malloc.h>
43#include <sys/mbuf.h>
44#include <sys/socket.h>
45#include <sys/sockio.h>
46#include <sys/errno.h>
47#include <sys/time.h>
48#include <sys/syslog.h>
49#include <machine/cpu.h>
50
51#include <net/if.h>
52#include <net/if_types.h>
53#include <net/netisr.h>
54#include <net/route.h>
55#include <net/bpf.h>
56
57#ifdef	INET
58#include <netinet/in.h>
59#include <netinet/in_systm.h>
60#include <netinet/in_var.h>
61#include <netinet/ip.h>
62#include <netinet/in_gif.h>
63#endif	/* INET */
64
65#ifdef INET6
66#ifndef INET
67#include <netinet/in.h>
68#endif
69#include <netinet6/in6_var.h>
70#include <netinet/ip6.h>
71#include <netinet6/ip6_var.h>
72#include <netinet6/in6_gif.h>
73#endif /* INET6 */
74
75#include <net/if_gif.h>
76
77#include "gif.h"
78
79#include <net/net_osdep.h>
80
81void gifattach __P((void *));
82
83/*
84 * gif global variable definitions
85 */
86int ngif = NGIF + 1;		/* number of interfaces. +1 for stf. */
87struct gif_softc *gif = 0;
88
89void
90gifattach(dummy)
91	void *dummy;
92{
93	register struct gif_softc *sc;
94	register int i;
95
96	gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAIT);
97	bzero(sc, ngif * sizeof(struct gif_softc));
98	for (i = 0; i < ngif - 1; sc++, i++) {  /* leave last one for stf */
99		sc->gif_if.if_name = "gif";
100		sc->gif_if.if_unit = i;
101		sc->gif_if.if_mtu    = GIF_MTU;
102		sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
103		sc->gif_if.if_ioctl  = gif_ioctl;
104		sc->gif_if.if_output = gif_output;
105		sc->gif_if.if_type   = IFT_GIF;
106		sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen;
107		if_attach(&sc->gif_if);
108		bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
109	}
110	sc->gif_if.if_name = "stf";
111	sc->gif_if.if_unit = 0;
112	sc->gif_if.if_mtu    = GIF_MTU;
113	sc->gif_if.if_flags  = IFF_MULTICAST;
114	sc->gif_if.if_ioctl  = gif_ioctl;
115	sc->gif_if.if_output = gif_output;
116	sc->gif_if.if_type   = IFT_GIF;
117	sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen;
118	if_attach(&sc->gif_if);
119	bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
120}
121
122PSEUDO_SET(gifattach, if_gif);
123
124int
125gif_output(ifp, m, dst, rt)
126	struct ifnet *ifp;
127	struct mbuf *m;
128	struct sockaddr *dst;
129	struct rtentry *rt;	/* added in net2 */
130{
131	register struct gif_softc *sc = (struct gif_softc*)ifp;
132	int error = 0;
133	static int called = 0;	/* XXX: MUTEX */
134	int calllimit = 10;	/* XXX: adhoc */
135
136	/*
137	 * gif may cause infinite recursion calls when misconfigured.
138	 * We'll prevent this by introducing upper limit.
139	 * XXX: this mechanism may introduce another problem about
140	 *      mutual exclusion of the variable CALLED, especially if we
141	 *      use kernel thread.
142	 */
143	if (++called >= calllimit) {
144		log(LOG_NOTICE,
145		    "gif_output: recursively called too many times(%d)\n",
146		    called);
147		m_freem(m);
148		error = EIO;	/* is there better errno? */
149		goto end;
150	}
151	getmicrotime(&ifp->if_lastchange);
152	m->m_flags &= ~(M_BCAST|M_MCAST);
153	if (!(ifp->if_flags & IFF_UP) ||
154	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
155		m_freem(m);
156		error = ENETDOWN;
157		goto end;
158	}
159
160	if (ifp->if_bpf) {
161		/*
162		 * We need to prepend the address family as
163		 * a four byte field.  Cons up a dummy header
164		 * to pacify bpf.  This is safe because bpf
165		 * will only read from the mbuf (i.e., it won't
166		 * try to free it or keep a pointer a to it).
167		 */
168		struct mbuf m0;
169		u_int af = dst->sa_family;
170
171		m0.m_next = m;
172		m0.m_len = 4;
173		m0.m_data = (char *)&af;
174
175		bpf_mtap(ifp, &m0);
176	}
177	ifp->if_opackets++;
178	ifp->if_obytes += m->m_pkthdr.len;
179
180	switch (sc->gif_psrc->sa_family) {
181#ifdef INET
182	case AF_INET:
183		error = in_gif_output(ifp, dst->sa_family, m, rt);
184		break;
185#endif
186#ifdef INET6
187	case AF_INET6:
188		error = in6_gif_output(ifp, dst->sa_family, m, rt);
189		break;
190#endif
191	default:
192		m_freem(m);
193		error = ENETDOWN;
194	}
195
196  end:
197	called = 0;		/* reset recursion counter */
198	if (error) ifp->if_oerrors++;
199	return error;
200}
201
202void
203gif_input(m, af, gifp)
204	struct mbuf *m;
205	int af;
206	struct ifnet *gifp;
207{
208	int s, isr;
209	register struct ifqueue *ifq = 0;
210
211	if (gifp == NULL) {
212		/* just in case */
213		m_freem(m);
214		return;
215	}
216
217	if (m->m_pkthdr.rcvif)
218		m->m_pkthdr.rcvif = gifp;
219
220	if (gifp->if_bpf) {
221		/*
222		 * We need to prepend the address family as
223		 * a four byte field.  Cons up a dummy header
224		 * to pacify bpf.  This is safe because bpf
225		 * will only read from the mbuf (i.e., it won't
226		 * try to free it or keep a pointer a to it).
227		 */
228		struct mbuf m0;
229		u_int af = AF_INET6;
230
231		m0.m_next = m;
232		m0.m_len = 4;
233		m0.m_data = (char *)&af;
234
235		bpf_mtap(gifp, &m0);
236	}
237
238	/*
239	 * Put the packet to the network layer input queue according to the
240	 * specified address family.
241	 * Note: older versions of gif_input directly called network layer
242	 * input functions, e.g. ip6_input, here. We changed the policy to
243	 * prevent too many recursive calls of such input functions, which
244	 * might cause kernel panic. But the change may introduce another
245	 * problem; if the input queue is full, packets are discarded.
246	 * We believed it rarely occurs and changed the policy. If we find
247	 * it occurs more times than we thought, we may change the policy
248	 * again.
249	 */
250	switch (af) {
251#ifdef INET
252	case AF_INET:
253		ifq = &ipintrq;
254		isr = NETISR_IP;
255		break;
256#endif
257#ifdef INET6
258	case AF_INET6:
259		ifq = &ip6intrq;
260		isr = NETISR_IPV6;
261		break;
262#endif
263	default:
264		m_freem(m);
265		return;
266	}
267
268	s = splimp();
269	if (IF_QFULL(ifq)) {
270		IF_DROP(ifq);	/* update statistics */
271		m_freem(m);
272		splx(s);
273		return;
274	}
275	IF_ENQUEUE(ifq, m);
276	/* we need schednetisr since the address family may change */
277	schednetisr(isr);
278	gifp->if_ipackets++;
279	gifp->if_ibytes += m->m_pkthdr.len;
280	splx(s);
281
282	return;
283}
284
285
286int
287gif_ioctl(ifp, cmd, data)
288	struct ifnet *ifp;
289	u_long cmd;
290	caddr_t data;
291{
292	struct gif_softc *sc  = (struct gif_softc*)ifp;
293	struct ifreq     *ifr = (struct ifreq*)data;
294	int error = 0, size;
295	struct sockaddr *sa, *dst, *src;
296
297	switch (cmd) {
298	case SIOCSIFADDR:
299		break;
300
301	case SIOCSIFDSTADDR:
302		break;
303
304	case SIOCADDMULTI:
305	case SIOCDELMULTI:
306		break;
307
308	case SIOCGIFMTU:
309		break;
310	case SIOCSIFMTU:
311		{
312			u_long mtu;
313			mtu = ifr->ifr_mtu;
314			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
315				return (EINVAL);
316			}
317			ifp->if_mtu = mtu;
318		}
319		break;
320
321	case SIOCSIFPHYADDR:
322#ifdef INET6
323	case SIOCSIFPHYADDR_IN6:
324#endif /* INET6 */
325		switch (ifr->ifr_addr.sa_family) {
326#ifdef INET
327		case AF_INET:
328			src = (struct sockaddr *)
329				&(((struct in_aliasreq *)data)->ifra_addr);
330			dst = (struct sockaddr *)
331				&(((struct in_aliasreq *)data)->ifra_dstaddr);
332
333			/* only one gif can have dst = INADDR_ANY */
334#define	satosaddr(sa) (((struct sockaddr_in *)(sa))->sin_addr.s_addr)
335
336#ifdef INET6
337			if (bcmp(ifp->if_name, "stf", 3) == 0)
338				satosaddr(dst) = INADDR_BROADCAST;
339#endif
340
341			if (satosaddr(dst) == INADDR_ANY) {
342				int i;
343				struct gif_softc *sc2;
344
345			  	for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
346					if (sc2 == sc) continue;
347					if (sc2->gif_pdst &&
348					    satosaddr(sc2->gif_pdst)
349						== INADDR_ANY) {
350					    error = EADDRNOTAVAIL;
351					    goto bad;
352					}
353				}
354			}
355			size = sizeof(struct sockaddr_in);
356			break;
357#endif /* INET */
358#ifdef INET6
359		case AF_INET6:
360			src = (struct sockaddr *)
361				&(((struct in6_aliasreq *)data)->ifra_addr);
362			dst = (struct sockaddr *)
363				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
364
365			/* only one gif can have dst = in6addr_any */
366#define	satoin6(sa) (&((struct sockaddr_in6 *)(sa))->sin6_addr)
367
368			if (IN6_IS_ADDR_UNSPECIFIED(satoin6(dst))) {
369				int i;
370				struct gif_softc *sc2;
371
372			  	for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
373					if (sc2 == sc) continue;
374					if (sc2->gif_pdst &&
375					    IN6_IS_ADDR_UNSPECIFIED(
376						satoin6(sc2->gif_pdst)
377								    )) {
378					    error = EADDRNOTAVAIL;
379					    goto bad;
380					}
381				}
382			}
383			size = sizeof(struct sockaddr_in6);
384			break;
385#endif /* INET6 */
386		default:
387			error = EPROTOTYPE;
388			goto bad;
389			break;
390		}
391		if (sc->gif_psrc != NULL)
392			free((caddr_t)sc->gif_psrc, M_IFADDR);
393		if (sc->gif_pdst != NULL)
394			free((caddr_t)sc->gif_pdst, M_IFADDR);
395
396		sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
397		bzero((caddr_t)sa, size);
398		bcopy((caddr_t)src, (caddr_t)sa, size);
399		sc->gif_psrc = sa;
400
401		sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
402		bzero((caddr_t)sa, size);
403		bcopy((caddr_t)dst, (caddr_t)sa, size);
404		sc->gif_pdst = sa;
405
406		ifp->if_flags |= (IFF_UP|IFF_RUNNING);
407		{
408			int s;
409
410			s = splnet();
411			if_up(ifp);		/* send up RTM_IFINFO */
412			splx(s);
413		}
414
415		break;
416
417	case SIOCGIFPSRCADDR:
418#ifdef INET6
419	case SIOCGIFPSRCADDR_IN6:
420#endif /* INET6 */
421		if (sc->gif_psrc == NULL) {
422			error = EADDRNOTAVAIL;
423			goto bad;
424		}
425		src = sc->gif_psrc;
426		switch (sc->gif_psrc->sa_family) {
427#ifdef INET
428		case AF_INET:
429			dst = &ifr->ifr_addr;
430			size = sizeof(struct sockaddr_in);
431			break;
432#endif /* INET */
433#ifdef INET6
434		case AF_INET6:
435			dst = (struct sockaddr *)
436				&(((struct in6_ifreq *)data)->ifr_addr);
437			size = sizeof(struct sockaddr_in6);
438			break;
439#endif /* INET6 */
440		default:
441			error = EADDRNOTAVAIL;
442			goto bad;
443		}
444		bcopy((caddr_t)src, (caddr_t)dst, size);
445		break;
446
447	case SIOCGIFPDSTADDR:
448#ifdef INET6
449	case SIOCGIFPDSTADDR_IN6:
450#endif /* INET6 */
451		if (sc->gif_pdst == NULL) {
452			error = EADDRNOTAVAIL;
453			goto bad;
454		}
455		src = sc->gif_pdst;
456		switch (sc->gif_pdst->sa_family) {
457#ifdef INET
458		case AF_INET:
459			dst = &ifr->ifr_addr;
460			size = sizeof(struct sockaddr_in);
461			break;
462#endif /* INET */
463#ifdef INET6
464		case AF_INET6:
465			dst = (struct sockaddr *)
466				&(((struct in6_ifreq *)data)->ifr_addr);
467			size = sizeof(struct sockaddr_in6);
468			break;
469#endif /* INET6 */
470		default:
471			error = EADDRNOTAVAIL;
472			goto bad;
473		}
474		bcopy((caddr_t)src, (caddr_t)dst, size);
475		break;
476
477	case SIOCSIFFLAGS:
478		break;
479
480	default:
481		error = EINVAL;
482		break;
483	}
484 bad:
485	return error;
486}
487