if_faith.c revision 263478
1227825Stheraven/*	$KAME: if_faith.c,v 1.23 2001/12/17 13:55:29 sumikawa Exp $	*/
2227825Stheraven
3227825Stheraven/*-
4353358Sdim * Copyright (c) 1982, 1986, 1993
5353358Sdim *	The Regents of the University of California.  All rights reserved.
6353358Sdim *
7227825Stheraven * Redistribution and use in source and binary forms, with or without
8227825Stheraven * modification, are permitted provided that the following conditions
9227825Stheraven * are met:
10227825Stheraven * 1. Redistributions of source code must retain the above copyright
11227825Stheraven *    notice, this list of conditions and the following disclaimer.
12227825Stheraven * 2. Redistributions in binary form must reproduce the above copyright
13227825Stheraven *    notice, this list of conditions and the following disclaimer in the
14227825Stheraven *    documentation and/or other materials provided with the distribution.
15227825Stheraven * 4. Neither the name of the University nor the names of its contributors
16227825Stheraven *    may be used to endorse or promote products derived from this software
17227825Stheraven *    without specific prior written permission.
18227825Stheraven *
19227825Stheraven * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20227825Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21321369Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22353358Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23227825Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24276792Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25261272Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26276792Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27341825Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28276792Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29288943Sdim * SUCH DAMAGE.
30276792Sdim *
31276792Sdim * $FreeBSD: stable/10/sys/net/if_faith.c 263478 2014-03-21 15:15:30Z glebius $
32276792Sdim */
33322320Sdim/*
34276792Sdim * derived from
35227825Stheraven *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
36321369Sdim * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
37321369Sdim */
38353358Sdim
39353358Sdim/*
40353358Sdim * Loopback interface driver for protocol testing and timing.
41300770Sdim */
42300770Sdim#include "opt_inet.h"
43321369Sdim#include "opt_inet6.h"
44227825Stheraven
45227825Stheraven#include <sys/param.h>
46227825Stheraven#include <sys/systm.h>
47227825Stheraven#include <sys/kernel.h>
48227825Stheraven#include <sys/mbuf.h>
49227825Stheraven#include <sys/module.h>
50227825Stheraven#include <sys/socket.h>
51327952Sdim#include <sys/errno.h>
52321369Sdim#include <sys/sockio.h>
53321369Sdim#include <sys/time.h>
54321369Sdim#include <sys/queue.h>
55321369Sdim#include <sys/types.h>
56321369Sdim#include <sys/malloc.h>
57321369Sdim
58321369Sdim#include <net/if.h>
59321369Sdim#include <net/if_clone.h>
60321369Sdim#include <net/if_types.h>
61321369Sdim#include <net/netisr.h>
62321369Sdim#include <net/route.h>
63321369Sdim#include <net/bpf.h>
64321369Sdim#include <net/vnet.h>
65321369Sdim
66321369Sdim#ifdef	INET
67327952Sdim#include <netinet/in.h>
68327952Sdim#include <netinet/in_systm.h>
69327952Sdim#include <netinet/in_var.h>
70353358Sdim#include <netinet/ip.h>
71353358Sdim#endif
72353358Sdim
73353358Sdim#ifdef INET6
74353358Sdim#ifndef INET
75353358Sdim#include <netinet/in.h>
76353358Sdim#endif
77353358Sdim#include <netinet6/in6_var.h>
78353358Sdim#include <netinet/ip6.h>
79353358Sdim#include <netinet6/ip6_var.h>
80353358Sdim#endif
81353358Sdim
82353358Sdimstruct faith_softc {
83353358Sdim	struct ifnet *sc_ifp;
84353358Sdim};
85353358Sdim
86327952Sdimstatic int faithioctl(struct ifnet *, u_long, caddr_t);
87353358Sdimstatic int faithoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
88353358Sdim	struct route *);
89353358Sdimstatic void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *);
90353358Sdim#ifdef INET6
91353358Sdimstatic int faithprefix(struct in6_addr *);
92353358Sdim#endif
93353358Sdim
94353358Sdimstatic int faithmodevent(module_t, int, void *);
95353358Sdim
96327952Sdimstatic const char faithname[] = "faith";
97353358Sdimstatic MALLOC_DEFINE(M_FAITH, faithname, "Firewall Assisted Tunnel Interface");
98353358Sdim
99353358Sdimstatic int	faith_clone_create(struct if_clone *, int, caddr_t);
100353358Sdimstatic void	faith_clone_destroy(struct ifnet *);
101353358Sdimstatic struct if_clone *faith_cloner;
102353358Sdim
103327952Sdim#define	FAITHMTU	1500
104353358Sdim
105327952Sdimstatic int
106321369Sdimfaithmodevent(mod, type, data)
107321369Sdim	module_t mod;
108321369Sdim	int type;
109249989Sdim	void *data;
110227825Stheraven{
111241900Sdim
112241900Sdim	switch (type) {
113241900Sdim	case MOD_LOAD:
114241900Sdim		faith_cloner = if_clone_simple(faithname, faith_clone_create,
115227825Stheraven		    faith_clone_destroy, 0);
116241900Sdim#ifdef INET6
117241900Sdim		faithprefix_p = faithprefix;
118241900Sdim#endif
119241900Sdim
120241900Sdim		break;
121249989Sdim	case MOD_UNLOAD:
122227825Stheraven#ifdef INET6
123227825Stheraven		faithprefix_p = NULL;
124227825Stheraven#endif
125249989Sdim
126249989Sdim		if_clone_detach(faith_cloner);
127227825Stheraven		break;
128227825Stheraven	default:
129321369Sdim		return EOPNOTSUPP;
130227825Stheraven	}
131227825Stheraven	return 0;
132227825Stheraven}
133227825Stheraven
134227825Stheravenstatic moduledata_t faith_mod = {
135227825Stheraven	"if_faith",
136227825Stheraven	faithmodevent,
137227825Stheraven	0
138227825Stheraven};
139227825Stheraven
140227825StheravenDECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
141227825StheravenMODULE_VERSION(if_faith, 1);
142227825Stheraven
143227825Stheravenstatic int
144227825Stheravenfaith_clone_create(ifc, unit, params)
145227825Stheraven	struct if_clone *ifc;
146227825Stheraven	int unit;
147227825Stheraven	caddr_t params;
148227825Stheraven{
149227825Stheraven	struct ifnet *ifp;
150227825Stheraven	struct faith_softc *sc;
151227825Stheraven
152227825Stheraven	sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK | M_ZERO);
153227825Stheraven	ifp = sc->sc_ifp = if_alloc(IFT_FAITH);
154227825Stheraven	if (ifp == NULL) {
155321369Sdim		free(sc, M_FAITH);
156321369Sdim		return (ENOSPC);
157321369Sdim	}
158227825Stheraven
159227825Stheraven	ifp->if_softc = sc;
160227825Stheraven	if_initname(sc->sc_ifp, faithname, unit);
161227825Stheraven
162227825Stheraven	ifp->if_mtu = FAITHMTU;
163227825Stheraven	/* Change to BROADCAST experimentaly to announce its prefix. */
164321369Sdim	ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
165227825Stheraven	ifp->if_ioctl = faithioctl;
166227825Stheraven	ifp->if_output = faithoutput;
167227825Stheraven	ifp->if_hdrlen = 0;
168227825Stheraven	ifp->if_addrlen = 0;
169227825Stheraven	ifp->if_snd.ifq_maxlen = ifqmaxlen;
170227825Stheraven	if_attach(ifp);
171227825Stheraven	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
172227825Stheraven	return (0);
173227825Stheraven}
174227825Stheraven
175227825Stheravenstatic void
176227825Stheravenfaith_clone_destroy(ifp)
177227825Stheraven	struct ifnet *ifp;
178227825Stheraven{
179227825Stheraven	struct faith_softc *sc = ifp->if_softc;
180227825Stheraven
181227825Stheraven	bpfdetach(ifp);
182227825Stheraven	if_detach(ifp);
183227825Stheraven	if_free(ifp);
184227825Stheraven	free(sc, M_FAITH);
185249989Sdim}
186227825Stheraven
187227825Stheravenstatic int
188227825Stheravenfaithoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
189227825Stheraven	struct route *ro)
190227825Stheraven{
191227825Stheraven	int isr;
192227825Stheraven	u_int32_t af;
193227825Stheraven	struct rtentry *rt = NULL;
194227825Stheraven
195227825Stheraven	M_ASSERTPKTHDR(m);
196227825Stheraven
197227825Stheraven	if (ro != NULL)
198227825Stheraven		rt = ro->ro_rt;
199227825Stheraven	/* BPF writes need to be handled specially. */
200227825Stheraven	if (dst->sa_family == AF_UNSPEC)
201249989Sdim		bcopy(dst->sa_data, &af, sizeof(af));
202227825Stheraven	else
203227825Stheraven		af = dst->sa_family;
204227825Stheraven
205227825Stheraven	if (bpf_peers_present(ifp->if_bpf))
206227825Stheraven		bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
207227825Stheraven
208241900Sdim	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
209227825Stheraven		m_freem(m);
210227825Stheraven		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
211227825Stheraven		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
212227825Stheraven	}
213227825Stheraven	ifp->if_opackets++;
214227825Stheraven	ifp->if_obytes += m->m_pkthdr.len;
215227825Stheraven	switch (af) {
216227825Stheraven#ifdef INET
217227825Stheraven	case AF_INET:
218227825Stheraven		isr = NETISR_IP;
219227825Stheraven		break;
220227825Stheraven#endif
221227825Stheraven#ifdef INET6
222227825Stheraven	case AF_INET6:
223227825Stheraven		isr = NETISR_IPV6;
224227825Stheraven		break;
225227825Stheraven#endif
226227825Stheraven	default:
227227825Stheraven		m_freem(m);
228227825Stheraven		return EAFNOSUPPORT;
229227825Stheraven	}
230227825Stheraven
231227825Stheraven	/* XXX do we need more sanity checks? */
232314564Sdim
233314564Sdim	m->m_pkthdr.rcvif = ifp;
234227825Stheraven	ifp->if_ipackets++;
235227825Stheraven	ifp->if_ibytes += m->m_pkthdr.len;
236227825Stheraven	netisr_dispatch(isr, m);
237227825Stheraven	return (0);
238227825Stheraven}
239227825Stheraven
240227825Stheraven/* ARGSUSED */
241227825Stheravenstatic void
242227825Stheravenfaithrtrequest(cmd, rt, info)
243227825Stheraven	int cmd;
244227825Stheraven	struct rtentry *rt;
245227825Stheraven	struct rt_addrinfo *info;
246227825Stheraven{
247227825Stheraven	RT_LOCK_ASSERT(rt);
248227825Stheraven	rt->rt_mtu = rt->rt_ifp->if_mtu;
249227825Stheraven}
250227825Stheraven
251227825Stheraven/*
252227825Stheraven * Process an ioctl request.
253227825Stheraven */
254227825Stheraven/* ARGSUSED */
255227825Stheravenstatic int
256314564Sdimfaithioctl(ifp, cmd, data)
257227825Stheraven	struct ifnet *ifp;
258227825Stheraven	u_long cmd;
259227825Stheraven	caddr_t data;
260227825Stheraven{
261227825Stheraven	struct ifaddr *ifa;
262227825Stheraven	struct ifreq *ifr = (struct ifreq *)data;
263227825Stheraven	int error = 0;
264227825Stheraven
265227825Stheraven	switch (cmd) {
266227825Stheraven
267227825Stheraven	case SIOCSIFADDR:
268227825Stheraven		ifp->if_flags |= IFF_UP;
269227825Stheraven		ifp->if_drv_flags |= IFF_DRV_RUNNING;
270227825Stheraven		ifa = (struct ifaddr *)data;
271227825Stheraven		ifa->ifa_rtrequest = faithrtrequest;
272227825Stheraven		/*
273227825Stheraven		 * Everything else is done at a higher level.
274353358Sdim		 */
275353358Sdim		break;
276227825Stheraven
277353358Sdim	case SIOCADDMULTI:
278227825Stheraven	case SIOCDELMULTI:
279227825Stheraven		if (ifr == 0) {
280227825Stheraven			error = EAFNOSUPPORT;		/* XXX */
281227825Stheraven			break;
282227825Stheraven		}
283227825Stheraven		switch (ifr->ifr_addr.sa_family) {
284227825Stheraven#ifdef INET
285227825Stheraven		case AF_INET:
286227825Stheraven			break;
287227825Stheraven#endif
288227825Stheraven#ifdef INET6
289227825Stheraven		case AF_INET6:
290227825Stheraven			break;
291227825Stheraven#endif
292227825Stheraven
293227825Stheraven		default:
294227825Stheraven			error = EAFNOSUPPORT;
295227825Stheraven			break;
296227825Stheraven		}
297227825Stheraven		break;
298227825Stheraven
299227825Stheraven#ifdef SIOCSIFMTU
300227825Stheraven	case SIOCSIFMTU:
301227825Stheraven		ifp->if_mtu = ifr->ifr_mtu;
302227825Stheraven		break;
303227825Stheraven#endif
304227825Stheraven
305227825Stheraven	case SIOCSIFFLAGS:
306227825Stheraven		break;
307227825Stheraven
308227825Stheraven	default:
309227825Stheraven		error = EINVAL;
310227825Stheraven	}
311227825Stheraven	return (error);
312227825Stheraven}
313227825Stheraven
314227825Stheraven#ifdef INET6
315227825Stheraven/*
316227825Stheraven * XXX could be slow
317227825Stheraven * XXX could be layer violation to call sys/net from sys/netinet6
318227825Stheraven */
319227825Stheravenstatic int
320227825Stheravenfaithprefix(in6)
321227825Stheraven	struct in6_addr *in6;
322227825Stheraven{
323227825Stheraven	struct rtentry *rt;
324227825Stheraven	struct sockaddr_in6 sin6;
325227825Stheraven	int ret;
326227825Stheraven
327227825Stheraven	if (V_ip6_keepfaith == 0)
328227825Stheraven		return 0;
329227825Stheraven
330227825Stheraven	bzero(&sin6, sizeof(sin6));
331232924Stheraven	sin6.sin6_family = AF_INET6;
332227825Stheraven	sin6.sin6_len = sizeof(struct sockaddr_in6);
333227825Stheraven	sin6.sin6_addr = *in6;
334227825Stheraven	rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
335227825Stheraven	if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
336227825Stheraven	    (rt->rt_ifp->if_flags & IFF_UP) != 0)
337227825Stheraven		ret = 1;
338314564Sdim	else
339314564Sdim		ret = 0;
340227825Stheraven	if (rt)
341227825Stheraven		RTFREE_LOCKED(rt);
342227825Stheraven	return ret;
343314564Sdim}
344227825Stheraven#endif
345227825Stheraven