if_faith.c revision 91317
1193323Sed/*	$KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $	*/
2193323Sed
3193323Sed/*
4193323Sed * Copyright (c) 1982, 1986, 1993
5193323Sed *	The Regents of the University of California.  All rights reserved.
6193323Sed *
7193323Sed * Redistribution and use in source and binary forms, with or without
8193323Sed * modification, are permitted provided that the following conditions
9193323Sed * are met:
10193323Sed * 1. Redistributions of source code must retain the above copyright
11193323Sed *    notice, this list of conditions and the following disclaimer.
12193323Sed * 2. Redistributions in binary form must reproduce the above copyright
13193323Sed *    notice, this list of conditions and the following disclaimer in the
14193323Sed *    documentation and/or other materials provided with the distribution.
15193323Sed * 3. All advertising materials mentioning features or use of this software
16193323Sed *    must display the following acknowledgement:
17193323Sed *	This product includes software developed by the University of
18193323Sed *	California, Berkeley and its contributors.
19193323Sed * 4. Neither the name of the University nor the names of its contributors
20193323Sed *    may be used to endorse or promote products derived from this software
21193323Sed *    without specific prior written permission.
22193323Sed *
23193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33193323Sed * SUCH DAMAGE.
34193323Sed *
35193323Sed * $FreeBSD: head/sys/net/if_faith.c 91317 2002-02-26 17:11:37Z dillon $
36195340Sed */
37193323Sed/*
38193323Sed * derived from
39195340Sed *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
40195340Sed * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
41195340Sed */
42195340Sed
43195340Sed/*
44195340Sed * Loopback interface driver for protocol testing and timing.
45195340Sed */
46195340Sed#include "opt_inet.h"
47195340Sed#include "opt_inet6.h"
48195340Sed
49195340Sed#include <sys/param.h>
50195340Sed#include <sys/systm.h>
51195340Sed#include <sys/kernel.h>
52195340Sed#include <sys/mbuf.h>
53193323Sed#include <sys/socket.h>
54195340Sed#include <sys/errno.h>
55195340Sed#include <sys/sockio.h>
56195340Sed#include <sys/time.h>
57195340Sed#include <sys/queue.h>
58195340Sed#include <sys/types.h>
59195340Sed#include <sys/malloc.h>
60195340Sed#include <machine/bus.h>	/* XXX: Shouldn't really be required! */
61193323Sed#include <sys/rman.h>
62193323Sed
63193323Sed#include <net/if.h>
64193323Sed#include <net/if_types.h>
65193323Sed#include <net/netisr.h>
66193323Sed#include <net/route.h>
67193323Sed#include <net/bpf.h>
68193323Sed
69193323Sed#ifdef	INET
70193323Sed#include <netinet/in.h>
71193323Sed#include <netinet/in_systm.h>
72193323Sed#include <netinet/in_var.h>
73#include <netinet/ip.h>
74#endif
75
76#ifdef INET6
77#ifndef INET
78#include <netinet/in.h>
79#endif
80#include <netinet6/in6_var.h>
81#include <netinet/ip6.h>
82#include <netinet6/ip6_var.h>
83#endif
84
85#include <net/net_osdep.h>
86
87#define FAITHNAME	"faith"
88#define FAITH_MAXUNIT	0x7fff	/* ifp->if_unit is only 15 bits */
89
90struct faith_softc {
91	struct ifnet sc_if;	/* must be first */
92	struct resource *r_unit;
93	LIST_ENTRY(faith_softc) sc_list;
94};
95
96static int faithioctl __P((struct ifnet *, u_long, caddr_t));
97int faithoutput __P((struct ifnet *, struct mbuf *, struct sockaddr *,
98	struct rtentry *));
99static void faithrtrequest __P((int, struct rtentry *, struct rt_addrinfo *));
100#ifdef INET6
101static int faithprefix __P((struct in6_addr *));
102#endif
103
104static int faithmodevent __P((module_t, int, void *));
105
106static MALLOC_DEFINE(M_FAITH, FAITHNAME, "Firewall Assisted Tunnel Interface");
107static struct rman faithunits[1];
108static LIST_HEAD(, faith_softc) faith_softc_list;
109
110int	faith_clone_create __P((struct if_clone *, int *));
111void	faith_clone_destroy __P((struct ifnet *));
112
113struct if_clone faith_cloner =
114    IF_CLONE_INITIALIZER(FAITHNAME, faith_clone_create, faith_clone_destroy);
115
116#define	FAITHMTU	1500
117
118static int
119faithmodevent(mod, type, data)
120	module_t mod;
121	int type;
122	void *data;
123{
124	int err;
125
126	switch (type) {
127	case MOD_LOAD:
128		faithunits->rm_type = RMAN_ARRAY;
129		faithunits->rm_descr = "configurable if_faith units";
130		err = rman_init(faithunits);
131		if (err != 0)
132			return (err);
133		err = rman_manage_region(faithunits, 0, FAITH_MAXUNIT);
134		if (err != 0) {
135			printf("%s: faithunits: rman_manage_region: "
136			    "Failed %d\n", FAITHNAME, err);
137			rman_fini(faithunits);
138			return (err);
139		}
140		LIST_INIT(&faith_softc_list);
141		if_clone_attach(&faith_cloner);
142
143#ifdef INET6
144		faithprefix_p = faithprefix;
145#endif
146
147		break;
148	case MOD_UNLOAD:
149#ifdef INET6
150		faithprefix_p = NULL;
151#endif
152
153		if_clone_detach(&faith_cloner);
154
155		while (!LIST_EMPTY(&faith_softc_list))
156			faith_clone_destroy(
157			    &LIST_FIRST(&faith_softc_list)->sc_if);
158
159		err = rman_fini(faithunits);
160		if (err != 0)
161			return (err);
162
163		break;
164	}
165	return 0;
166}
167
168static moduledata_t faith_mod = {
169	"if_faith",
170	faithmodevent,
171	0
172};
173
174DECLARE_MODULE(if_faith, faith_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
175MODULE_VERSION(if_faith, 1);
176
177int
178faith_clone_create(ifc, unit)
179	struct if_clone *ifc;
180	int *unit;
181{
182	struct resource *r;
183	struct faith_softc *sc;
184
185	if (*unit > FAITH_MAXUNIT)
186		return (ENXIO);
187
188	if (*unit < 0) {
189		r = rman_reserve_resource(faithunits, 0, FAITH_MAXUNIT, 1,
190		    RF_ALLOCATED | RF_ACTIVE, NULL);
191		if (r == NULL)
192			return (ENOSPC);
193		*unit = rman_get_start(r);
194	} else {
195		r = rman_reserve_resource(faithunits, *unit, *unit, 1,
196		    RF_ALLOCATED | RF_ACTIVE, NULL);
197		if (r == NULL)
198			return (ENOSPC);
199	}
200
201	sc = malloc(sizeof(struct faith_softc), M_FAITH, M_WAITOK);
202	bzero(sc, sizeof(struct faith_softc));
203
204	sc->sc_if.if_softc = sc;
205	sc->sc_if.if_name = FAITHNAME;
206	sc->sc_if.if_unit = *unit;
207	sc->r_unit = r;
208
209	sc->sc_if.if_mtu = FAITHMTU;
210	/* Change to BROADCAST experimentaly to announce its prefix. */
211	sc->sc_if.if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST;
212	sc->sc_if.if_ioctl = faithioctl;
213	sc->sc_if.if_output = faithoutput;
214	sc->sc_if.if_type = IFT_FAITH;
215	sc->sc_if.if_hdrlen = 0;
216	sc->sc_if.if_addrlen = 0;
217	sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
218	if_attach(&sc->sc_if);
219	bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
220	LIST_INSERT_HEAD(&faith_softc_list, sc, sc_list);
221	return (0);
222}
223
224void
225faith_clone_destroy(ifp)
226	struct ifnet *ifp;
227{
228	int err;
229	struct faith_softc *sc = (void *) ifp;
230
231	LIST_REMOVE(sc, sc_list);
232	bpfdetach(ifp);
233	if_detach(ifp);
234
235	err = rman_release_resource(sc->r_unit);
236	KASSERT(err == 0, ("Unexpected error freeing resource"));
237
238	free(sc, M_FAITH);
239}
240
241int
242faithoutput(ifp, m, dst, rt)
243	struct ifnet *ifp;
244	struct mbuf *m;
245	struct sockaddr *dst;
246	struct rtentry *rt;
247{
248	int isr;
249	struct ifqueue *ifq = 0;
250
251	if ((m->m_flags & M_PKTHDR) == 0)
252		panic("faithoutput no HDR");
253
254	/* BPF write needs to be handled specially */
255	if (dst->sa_family == AF_UNSPEC) {
256		dst->sa_family = *(mtod(m, int *));
257		m->m_len -= sizeof(int);
258		m->m_pkthdr.len -= sizeof(int);
259		m->m_data += sizeof(int);
260	}
261
262	if (ifp->if_bpf) {
263		/*
264		 * We need to prepend the address family as
265		 * a four byte field.  Cons up a faith header
266		 * to pacify bpf.  This is safe because bpf
267		 * will only read from the mbuf (i.e., it won't
268		 * try to free it or keep a pointer a to it).
269		 */
270		struct mbuf m0;
271		u_int32_t af = dst->sa_family;
272
273		m0.m_next = m;
274		m0.m_len = 4;
275		m0.m_data = (char *)&af;
276
277		bpf_mtap(ifp, &m0);
278	}
279
280	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
281		m_freem(m);
282		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
283		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
284	}
285	ifp->if_opackets++;
286	ifp->if_obytes += m->m_pkthdr.len;
287	switch (dst->sa_family) {
288#ifdef INET
289	case AF_INET:
290		ifq = &ipintrq;
291		isr = NETISR_IP;
292		break;
293#endif
294#ifdef INET6
295	case AF_INET6:
296		ifq = &ip6intrq;
297		isr = NETISR_IPV6;
298		break;
299#endif
300	default:
301		m_freem(m);
302		return EAFNOSUPPORT;
303	}
304
305	/* XXX do we need more sanity checks? */
306
307	m->m_pkthdr.rcvif = ifp;
308	ifp->if_ipackets++;
309	ifp->if_ibytes += m->m_pkthdr.len;
310	(void) IF_HANDOFF(ifq, m, NULL);
311	schednetisr(isr);
312	return (0);
313}
314
315/* ARGSUSED */
316static void
317faithrtrequest(cmd, rt, info)
318	int cmd;
319	struct rtentry *rt;
320	struct rt_addrinfo *info;
321{
322	if (rt) {
323		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
324		/*
325		 * For optimal performance, the send and receive buffers
326		 * should be at least twice the MTU plus a little more for
327		 * overhead.
328		 */
329		rt->rt_rmx.rmx_recvpipe =
330			rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU;
331	}
332}
333
334/*
335 * Process an ioctl request.
336 */
337/* ARGSUSED */
338static int
339faithioctl(ifp, cmd, data)
340	struct ifnet *ifp;
341	u_long cmd;
342	caddr_t data;
343{
344	struct ifaddr *ifa;
345	struct ifreq *ifr = (struct ifreq *)data;
346	int error = 0;
347
348	switch (cmd) {
349
350	case SIOCSIFADDR:
351		ifp->if_flags |= IFF_UP | IFF_RUNNING;
352		ifa = (struct ifaddr *)data;
353		ifa->ifa_rtrequest = faithrtrequest;
354		/*
355		 * Everything else is done at a higher level.
356		 */
357		break;
358
359	case SIOCADDMULTI:
360	case SIOCDELMULTI:
361		if (ifr == 0) {
362			error = EAFNOSUPPORT;		/* XXX */
363			break;
364		}
365		switch (ifr->ifr_addr.sa_family) {
366#ifdef INET
367		case AF_INET:
368			break;
369#endif
370#ifdef INET6
371		case AF_INET6:
372			break;
373#endif
374
375		default:
376			error = EAFNOSUPPORT;
377			break;
378		}
379		break;
380
381#ifdef SIOCSIFMTU
382	case SIOCSIFMTU:
383		ifp->if_mtu = ifr->ifr_mtu;
384		break;
385#endif
386
387	case SIOCSIFFLAGS:
388		break;
389
390	default:
391		error = EINVAL;
392	}
393	return (error);
394}
395
396#ifdef INET6
397/*
398 * XXX could be slow
399 * XXX could be layer violation to call sys/net from sys/netinet6
400 */
401static int
402faithprefix(in6)
403	struct in6_addr *in6;
404{
405	struct rtentry *rt;
406	struct sockaddr_in6 sin6;
407	int ret;
408
409	if (ip6_keepfaith == 0)
410		return 0;
411
412	bzero(&sin6, sizeof(sin6));
413	sin6.sin6_family = AF_INET6;
414	sin6.sin6_len = sizeof(struct sockaddr_in6);
415	sin6.sin6_addr = *in6;
416	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
417	if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
418	    (rt->rt_ifp->if_flags & IFF_UP) != 0)
419		ret = 1;
420	else
421		ret = 0;
422	if (rt)
423		RTFREE(rt);
424	return ret;
425}
426#endif
427