if_gif.c revision 57536
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 57536 2000-02-27 18:36:30Z 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;		/* number of interfaces */
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; sc++, i++) {
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}
111
112PSEUDO_SET(gifattach, if_gif);
113
114int
115gif_output(ifp, m, dst, rt)
116	struct ifnet *ifp;
117	struct mbuf *m;
118	struct sockaddr *dst;
119	struct rtentry *rt;	/* added in net2 */
120{
121	register struct gif_softc *sc = (struct gif_softc*)ifp;
122	int error = 0;
123	static int called = 0;	/* XXX: MUTEX */
124	int calllimit = 10;	/* XXX: adhoc */
125
126	/*
127	 * gif may cause infinite recursion calls when misconfigured.
128	 * We'll prevent this by introducing upper limit.
129	 * XXX: this mechanism may introduce another problem about
130	 *      mutual exclusion of the variable CALLED, especially if we
131	 *      use kernel thread.
132	 */
133	if (++called >= calllimit) {
134		log(LOG_NOTICE,
135		    "gif_output: recursively called too many times(%d)\n",
136		    called);
137		m_freem(m);
138		error = EIO;	/* is there better errno? */
139		goto end;
140	}
141	getmicrotime(&ifp->if_lastchange);
142	m->m_flags &= ~(M_BCAST|M_MCAST);
143	if (!(ifp->if_flags & IFF_UP) ||
144	    sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
145		m_freem(m);
146		error = ENETDOWN;
147		goto end;
148	}
149
150	if (ifp->if_bpf) {
151		/*
152		 * We need to prepend the address family as
153		 * a four byte field.  Cons up a dummy header
154		 * to pacify bpf.  This is safe because bpf
155		 * will only read from the mbuf (i.e., it won't
156		 * try to free it or keep a pointer a to it).
157		 */
158		struct mbuf m0;
159		u_int af = dst->sa_family;
160
161		m0.m_next = m;
162		m0.m_len = 4;
163		m0.m_data = (char *)&af;
164
165		bpf_mtap(ifp, &m0);
166	}
167	ifp->if_opackets++;
168	ifp->if_obytes += m->m_pkthdr.len;
169
170	switch (sc->gif_psrc->sa_family) {
171#ifdef INET
172	case AF_INET:
173		error = in_gif_output(ifp, dst->sa_family, m, rt);
174		break;
175#endif
176#ifdef INET6
177	case AF_INET6:
178		error = in6_gif_output(ifp, dst->sa_family, m, rt);
179		break;
180#endif
181	default:
182		m_freem(m);
183		error = ENETDOWN;
184	}
185
186  end:
187	called = 0;		/* reset recursion counter */
188	if (error) ifp->if_oerrors++;
189	return error;
190}
191
192void
193gif_input(m, af, gifp)
194	struct mbuf *m;
195	int af;
196	struct ifnet *gifp;
197{
198	int s, isr;
199	register struct ifqueue *ifq = 0;
200
201	if (gifp == NULL) {
202		/* just in case */
203		m_freem(m);
204		return;
205	}
206
207	if (m->m_pkthdr.rcvif)
208		m->m_pkthdr.rcvif = gifp;
209
210	if (gifp->if_bpf) {
211		/*
212		 * We need to prepend the address family as
213		 * a four byte field.  Cons up a dummy header
214		 * to pacify bpf.  This is safe because bpf
215		 * will only read from the mbuf (i.e., it won't
216		 * try to free it or keep a pointer a to it).
217		 */
218		struct mbuf m0;
219		u_int af = AF_INET6;
220
221		m0.m_next = m;
222		m0.m_len = 4;
223		m0.m_data = (char *)&af;
224
225		bpf_mtap(gifp, &m0);
226	}
227
228	/*
229	 * Put the packet to the network layer input queue according to the
230	 * specified address family.
231	 * Note: older versions of gif_input directly called network layer
232	 * input functions, e.g. ip6_input, here. We changed the policy to
233	 * prevent too many recursive calls of such input functions, which
234	 * might cause kernel panic. But the change may introduce another
235	 * problem; if the input queue is full, packets are discarded.
236	 * We believed it rarely occurs and changed the policy. If we find
237	 * it occurs more times than we thought, we may change the policy
238	 * again.
239	 */
240	switch (af) {
241#ifdef INET
242	case AF_INET:
243		ifq = &ipintrq;
244		isr = NETISR_IP;
245		break;
246#endif
247#ifdef INET6
248	case AF_INET6:
249		ifq = &ip6intrq;
250		isr = NETISR_IPV6;
251		break;
252#endif
253	default:
254		m_freem(m);
255		return;
256	}
257
258	s = splimp();
259	if (IF_QFULL(ifq)) {
260		IF_DROP(ifq);	/* update statistics */
261		m_freem(m);
262		splx(s);
263		return;
264	}
265	IF_ENQUEUE(ifq, m);
266	/* we need schednetisr since the address family may change */
267	schednetisr(isr);
268	gifp->if_ipackets++;
269	gifp->if_ibytes += m->m_pkthdr.len;
270	splx(s);
271
272	return;
273}
274
275
276int
277gif_ioctl(ifp, cmd, data)
278	struct ifnet *ifp;
279	u_long cmd;
280	caddr_t data;
281{
282	struct gif_softc *sc  = (struct gif_softc*)ifp;
283	struct ifreq     *ifr = (struct ifreq*)data;
284	int error = 0, size;
285	struct sockaddr *sa, *dst, *src;
286
287	switch (cmd) {
288	case SIOCSIFADDR:
289		break;
290
291	case SIOCSIFDSTADDR:
292		break;
293
294	case SIOCADDMULTI:
295	case SIOCDELMULTI:
296		break;
297
298	case SIOCGIFMTU:
299		break;
300	case SIOCSIFMTU:
301		{
302			u_long mtu;
303			mtu = ifr->ifr_mtu;
304			if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
305				return (EINVAL);
306			}
307			ifp->if_mtu = mtu;
308		}
309		break;
310
311	case SIOCSIFPHYADDR:
312#ifdef INET6
313	case SIOCSIFPHYADDR_IN6:
314#endif /* INET6 */
315		switch (ifr->ifr_addr.sa_family) {
316#ifdef INET
317		case AF_INET:
318			src = (struct sockaddr *)
319				&(((struct in_aliasreq *)data)->ifra_addr);
320			dst = (struct sockaddr *)
321				&(((struct in_aliasreq *)data)->ifra_dstaddr);
322
323			/* only one gif can have dst = INADDR_ANY */
324#define	satosaddr(sa) (((struct sockaddr_in *)(sa))->sin_addr.s_addr)
325
326			if (satosaddr(dst) == INADDR_ANY) {
327				int i;
328				struct gif_softc *sc2;
329
330			  	for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
331					if (sc2 == sc) continue;
332					if (sc2->gif_pdst &&
333					    satosaddr(sc2->gif_pdst)
334						== INADDR_ANY) {
335					    error = EADDRNOTAVAIL;
336					    goto bad;
337					}
338				}
339			}
340			size = sizeof(struct sockaddr_in);
341			break;
342#endif /* INET */
343#ifdef INET6
344		case AF_INET6:
345			src = (struct sockaddr *)
346				&(((struct in6_aliasreq *)data)->ifra_addr);
347			dst = (struct sockaddr *)
348				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
349
350			/* only one gif can have dst = in6addr_any */
351#define	satoin6(sa) (&((struct sockaddr_in6 *)(sa))->sin6_addr)
352
353			if (IN6_IS_ADDR_UNSPECIFIED(satoin6(dst))) {
354				int i;
355				struct gif_softc *sc2;
356
357			  	for (i = 0, sc2 = gif; i < ngif; i++, sc2++) {
358					if (sc2 == sc) continue;
359					if (sc2->gif_pdst &&
360					    IN6_IS_ADDR_UNSPECIFIED(
361						satoin6(sc2->gif_pdst)
362								    )) {
363					    error = EADDRNOTAVAIL;
364					    goto bad;
365					}
366				}
367			}
368			size = sizeof(struct sockaddr_in6);
369			break;
370#endif /* INET6 */
371		default:
372			error = EPROTOTYPE;
373			goto bad;
374			break;
375		}
376		if (sc->gif_psrc != NULL)
377			free((caddr_t)sc->gif_psrc, M_IFADDR);
378		if (sc->gif_pdst != NULL)
379			free((caddr_t)sc->gif_pdst, M_IFADDR);
380
381		sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
382		bzero((caddr_t)sa, size);
383		bcopy((caddr_t)src, (caddr_t)sa, size);
384		sc->gif_psrc = sa;
385
386		sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK);
387		bzero((caddr_t)sa, size);
388		bcopy((caddr_t)dst, (caddr_t)sa, size);
389		sc->gif_pdst = sa;
390
391		ifp->if_flags |= (IFF_UP|IFF_RUNNING);
392		{
393			int s;
394
395			s = splnet();
396			if_up(ifp);		/* send up RTM_IFINFO */
397			splx(s);
398		}
399
400		break;
401
402	case SIOCGIFPSRCADDR:
403#ifdef INET6
404	case SIOCGIFPSRCADDR_IN6:
405#endif /* INET6 */
406		if (sc->gif_psrc == NULL) {
407			error = EADDRNOTAVAIL;
408			goto bad;
409		}
410		src = sc->gif_psrc;
411		switch (sc->gif_psrc->sa_family) {
412#ifdef INET
413		case AF_INET:
414			dst = &ifr->ifr_addr;
415			size = sizeof(struct sockaddr_in);
416			break;
417#endif /* INET */
418#ifdef INET6
419		case AF_INET6:
420			dst = (struct sockaddr *)
421				&(((struct in6_ifreq *)data)->ifr_addr);
422			size = sizeof(struct sockaddr_in6);
423			break;
424#endif /* INET6 */
425		default:
426			error = EADDRNOTAVAIL;
427			goto bad;
428		}
429		bcopy((caddr_t)src, (caddr_t)dst, size);
430		break;
431
432	case SIOCGIFPDSTADDR:
433#ifdef INET6
434	case SIOCGIFPDSTADDR_IN6:
435#endif /* INET6 */
436		if (sc->gif_pdst == NULL) {
437			error = EADDRNOTAVAIL;
438			goto bad;
439		}
440		src = sc->gif_pdst;
441		switch (sc->gif_pdst->sa_family) {
442#ifdef INET
443		case AF_INET:
444			dst = &ifr->ifr_addr;
445			size = sizeof(struct sockaddr_in);
446			break;
447#endif /* INET */
448#ifdef INET6
449		case AF_INET6:
450			dst = (struct sockaddr *)
451				&(((struct in6_ifreq *)data)->ifr_addr);
452			size = sizeof(struct sockaddr_in6);
453			break;
454#endif /* INET6 */
455		default:
456			error = EADDRNOTAVAIL;
457			goto bad;
458		}
459		bcopy((caddr_t)src, (caddr_t)dst, size);
460		break;
461
462	case SIOCSIFFLAGS:
463		break;
464
465	default:
466		error = EINVAL;
467		break;
468	}
469 bad:
470	return error;
471}
472