if_faith.c revision 231852
1179737Sjfv/*	$KAME: if_faith.c,v 1.23 2001/12/17 13:55:29 sumikawa Exp $	*/
2179737Sjfv
3179737Sjfv/*-
4179737Sjfv * Copyright (c) 1982, 1986, 1993
5179737Sjfv *	The Regents of the University of California.  All rights reserved.
6179737Sjfv *
7179737Sjfv * Redistribution and use in source and binary forms, with or without
8179737Sjfv * modification, are permitted provided that the following conditions
9179737Sjfv * are met:
10179737Sjfv * 1. Redistributions of source code must retain the above copyright
11179737Sjfv *    notice, this list of conditions and the following disclaimer.
12179737Sjfv * 2. Redistributions in binary form must reproduce the above copyright
13179737Sjfv *    notice, this list of conditions and the following disclaimer in the
14179737Sjfv *    documentation and/or other materials provided with the distribution.
15179737Sjfv * 4. Neither the name of the University nor the names of its contributors
16179737Sjfv *    may be used to endorse or promote products derived from this software
17179737Sjfv *    without specific prior written permission.
18179737Sjfv *
19179737Sjfv * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20179737Sjfv * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21179737Sjfv * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22179737Sjfv * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23179737Sjfv * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24179737Sjfv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25179737Sjfv * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26179737Sjfv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27179737Sjfv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28179737Sjfv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29179737Sjfv * SUCH DAMAGE.
30179737Sjfv *
31179737Sjfv * $FreeBSD: head/sys/net/if_faith.c 231852 2012-02-17 02:39:58Z bz $
32179737Sjfv */
33179737Sjfv/*
34179737Sjfv * derived from
35179737Sjfv *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
36179737Sjfv * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
37179737Sjfv */
38179737Sjfv
39179737Sjfv/*
40179737Sjfv * Loopback interface driver for protocol testing and timing.
41179737Sjfv */
42179737Sjfv#include "opt_inet.h"
43179737Sjfv#include "opt_inet6.h"
44179737Sjfv
45179737Sjfv#include <sys/param.h>
46179737Sjfv#include <sys/systm.h>
47179737Sjfv#include <sys/kernel.h>
48179737Sjfv#include <sys/mbuf.h>
49179737Sjfv#include <sys/module.h>
50179737Sjfv#include <sys/socket.h>
51179737Sjfv#include <sys/errno.h>
52179737Sjfv#include <sys/sockio.h>
53179737Sjfv#include <sys/time.h>
54179737Sjfv#include <sys/queue.h>
55179737Sjfv#include <sys/types.h>
56179737Sjfv#include <sys/malloc.h>
57179737Sjfv
58179737Sjfv#include <net/if.h>
59179737Sjfv#include <net/if_clone.h>
60179737Sjfv#include <net/if_types.h>
61179737Sjfv#include <net/netisr.h>
62179737Sjfv#include <net/route.h>
63179737Sjfv#include <net/bpf.h>
64179737Sjfv#include <net/vnet.h>
65179737Sjfv
66179737Sjfv#ifdef	INET
67179737Sjfv#include <netinet/in.h>
68179737Sjfv#include <netinet/in_systm.h>
69179737Sjfv#include <netinet/in_var.h>
70179737Sjfv#include <netinet/ip.h>
71179737Sjfv#endif
72179737Sjfv
73179737Sjfv#ifdef INET6
74179737Sjfv#ifndef INET
75179737Sjfv#include <netinet/in.h>
76179737Sjfv#endif
77179737Sjfv#include <netinet6/in6_var.h>
78179737Sjfv#include <netinet/ip6.h>
79179737Sjfv#include <netinet6/ip6_var.h>
80179737Sjfv#endif
81179737Sjfv
82179737Sjfv#define FAITHNAME	"faith"
83179737Sjfv
84179737Sjfvstruct faith_softc {
85179737Sjfv	struct ifnet *sc_ifp;
86179737Sjfv};
87179737Sjfv
88179737Sjfvstatic int faithioctl(struct ifnet *, u_long, caddr_t);
89179737Sjfvint faithoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
90179737Sjfv	struct route *);
91179737Sjfvstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *);
92179737Sjfv#ifdef INET6
93179737Sjfvstatic int faithprefix(struct in6_addr *);
94179737Sjfv#endif
95179737Sjfv
96179737Sjfvstatic int faithmodevent(module_t, int, void *);
97179737Sjfv
98179737Sjfvstatic MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface");
99179737Sjfv
100179737Sjfvstatic int	faith_clone_create(struct if_clone *, int, caddr_t);
101179737Sjfvstatic void	faith_clone_destroy(struct ifnet *);
102179737Sjfv
103179737SjfvIFC_SIMPLE_DECLARE(faith, 0);
104179737Sjfv
105179737Sjfv#define	FAITHMTU	1500
106179737Sjfv
107179737Sjfvstatic int
108179737Sjfvfaithmodevent(mod, type, data)
109179737Sjfv	module_t mod;
110179737Sjfv	int type;
111217126Sjhb	void *data;
112179737Sjfv{
113179737Sjfv
114179737Sjfv	switch (type) {
115179737Sjfv	case MOD_LOAD:
116179737Sjfv		if_clone_attach(&faith_cloner);
117179737Sjfv
118179737Sjfv#ifdef INET6
119179737Sjfv		faithprefix_p = faithprefix;
120179737Sjfv#endif
121179737Sjfv
122179737Sjfv		break;
123179737Sjfv	case MOD_UNLOAD:
124179737Sjfv#ifdef INET6
125179737Sjfv		faithprefix_p = NULL;
126179737Sjfv#endif
127179737Sjfv
128179737Sjfv		if_clone_detach(&faith_cloner);
129179737Sjfv		break;
130179737Sjfv	default:
131179737Sjfv		return EOPNOTSUPP;
132179737Sjfv	}
133179737Sjfv	return 0;
134179737Sjfv}
135179737Sjfv
136179737Sjfvstatic moduledata_t faith_mod = {
137179737Sjfv	"if_faith",
138179737Sjfv	faithmodevent,
139179737Sjfv	0
140179737Sjfv};
141179737Sjfv
142179737SjfvDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
143179737SjfvMODULE_VERSION(if_faith, 1);
144179737Sjfv
145179737Sjfvstatic int
146179737Sjfvfaith_clone_create(ifc, unit, params)
147179737Sjfv	struct if_clone *ifc;
148179737Sjfv	int unit;
149179737Sjfv	caddr_t params;
150179737Sjfv{
151179737Sjfv	struct ifnet *ifp;
152179737Sjfv	struct faith_softc *sc;
153179737Sjfv
154179737Sjfv	sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK | M_ZERO);
155179737Sjfv	ifp = sc->sc_ifp = if_alloc(IFT_FAITH);
156179737Sjfv	if (ifp == NULL) {
157179737Sjfv		free(sc, M_FAITH);
158179737Sjfv		return (ENOSPC);
159179737Sjfv	}
160179737Sjfv
161179737Sjfv	ifp->if_softc = sc;
162179737Sjfv	if_initname(sc->sc_ifp, ifc->ifc_name, unit);
163179737Sjfv
164179737Sjfv	ifp->if_mtu = FAITHMTU;
165179737Sjfv	/* Change to BROADCAST experimentaly to announce its prefix. */
166179737Sjfv	ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
167179737Sjfv	ifp->if_ioctl = faithioctl;
168179737Sjfv	ifp->if_output = faithoutput;
169179737Sjfv	ifp->if_hdrlen = 0;
170179737Sjfv	ifp->if_addrlen = 0;
171179737Sjfv	ifp->if_snd.ifq_maxlen = ifqmaxlen;
172179737Sjfv	if_attach(ifp);
173179737Sjfv	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
174179737Sjfv	return (0);
175179737Sjfv}
176179737Sjfv
177179737Sjfvstatic void
178179737Sjfvfaith_clone_destroy(ifp)
179179737Sjfv	struct ifnet *ifp;
180179737Sjfv{
181179737Sjfv	struct faith_softc *sc = ifp->if_softc;
182179737Sjfv
183179737Sjfv	bpfdetach(ifp);
184179737Sjfv	if_detach(ifp);
185179737Sjfv	if_free(ifp);
186179737Sjfv	free(sc, M_FAITH);
187182089Skmacy}
188179737Sjfv
189179737Sjfvint
190179737Sjfvfaithoutput(ifp, m, dst, ro)
191179737Sjfv	struct ifnet *ifp;
192179737Sjfv	struct mbuf *m;
193179737Sjfv	struct sockaddr *dst;
194179737Sjfv	struct route *ro;
195179737Sjfv{
196179737Sjfv	int isr;
197179737Sjfv	u_int32_t af;
198179737Sjfv	struct rtentry *rt = NULL;
199179737Sjfv
200179737Sjfv	M_ASSERTPKTHDR(m);
201179737Sjfv
202179737Sjfv	if (ro != NULL)
203179737Sjfv		rt = ro->ro_rt;
204179737Sjfv	/* BPF writes need to be handled specially. */
205179737Sjfv	if (dst->sa_family == AF_UNSPEC) {
206179737Sjfv		bcopy(dst->sa_data, &af, sizeof(af));
207182089Skmacy		dst->sa_family = af;
208182089Skmacy	}
209182089Skmacy
210182089Skmacy	if (bpf_peers_present(ifp->if_bpf)) {
211182089Skmacy		af = dst->sa_family;
212182089Skmacy		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
213182089Skmacy	}
214182089Skmacy
215182089Skmacy	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
216182089Skmacy		m_freem(m);
217182089Skmacy		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
218182089Skmacy		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
219179737Sjfv	}
220182089Skmacy	ifp->if_opackets++;
221179737Sjfv	ifp->if_obytes += m->m_pkthdr.len;
222179737Sjfv	switch (dst->sa_family) {
223179737Sjfv#ifdef INET
224179737Sjfv	case AF_INET:
225179737Sjfv		isr = NETISR_IP;
226179737Sjfv		break;
227179737Sjfv#endif
228179737Sjfv#ifdef INET6
229179737Sjfv	case AF_INET6:
230179737Sjfv		isr = NETISR_IPV6;
231179737Sjfv		break;
232179737Sjfv#endif
233179737Sjfv	default:
234179737Sjfv		m_freem(m);
235179737Sjfv		return EAFNOSUPPORT;
236179737Sjfv	}
237179737Sjfv
238179737Sjfv	/* XXX do we need more sanity checks? */
239179737Sjfv
240179737Sjfv	m->m_pkthdr.rcvif = ifp;
241179737Sjfv	ifp->if_ipackets++;
242179737Sjfv	ifp->if_ibytes += m->m_pkthdr.len;
243179737Sjfv	netisr_dispatch(isr, m);
244179737Sjfv	return (0);
245179737Sjfv}
246179737Sjfv
247179737Sjfv/* ARGSUSED */
248179737Sjfvstatic void
249179737Sjfvfaithrtrequest(cmd, rt, info)
250179737Sjfv	int cmd;
251179737Sjfv	struct rtentry *rt;
252179737Sjfv	struct rt_addrinfo *info;
253179737Sjfv{
254179737Sjfv	RT_LOCK_ASSERT(rt);
255179737Sjfv	rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
256179737Sjfv}
257179737Sjfv
258179737Sjfv/*
259179737Sjfv * Process an ioctl request.
260179737Sjfv */
261179737Sjfv/* ARGSUSED */
262179737Sjfvstatic int
263179737Sjfvfaithioctl(ifp, cmd, data)
264179737Sjfv	struct ifnet *ifp;
265179737Sjfv	u_long cmd;
266179737Sjfv	caddr_t data;
267179737Sjfv{
268179737Sjfv	struct ifaddr *ifa;
269179737Sjfv	struct ifreq *ifr = (struct ifreq *)data;
270179737Sjfv	int error = 0;
271179737Sjfv
272179737Sjfv	switch (cmd) {
273179737Sjfv
274179737Sjfv	case SIOCSIFADDR:
275179737Sjfv		ifp->if_flags |= IFF_UP;
276179737Sjfv		ifp->if_drv_flags |= IFF_DRV_RUNNING;
277179737Sjfv		ifa = (struct ifaddr *)data;
278179737Sjfv		ifa->ifa_rtrequest = faithrtrequest;
279179737Sjfv		/*
280223797Scperciva		 * Everything else is done at a higher level.
281223797Scperciva		 */
282223797Scperciva		break;
283223797Scperciva
284223797Scperciva	case SIOCADDMULTI:
285223797Scperciva	case SIOCDELMULTI:
286223797Scperciva		if (ifr == 0) {
287223797Scperciva			error = EAFNOSUPPORT;		/* XXX */
288179737Sjfv			break;
289179737Sjfv		}
290220428Sjfv		switch (ifr->ifr_addr.sa_family) {
291220428Sjfv#ifdef INET
292220428Sjfv		case AF_INET:
293220428Sjfv			break;
294179737Sjfv#endif
295179737Sjfv#ifdef INET6
296179737Sjfv		case AF_INET6:
297179737Sjfv			break;
298179737Sjfv#endif
299179737Sjfv
300179737Sjfv		default:
301179737Sjfv			error = EAFNOSUPPORT;
302179737Sjfv			break;
303179737Sjfv		}
304179737Sjfv		break;
305179737Sjfv
306179737Sjfv#ifdef SIOCSIFMTU
307179737Sjfv	case SIOCSIFMTU:
308179737Sjfv		ifp->if_mtu = ifr->ifr_mtu;
309179737Sjfv		break;
310179737Sjfv#endif
311179737Sjfv
312179737Sjfv	case SIOCSIFFLAGS:
313179737Sjfv		break;
314179737Sjfv
315179737Sjfv	default:
316179737Sjfv		error = EINVAL;
317179737Sjfv	}
318179737Sjfv	return (error);
319179737Sjfv}
320179737Sjfv
321179737Sjfv#ifdef INET6
322179737Sjfv/*
323179737Sjfv * XXX could be slow
324179737Sjfv * XXX could be layer violation to call sys/net from sys/netinet6
325179737Sjfv */
326179737Sjfvstatic int
327179737Sjfvfaithprefix(in6)
328179737Sjfv	struct in6_addr *in6;
329179737Sjfv{
330179737Sjfv	struct rtentry *rt;
331179737Sjfv	struct sockaddr_in6 sin6;
332179737Sjfv	int ret;
333179737Sjfv
334179737Sjfv	if (V_ip6_keepfaith == 0)
335179737Sjfv		return 0;
336179737Sjfv
337179737Sjfv	bzero(&sin6, sizeof(sin6));
338179737Sjfv	sin6.sin6_family = AF_INET6;
339179737Sjfv	sin6.sin6_len = sizeof(struct sockaddr_in6);
340179737Sjfv	sin6.sin6_addr = *in6;
341179737Sjfv	rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
342179737Sjfv	if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
343179737Sjfv	    (rt->rt_ifp->if_flags & IFF_UP) != 0)
344179737Sjfv		ret = 1;
345179737Sjfv	else
346179737Sjfv		ret = 0;
347179737Sjfv	if (rt)
348179737Sjfv		RTFREE_LOCKED(rt);
349179737Sjfv	return ret;
350179737Sjfv}
351179737Sjfv#endif
352179737Sjfv