if_loop.c revision 113255
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. All advertising materials mentioning features or use of this software
141541Srgrimes *    must display the following acknowledgement:
151541Srgrimes *	This product includes software developed by the University of
161541Srgrimes *	California, Berkeley and its contributors.
171541Srgrimes * 4. Neither the name of the University nor the names of its contributors
181541Srgrimes *    may be used to endorse or promote products derived from this software
191541Srgrimes *    without specific prior written permission.
201541Srgrimes *
211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311541Srgrimes * SUCH DAMAGE.
321541Srgrimes *
3385051Sru *	@(#)if_loop.c	8.2 (Berkeley) 1/9/95
3450477Speter * $FreeBSD: head/sys/net/if_loop.c 113255 2003-04-08 14:25:47Z des $
351541Srgrimes */
361541Srgrimes
371541Srgrimes/*
381541Srgrimes * Loopback interface driver for protocol testing and timing.
391541Srgrimes */
401541Srgrimes
4132356Seivind#include "opt_atalk.h"
4232350Seivind#include "opt_inet.h"
4354263Sshin#include "opt_inet6.h"
4431742Seivind#include "opt_ipx.h"
45108041Srwatson#include "opt_mac.h"
4631742Seivind
471541Srgrimes#include <sys/param.h>
481541Srgrimes#include <sys/systm.h>
491541Srgrimes#include <sys/kernel.h>
50108041Srwatson#include <sys/mac.h>
5171791Speter#include <sys/malloc.h>
521541Srgrimes#include <sys/mbuf.h>
5371862Speter#include <sys/module.h>
5491648Sbrooks#include <machine/bus.h>
5591648Sbrooks#include <sys/rman.h>
561541Srgrimes#include <sys/socket.h>
5724204Sbde#include <sys/sockio.h>
5871791Speter#include <sys/sysctl.h>
591541Srgrimes
601541Srgrimes#include <net/if.h>
611541Srgrimes#include <net/if_types.h>
621541Srgrimes#include <net/netisr.h>
631541Srgrimes#include <net/route.h>
641541Srgrimes#include <net/bpf.h>
6578064Sume#include <net/bpfdesc.h>
661541Srgrimes
671541Srgrimes#ifdef	INET
681541Srgrimes#include <netinet/in.h>
691541Srgrimes#include <netinet/in_var.h>
701541Srgrimes#endif
711541Srgrimes
7211819Sjulian#ifdef IPX
7311819Sjulian#include <netipx/ipx.h>
7411819Sjulian#include <netipx/ipx_if.h>
7511819Sjulian#endif
7611819Sjulian
7753541Sshin#ifdef INET6
7853541Sshin#ifndef INET
7953541Sshin#include <netinet/in.h>
8053541Sshin#endif
8153541Sshin#include <netinet6/in6_var.h>
8262587Sitojun#include <netinet/ip6.h>
8353541Sshin#endif
8453541Sshin
8515885Sjulian#ifdef NETATALK
8615885Sjulian#include <netatalk/at.h>
8715885Sjulian#include <netatalk/at_var.h>
8883268Speter#endif
8915885Sjulian
901622Sdg#ifdef TINY_LOMTU
911541Srgrimes#define	LOMTU	(1024+512)
9253541Sshin#elif defined(LARGE_LOMTU)
9353541Sshin#define LOMTU	131072
941622Sdg#else
956876Sdg#define LOMTU	16384
961622Sdg#endif
971541Srgrimes
9891648Sbrooks#define LONAME	"lo"
991541Srgrimes
10071791Speterstruct lo_softc {
10171791Speter	struct	ifnet sc_if;		/* network-visible interface */
10287914Sjlemon	LIST_ENTRY(lo_softc) sc_next;
10371791Speter};
10491648Sbrooks
10591648Sbrooksint		loioctl(struct ifnet *, u_long, caddr_t);
10691648Sbrooksstatic void	lortrequest(int, struct rtentry *, struct rt_addrinfo *);
10791648Sbrooksint		looutput(struct ifnet *ifp, struct mbuf *m,
10891648Sbrooks		    struct sockaddr *dst, struct rtentry *rt);
10992081Smuxint		lo_clone_create(struct if_clone *, int);
11097289Sbrooksvoid		lo_clone_destroy(struct ifnet *);
11191648Sbrooks
11291648Sbrooksstruct ifnet *loif = NULL;			/* Used externally */
11391648Sbrooks
11491648Sbrooksstatic MALLOC_DEFINE(M_LO, LONAME, "Loopback Interface");
11591648Sbrooks
11671791Speterstatic LIST_HEAD(lo_list, lo_softc) lo_list;
11771791Speter
11897289Sbrooksstruct if_clone lo_cloner = IF_CLONE_INITIALIZER(LONAME,
11997289Sbrooks    lo_clone_create, lo_clone_destroy, 1, IF_MAXUNIT);
12091648Sbrooks
12197289Sbrooksvoid
12291648Sbrookslo_clone_destroy(ifp)
12391648Sbrooks	struct ifnet *ifp;
12491648Sbrooks{
12591648Sbrooks	struct lo_softc *sc;
12691648Sbrooks
12791648Sbrooks	sc = ifp->if_softc;
12891648Sbrooks
12997289Sbrooks	/* XXX: destroying lo0 will lead to panics. */
13097289Sbrooks	KASSERT(loif != ifp, ("%s: destroying lo0", __func__));
13191648Sbrooks
13291648Sbrooks	bpfdetach(ifp);
13391648Sbrooks	if_detach(ifp);
13491648Sbrooks	LIST_REMOVE(sc, sc_next);
13593752Sluigi	free(sc, M_LO);
13691648Sbrooks}
13791648Sbrooks
13892081Smuxint
13992081Smuxlo_clone_create(ifc, unit)
14092081Smux	struct if_clone *ifc;
14192081Smux	int unit;
14271791Speter{
14371791Speter	struct lo_softc *sc;
14471791Speter
145111119Simp	MALLOC(sc, struct lo_softc *, sizeof(*sc), M_LO, M_WAITOK | M_ZERO);
14671791Speter
14791648Sbrooks	sc->sc_if.if_name = LONAME;
14871791Speter	sc->sc_if.if_unit = unit;
14971791Speter	sc->sc_if.if_mtu = LOMTU;
15071791Speter	sc->sc_if.if_flags = IFF_LOOPBACK | IFF_MULTICAST;
15171791Speter	sc->sc_if.if_ioctl = loioctl;
15271791Speter	sc->sc_if.if_output = looutput;
15371791Speter	sc->sc_if.if_type = IFT_LOOP;
15471791Speter	sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
15591648Sbrooks	sc->sc_if.if_softc = sc;
15671791Speter	if_attach(&sc->sc_if);
15771791Speter	bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
15871791Speter	LIST_INSERT_HEAD(&lo_list, sc, sc_next);
15971791Speter	if (loif == NULL)
16071791Speter		loif = &sc->sc_if;
16192081Smux
16292081Smux	return (0);
16371791Speter}
16471791Speter
16571791Speterstatic int
16671862Speterloop_modevent(module_t mod, int type, void *data)
16771862Speter{
16871862Speter	switch (type) {
16971862Speter	case MOD_LOAD:
17091648Sbrooks		LIST_INIT(&lo_list);
17191648Sbrooks		if_clone_attach(&lo_cloner);
17271862Speter		break;
17371862Speter	case MOD_UNLOAD:
17471862Speter		printf("loop module unload - not possible for this module type\n");
17571862Speter		return EINVAL;
17671862Speter	}
17771862Speter	return 0;
17871862Speter}
1791541Srgrimes
18071862Speterstatic moduledata_t loop_mod = {
18171862Speter	"loop",
18271862Speter	loop_modevent,
18371862Speter	0
18471862Speter};
18571862Speter
18671862SpeterDECLARE_MODULE(loop, loop_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
18771862Speter
18854263Sshinint
1891541Srgrimeslooutput(ifp, m, dst, rt)
1901541Srgrimes	struct ifnet *ifp;
1911541Srgrimes	register struct mbuf *m;
1921541Srgrimes	struct sockaddr *dst;
1931541Srgrimes	register struct rtentry *rt;
1941541Srgrimes{
19536908Sjulian
196113255Sdes	M_ASSERTPKTHDR(m); /* check if we have the packet header */
197113255Sdes
19836908Sjulian	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
19936908Sjulian		m_freem(m);
20036908Sjulian		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
20136908Sjulian		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
20236908Sjulian	}
20353541Sshin	/*
20453541Sshin	 * KAME requires that the packet to be contiguous on the
20553541Sshin	 * mbuf.  We need to make that sure.
20653541Sshin	 * this kind of code should be avoided.
20753541Sshin	 * XXX: fails to join if interface MTU > MCLBYTES.  jumbogram?
20853541Sshin	 */
20953541Sshin	if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) {
21053541Sshin		struct mbuf *n;
21153541Sshin
212108466Ssam		/* XXX MT_HEADER should be m->m_type */
213111119Simp		MGETHDR(n, M_DONTWAIT, MT_HEADER);
21453541Sshin		if (!n)
21553541Sshin			goto contiguousfail;
216108466Ssam		M_MOVE_PKTHDR(n, m);
217108466Ssam#ifdef MAC
218108466Ssam		/*
219108466Ssam		 * XXXMAC: Once we put labels in tags and proper
220108466Ssam		 * primitives are used for relocating mbuf header
221108466Ssam		 * data, this will no longer be required.
222108466Ssam		 */
223108466Ssam		m->m_pkthdr.label.l_flags &= ~MAC_FLAG_INITIALIZED;
224108466Ssam#endif
225111119Simp		MCLGET(n, M_DONTWAIT);
22653541Sshin		if (! (n->m_flags & M_EXT)) {
22753541Sshin			m_freem(n);
22853541Sshin			goto contiguousfail;
22953541Sshin		}
23053541Sshin
231108825Ssam		m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t));
232108825Ssam		n->m_len = n->m_pkthdr.len;
23353541Sshin		m_freem(m);
23453541Sshin		m = n;
23553541Sshin	}
23653541Sshin	if (0) {
23753541Sshincontiguousfail:
23853541Sshin		printf("looutput: mbuf allocation failed\n");
23953541Sshin	}
24053541Sshin
24136908Sjulian	ifp->if_opackets++;
24236908Sjulian	ifp->if_obytes += m->m_pkthdr.len;
24336992Sjulian#if 1	/* XXX */
24436992Sjulian	switch (dst->sa_family) {
24536992Sjulian	case AF_INET:
24653541Sshin	case AF_INET6:
24736992Sjulian	case AF_IPX:
24836992Sjulian	case AF_APPLETALK:
24936994Sjulian		break;
25036992Sjulian	default:
25165454Srwatson		printf("looutput: af=%d unexpected\n", dst->sa_family);
25236992Sjulian		m_freem(m);
25336992Sjulian		return (EAFNOSUPPORT);
25436992Sjulian	}
25536992Sjulian#endif
25660889Sarchie	return(if_simloop(ifp, m, dst->sa_family, 0));
25736908Sjulian}
25836908Sjulian
25936908Sjulian/*
26036908Sjulian * if_simloop()
26136908Sjulian *
26236908Sjulian * This function is to support software emulation of hardware loopback,
26336908Sjulian * i.e., for interfaces with the IFF_SIMPLEX attribute. Since they can't
26436908Sjulian * hear their own broadcasts, we create a copy of the packet that we
26536908Sjulian * would normally receive via a hardware loopback.
26636908Sjulian *
26736908Sjulian * This function expects the packet to include the media header of length hlen.
26836908Sjulian */
26936908Sjulian
27036908Sjulianint
27160889Sarchieif_simloop(ifp, m, af, hlen)
27236908Sjulian	struct ifnet *ifp;
27378064Sume	struct mbuf *m;
27460889Sarchie	int af;
27536908Sjulian	int hlen;
27636908Sjulian{
27769152Sjlemon	int isr;
2781541Srgrimes
279113255Sdes	M_ASSERTPKTHDR(m);
28036908Sjulian	m->m_pkthdr.rcvif = ifp;
28160889Sarchie
28210957Swollman	/* BPF write needs to be handled specially */
28360889Sarchie	if (af == AF_UNSPEC) {
28460889Sarchie		KASSERT(m->m_len >= sizeof(int), ("if_simloop: m_len"));
28560889Sarchie		af = *(mtod(m, int *));
28610957Swollman		m->m_len -= sizeof(int);
28710957Swollman		m->m_pkthdr.len -= sizeof(int);
28810957Swollman		m->m_data += sizeof(int);
28910957Swollman	}
29010957Swollman
29160889Sarchie	/* Let BPF see incoming packet */
2928090Spst	if (ifp->if_bpf) {
29336908Sjulian		struct mbuf m0, *n = m;
2941541Srgrimes
29578064Sume		if (ifp->if_bpf->bif_dlt == DLT_NULL) {
29678064Sume			/*
29778064Sume			 * We need to prepend the address family as
29878064Sume			 * a four byte field.  Cons up a dummy header
29978064Sume			 * to pacify bpf.  This is safe because bpf
30078064Sume			 * will only read from the mbuf (i.e., it won't
30178064Sume			 * try to free it or keep a pointer a to it).
30278064Sume			 */
30378064Sume			m0.m_next = m;
30478064Sume			m0.m_len = 4;
30578064Sume			m0.m_data = (char *)&af;
30678064Sume			n = &m0;
30778064Sume		}
308106939Ssam		BPF_MTAP(ifp, n);
3091541Srgrimes	}
3101541Srgrimes
31136908Sjulian	/* Strip away media header */
31237600Sdfr	if (hlen > 0) {
31360952Sgallatin		m_adj(m, hlen);
31488660Sjake#if defined(__alpha__) || defined(__ia64__) || defined(__sparc64__)
31537600Sdfr		/* The alpha doesn't like unaligned data.
31637600Sdfr		 * We move data down in the first mbuf */
31760952Sgallatin		if (mtod(m, vm_offset_t) & 3) {
31861181Smjacob			KASSERT(hlen >= 3, ("if_simloop: hlen too small"));
31960952Sgallatin			bcopy(m->m_data,
32060952Sgallatin			    (char *)(mtod(m, vm_offset_t)
32160952Sgallatin				- (mtod(m, vm_offset_t) & 3)),
32260952Sgallatin			    m->m_len);
32360952Sgallatin			mtod(m,vm_offset_t) -= (mtod(m, vm_offset_t) & 3);
32460952Sgallatin		}
32537600Sdfr#endif
32637600Sdfr	}
32736908Sjulian
32860889Sarchie	/* Deliver to upper layer protocol */
32960889Sarchie	switch (af) {
3301541Srgrimes#ifdef INET
3311541Srgrimes	case AF_INET:
3321541Srgrimes		isr = NETISR_IP;
3331541Srgrimes		break;
3341541Srgrimes#endif
33553541Sshin#ifdef INET6
33653541Sshin	case AF_INET6:
33753541Sshin		m->m_flags |= M_LOOP;
33853541Sshin		isr = NETISR_IPV6;
33953541Sshin		break;
34053541Sshin#endif
34111819Sjulian#ifdef IPX
34211819Sjulian	case AF_IPX:
34311819Sjulian		isr = NETISR_IPX;
34411819Sjulian		break;
34511819Sjulian#endif
34615885Sjulian#ifdef NETATALK
34715885Sjulian	case AF_APPLETALK:
348111888Sjlemon		isr = NETISR_ATALK2;
34915885Sjulian		break;
35083268Speter#endif
3511541Srgrimes	default:
35260889Sarchie		printf("if_simloop: can't handle af=%d\n", af);
3531541Srgrimes		m_freem(m);
3541541Srgrimes		return (EAFNOSUPPORT);
3551541Srgrimes	}
3561541Srgrimes	ifp->if_ipackets++;
3571541Srgrimes	ifp->if_ibytes += m->m_pkthdr.len;
358111888Sjlemon	netisr_dispatch(isr, m);
3591541Srgrimes	return (0);
3601541Srgrimes}
3611541Srgrimes
3621541Srgrimes/* ARGSUSED */
36312706Sphkstatic void
36485074Srulortrequest(cmd, rt, info)
3651541Srgrimes	int cmd;
3661541Srgrimes	struct rtentry *rt;
36785074Sru	struct rt_addrinfo *info;
3681541Srgrimes{
36913928Swollman	if (rt) {
37013928Swollman		rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
37113928Swollman		/*
37213928Swollman		 * For optimal performance, the send and receive buffers
37313928Swollman		 * should be at least twice the MTU plus a little more for
37413928Swollman		 * overhead.
37513928Swollman		 */
37653541Sshin		rt->rt_rmx.rmx_recvpipe =
37713928Swollman			rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
37813928Swollman	}
3791541Srgrimes}
3801541Srgrimes
3811541Srgrimes/*
3821541Srgrimes * Process an ioctl request.
3831541Srgrimes */
3841541Srgrimes/* ARGSUSED */
38554263Sshinint
3861541Srgrimesloioctl(ifp, cmd, data)
3871541Srgrimes	register struct ifnet *ifp;
38836735Sdfr	u_long cmd;
3891541Srgrimes	caddr_t data;
3901541Srgrimes{
3911541Srgrimes	register struct ifaddr *ifa;
3921944Sdg	register struct ifreq *ifr = (struct ifreq *)data;
3931541Srgrimes	register int error = 0;
3941541Srgrimes
3951541Srgrimes	switch (cmd) {
3961541Srgrimes
3971541Srgrimes	case SIOCSIFADDR:
39816512Swollman		ifp->if_flags |= IFF_UP | IFF_RUNNING;
3991541Srgrimes		ifa = (struct ifaddr *)data;
40013928Swollman		ifa->ifa_rtrequest = lortrequest;
4011541Srgrimes		/*
4021541Srgrimes		 * Everything else is done at a higher level.
4031541Srgrimes		 */
4041541Srgrimes		break;
4051541Srgrimes
4061541Srgrimes	case SIOCADDMULTI:
4071541Srgrimes	case SIOCDELMULTI:
4081541Srgrimes		if (ifr == 0) {
4091541Srgrimes			error = EAFNOSUPPORT;		/* XXX */
4101541Srgrimes			break;
4111541Srgrimes		}
4121541Srgrimes		switch (ifr->ifr_addr.sa_family) {
4131541Srgrimes
4141541Srgrimes#ifdef INET
4151541Srgrimes		case AF_INET:
4161541Srgrimes			break;
4171541Srgrimes#endif
41853541Sshin#ifdef INET6
41953541Sshin		case AF_INET6:
42053541Sshin			break;
42153541Sshin#endif
4221541Srgrimes
4231541Srgrimes		default:
4241541Srgrimes			error = EAFNOSUPPORT;
4251541Srgrimes			break;
4261541Srgrimes		}
4271541Srgrimes		break;
4281541Srgrimes
4291944Sdg	case SIOCSIFMTU:
43049468Sbrian		ifp->if_mtu = ifr->ifr_mtu;
4311944Sdg		break;
4321944Sdg
43335563Sphk	case SIOCSIFFLAGS:
43435563Sphk		break;
43535563Sphk
4361541Srgrimes	default:
4371541Srgrimes		error = EINVAL;
4381541Srgrimes	}
4391541Srgrimes	return (error);
4401541Srgrimes}
441