if_loop.c revision 195837
1139823Simp/*-
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 * 4. Neither the name of the University nor the names of its contributors
141541Srgrimes *    may be used to endorse or promote products derived from this software
151541Srgrimes *    without specific prior written permission.
161541Srgrimes *
171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271541Srgrimes * SUCH DAMAGE.
281541Srgrimes *
2985051Sru *	@(#)if_loop.c	8.2 (Berkeley) 1/9/95
3050477Speter * $FreeBSD: head/sys/net/if_loop.c 195837 2009-07-23 20:46:49Z rwatson $
311541Srgrimes */
321541Srgrimes
331541Srgrimes/*
341541Srgrimes * Loopback interface driver for protocol testing and timing.
351541Srgrimes */
361541Srgrimes
3732356Seivind#include "opt_atalk.h"
3832350Seivind#include "opt_inet.h"
3954263Sshin#include "opt_inet6.h"
4031742Seivind#include "opt_ipx.h"
4131742Seivind
421541Srgrimes#include <sys/param.h>
431541Srgrimes#include <sys/systm.h>
441541Srgrimes#include <sys/kernel.h>
451541Srgrimes#include <sys/mbuf.h>
4671862Speter#include <sys/module.h>
4791648Sbrooks#include <machine/bus.h>
4891648Sbrooks#include <sys/rman.h>
491541Srgrimes#include <sys/socket.h>
5024204Sbde#include <sys/sockio.h>
5171791Speter#include <sys/sysctl.h>
52181803Sbz#include <sys/vimage.h>
531541Srgrimes
541541Srgrimes#include <net/if.h>
55130933Sbrooks#include <net/if_clone.h>
561541Srgrimes#include <net/if_types.h>
571541Srgrimes#include <net/netisr.h>
581541Srgrimes#include <net/route.h>
591541Srgrimes#include <net/bpf.h>
60185571Sbz#include <net/vnet.h>
611541Srgrimes
621541Srgrimes#ifdef	INET
631541Srgrimes#include <netinet/in.h>
641541Srgrimes#include <netinet/in_var.h>
651541Srgrimes#endif
661541Srgrimes
6711819Sjulian#ifdef IPX
6811819Sjulian#include <netipx/ipx.h>
6911819Sjulian#include <netipx/ipx_if.h>
7011819Sjulian#endif
7111819Sjulian
7253541Sshin#ifdef INET6
7353541Sshin#ifndef INET
7453541Sshin#include <netinet/in.h>
7553541Sshin#endif
7653541Sshin#include <netinet6/in6_var.h>
7762587Sitojun#include <netinet/ip6.h>
7853541Sshin#endif
7953541Sshin
8015885Sjulian#ifdef NETATALK
8115885Sjulian#include <netatalk/at.h>
8215885Sjulian#include <netatalk/at_var.h>
8383268Speter#endif
8415885Sjulian
85187039Srwatson#include <security/mac/mac_framework.h>
86187039Srwatson
871622Sdg#ifdef TINY_LOMTU
881541Srgrimes#define	LOMTU	(1024+512)
8953541Sshin#elif defined(LARGE_LOMTU)
9053541Sshin#define LOMTU	131072
911622Sdg#else
926876Sdg#define LOMTU	16384
931622Sdg#endif
941541Srgrimes
95189873Srwatson#define	LO_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP)
96189873Srwatson#define	LO_CSUM_SET		(CSUM_DATA_VALID | CSUM_PSEUDO_HDR | \
97189873Srwatson				    CSUM_IP_CHECKED | CSUM_IP_VALID | \
98189873Srwatson				    CSUM_SCTP_VALID)
99189873Srwatson
10091648Sbrooksint		loioctl(struct ifnet *, u_long, caddr_t);
10191648Sbrooksstatic void	lortrequest(int, struct rtentry *, struct rt_addrinfo *);
10291648Sbrooksint		looutput(struct ifnet *ifp, struct mbuf *m,
103191148Skmacy		    struct sockaddr *dst, struct route *ro);
104160195Ssamstatic int	lo_clone_create(struct if_clone *, int, caddr_t);
105128209Sbrooksstatic void	lo_clone_destroy(struct ifnet *);
10691648Sbrooks
107195699SrwatsonVNET_DEFINE(struct ifnet *, loif);	/* Used externally */
10891648Sbrooks
109192669Szec#ifdef VIMAGE
110195837Srwatsonstatic VNET_DEFINE(struct ifc_simple_data, lo_cloner_data);
111195837Srwatsonstatic VNET_DEFINE(struct if_clone, lo_cloner);
112195727Srwatson#define	V_lo_cloner_data	VNET(lo_cloner_data)
113195727Srwatson#define	V_lo_cloner		VNET(lo_cloner)
114192669Szec#endif
115192669Szec
116130933SbrooksIFC_SIMPLE_DECLARE(lo, 1);
11791648Sbrooks
118128209Sbrooksstatic void
119177965Srwatsonlo_clone_destroy(struct ifnet *ifp)
12091648Sbrooks{
12191648Sbrooks
122193731Szec#ifndef VIMAGE
12397289Sbrooks	/* XXX: destroying lo0 will lead to panics. */
124181803Sbz	KASSERT(V_loif != ifp, ("%s: destroying lo0", __func__));
125193731Szec#endif
12691648Sbrooks
12791648Sbrooks	bpfdetach(ifp);
12891648Sbrooks	if_detach(ifp);
129147256Sbrooks	if_free(ifp);
13091648Sbrooks}
13191648Sbrooks
132128209Sbrooksstatic int
133177965Srwatsonlo_clone_create(struct if_clone *ifc, int unit, caddr_t params)
13471791Speter{
135147256Sbrooks	struct ifnet *ifp;
13671791Speter
137180094Sed	ifp = if_alloc(IFT_LOOP);
138180094Sed	if (ifp == NULL)
139147256Sbrooks		return (ENOSPC);
14071791Speter
141147256Sbrooks	if_initname(ifp, ifc->ifc_name, unit);
142147256Sbrooks	ifp->if_mtu = LOMTU;
143147256Sbrooks	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
144147256Sbrooks	ifp->if_ioctl = loioctl;
145147256Sbrooks	ifp->if_output = looutput;
146147256Sbrooks	ifp->if_snd.ifq_maxlen = ifqmaxlen;
147189871Srwatson	ifp->if_capabilities = ifp->if_capenable = IFCAP_HWCSUM;
148189873Srwatson	ifp->if_hwassist = LO_CSUM_FEATURES;
149147256Sbrooks	if_attach(ifp);
150147611Sdwmalone	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
151181803Sbz	if (V_loif == NULL)
152181803Sbz		V_loif = ifp;
15392081Smux
15492081Smux	return (0);
15571791Speter}
15671791Speter
157195837Srwatsonstatic void
158195837Srwatsonvnet_loif_init(const void *unused __unused)
159190787Szec{
160190787Szec
161192669Szec#ifdef VIMAGE
162195837Srwatson	V_lo_cloner = lo_cloner;
163195837Srwatson	V_lo_cloner_data = lo_cloner_data;
164195837Srwatson	V_lo_cloner.ifc_data = &V_lo_cloner_data;
165195837Srwatson	if_clone_attach(&V_lo_cloner);
166192669Szec#else
167190787Szec	if_clone_attach(&lo_cloner);
168192669Szec#endif
169190787Szec}
170195837SrwatsonVNET_SYSINIT(vnet_loif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
171195837Srwatson    vnet_loif_init, NULL);
172190787Szec
173193731Szec#ifdef VIMAGE
174195837Srwatsonstatic void
175195837Srwatsonvnet_loif_uninit(const void *unused __unused)
176193731Szec{
177193731Szec
178195837Srwatson	if_clone_detach(&V_lo_cloner);
179193731Szec	V_loif = NULL;
180193731Szec}
181195837SrwatsonVNET_SYSUNINIT(vnet_loif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
182195837Srwatson    vnet_loif_uninit, NULL);
183193731Szec#endif
184193731Szec
185193731Szecstatic int
186178883Srwatsonloop_modevent(module_t mod, int type, void *data)
187178883Srwatson{
188177965Srwatson
189178883Srwatson	switch (type) {
190178883Srwatson	case MOD_LOAD:
191178883Srwatson		break;
192177965Srwatson
193178883Srwatson	case MOD_UNLOAD:
194178883Srwatson		printf("loop module unload - not possible for this module type\n");
195177965Srwatson		return (EINVAL);
196177965Srwatson
197132199Sphk	default:
198177965Srwatson		return (EOPNOTSUPP);
199178883Srwatson	}
200177965Srwatson	return (0);
201178883Srwatson}
2021541Srgrimes
203178883Srwatsonstatic moduledata_t loop_mod = {
204178883Srwatson	"loop",
205178883Srwatson	loop_modevent,
20671862Speter	0
207178883Srwatson};
20871862Speter
209121596SkanDECLARE_MODULE(loop, loop_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
21071862Speter
21154263Sshinint
212177965Srwatsonlooutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
213191148Skmacy    struct route *ro)
2141541Srgrimes{
215147611Sdwmalone	u_int32_t af;
216191148Skmacy	struct rtentry *rt = NULL;
217187039Srwatson#ifdef MAC
218187039Srwatson	int error;
219187039Srwatson#endif
220147611Sdwmalone
221113255Sdes	M_ASSERTPKTHDR(m); /* check if we have the packet header */
222113255Sdes
223191148Skmacy	if (ro != NULL)
224191148Skmacy		rt = ro->ro_rt;
225187039Srwatson#ifdef MAC
226187039Srwatson	error = mac_ifnet_check_transmit(ifp, m);
227187039Srwatson	if (error) {
228187039Srwatson		m_freem(m);
229187039Srwatson		return (error);
230187039Srwatson	}
231187039Srwatson#endif
232187039Srwatson
23336908Sjulian	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
23436908Sjulian		m_freem(m);
23536908Sjulian		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
23636908Sjulian		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
23736908Sjulian	}
23853541Sshin
23936908Sjulian	ifp->if_opackets++;
24036908Sjulian	ifp->if_obytes += m->m_pkthdr.len;
241147611Sdwmalone
242147611Sdwmalone	/* BPF writes need to be handled specially. */
243147611Sdwmalone	if (dst->sa_family == AF_UNSPEC) {
244147611Sdwmalone		bcopy(dst->sa_data, &af, sizeof(af));
245147611Sdwmalone		dst->sa_family = af;
246147611Sdwmalone	}
247147611Sdwmalone
24836992Sjulian#if 1	/* XXX */
24936992Sjulian	switch (dst->sa_family) {
25036992Sjulian	case AF_INET:
251189863Srwatson		if (ifp->if_capenable & IFCAP_RXCSUM) {
252189863Srwatson			m->m_pkthdr.csum_data = 0xffff;
253189873Srwatson			m->m_pkthdr.csum_flags = LO_CSUM_SET;
254189863Srwatson		}
255189873Srwatson		m->m_pkthdr.csum_flags &= ~LO_CSUM_FEATURES;
25653541Sshin	case AF_INET6:
25736992Sjulian	case AF_IPX:
25836992Sjulian	case AF_APPLETALK:
25936994Sjulian		break;
26036992Sjulian	default:
26165454Srwatson		printf("looutput: af=%d unexpected\n", dst->sa_family);
26236992Sjulian		m_freem(m);
26336992Sjulian		return (EAFNOSUPPORT);
26436992Sjulian	}
26536992Sjulian#endif
266177965Srwatson	return (if_simloop(ifp, m, dst->sa_family, 0));
26736908Sjulian}
26836908Sjulian
26936908Sjulian/*
27036908Sjulian * if_simloop()
27136908Sjulian *
27236908Sjulian * This function is to support software emulation of hardware loopback,
27336908Sjulian * i.e., for interfaces with the IFF_SIMPLEX attribute. Since they can't
27436908Sjulian * hear their own broadcasts, we create a copy of the packet that we
27536908Sjulian * would normally receive via a hardware loopback.
27636908Sjulian *
27736908Sjulian * This function expects the packet to include the media header of length hlen.
27836908Sjulian */
27936908Sjulianint
280177965Srwatsonif_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen)
28136908Sjulian{
28269152Sjlemon	int isr;
2831541Srgrimes
284113255Sdes	M_ASSERTPKTHDR(m);
285121645Ssam	m_tag_delete_nonpersistent(m);
28636908Sjulian	m->m_pkthdr.rcvif = ifp;
28760889Sarchie
288187039Srwatson#ifdef MAC
289187039Srwatson	mac_ifnet_create_mbuf(ifp, m);
290187039Srwatson#endif
291187039Srwatson
292162539Ssuz	/*
293162539Ssuz	 * Let BPF see incoming packet in the following manner:
294178883Srwatson	 *  - Emulated packet loopback for a simplex interface
295162539Ssuz	 *    (net/if_ethersubr.c)
296162539Ssuz	 *	-> passes it to ifp's BPF
297162539Ssuz	 *  - IPv4/v6 multicast packet loopback (netinet(6)/ip(6)_output.c)
298162539Ssuz	 *	-> not passes it to any BPF
299162539Ssuz	 *  - Normal packet loopback from myself to myself (net/if_loop.c)
300162539Ssuz	 *	-> passes to lo0's BPF (even in case of IPv6, where ifp!=lo0)
301162539Ssuz	 */
302162539Ssuz	if (hlen > 0) {
303162539Ssuz		if (bpf_peers_present(ifp->if_bpf)) {
304123922Ssam			bpf_mtap(ifp->if_bpf, m);
305162539Ssuz		}
306162539Ssuz	} else {
307181803Sbz		if (bpf_peers_present(V_loif->if_bpf)) {
308181803Sbz			if ((m->m_flags & M_MCAST) == 0 || V_loif == ifp) {
309162539Ssuz				/* XXX beware sizeof(af) != 4 */
310181118Srwatson				u_int32_t af1 = af;
311162539Ssuz
312162539Ssuz				/*
313162539Ssuz				 * We need to prepend the address family.
314162539Ssuz				 */
315181803Sbz				bpf_mtap2(V_loif->if_bpf, &af1, sizeof(af1), m);
316162539Ssuz			}
317162539Ssuz		}
3181541Srgrimes	}
3191541Srgrimes
32036908Sjulian	/* Strip away media header */
32137600Sdfr	if (hlen > 0) {
32260952Sgallatin		m_adj(m, hlen);
323166577Scognet#ifndef __NO_STRICT_ALIGNMENT
324158471Sjhb		/*
325158471Sjhb		 * Some archs do not like unaligned data, so
326158471Sjhb		 * we move data down in the first mbuf.
327158471Sjhb		 */
32860952Sgallatin		if (mtod(m, vm_offset_t) & 3) {
32961181Smjacob			KASSERT(hlen >= 3, ("if_simloop: hlen too small"));
330178883Srwatson			bcopy(m->m_data,
331178883Srwatson			    (char *)(mtod(m, vm_offset_t)
33260952Sgallatin				- (mtod(m, vm_offset_t) & 3)),
33360952Sgallatin			    m->m_len);
334132780Skan			m->m_data -= (mtod(m,vm_offset_t) & 3);
33560952Sgallatin		}
33637600Sdfr#endif
33737600Sdfr	}
33836908Sjulian
33960889Sarchie	/* Deliver to upper layer protocol */
34060889Sarchie	switch (af) {
3411541Srgrimes#ifdef INET
3421541Srgrimes	case AF_INET:
3431541Srgrimes		isr = NETISR_IP;
3441541Srgrimes		break;
3451541Srgrimes#endif
34653541Sshin#ifdef INET6
34753541Sshin	case AF_INET6:
34853541Sshin		m->m_flags |= M_LOOP;
34953541Sshin		isr = NETISR_IPV6;
35053541Sshin		break;
35153541Sshin#endif
35211819Sjulian#ifdef IPX
35311819Sjulian	case AF_IPX:
35411819Sjulian		isr = NETISR_IPX;
35511819Sjulian		break;
35611819Sjulian#endif
35715885Sjulian#ifdef NETATALK
35815885Sjulian	case AF_APPLETALK:
359111888Sjlemon		isr = NETISR_ATALK2;
36015885Sjulian		break;
36183268Speter#endif
3621541Srgrimes	default:
36360889Sarchie		printf("if_simloop: can't handle af=%d\n", af);
3641541Srgrimes		m_freem(m);
3651541Srgrimes		return (EAFNOSUPPORT);
3661541Srgrimes	}
3671541Srgrimes	ifp->if_ipackets++;
3681541Srgrimes	ifp->if_ibytes += m->m_pkthdr.len;
369134391Sandre	netisr_queue(isr, m);	/* mbuf is free'd on failure. */
3701541Srgrimes	return (0);
3711541Srgrimes}
3721541Srgrimes
3731541Srgrimes/* ARGSUSED */
37412706Sphkstatic void
375177965Srwatsonlortrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
3761541Srgrimes{
377177965Srwatson
378120727Ssam	RT_LOCK_ASSERT(rt);
379142352Ssam	rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu;
3801541Srgrimes}
3811541Srgrimes
3821541Srgrimes/*
3831541Srgrimes * Process an ioctl request.
3841541Srgrimes */
3851541Srgrimes/* ARGSUSED */
38654263Sshinint
387177965Srwatsonloioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3881541Srgrimes{
389177965Srwatson	struct ifaddr *ifa;
390177965Srwatson	struct ifreq *ifr = (struct ifreq *)data;
391189863Srwatson	int error = 0, mask;
3921541Srgrimes
3931541Srgrimes	switch (cmd) {
3941541Srgrimes	case SIOCSIFADDR:
395148887Srwatson		ifp->if_flags |= IFF_UP;
396148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
3971541Srgrimes		ifa = (struct ifaddr *)data;
39813928Swollman		ifa->ifa_rtrequest = lortrequest;
3991541Srgrimes		/*
4001541Srgrimes		 * Everything else is done at a higher level.
4011541Srgrimes		 */
4021541Srgrimes		break;
4031541Srgrimes
4041541Srgrimes	case SIOCADDMULTI:
4051541Srgrimes	case SIOCDELMULTI:
4061541Srgrimes		if (ifr == 0) {
4071541Srgrimes			error = EAFNOSUPPORT;		/* XXX */
4081541Srgrimes			break;
4091541Srgrimes		}
4101541Srgrimes		switch (ifr->ifr_addr.sa_family) {
4111541Srgrimes
4121541Srgrimes#ifdef INET
4131541Srgrimes		case AF_INET:
4141541Srgrimes			break;
4151541Srgrimes#endif
41653541Sshin#ifdef INET6
41753541Sshin		case AF_INET6:
41853541Sshin			break;
41953541Sshin#endif
4201541Srgrimes
4211541Srgrimes		default:
4221541Srgrimes			error = EAFNOSUPPORT;
4231541Srgrimes			break;
4241541Srgrimes		}
4251541Srgrimes		break;
4261541Srgrimes
4271944Sdg	case SIOCSIFMTU:
42849468Sbrian		ifp->if_mtu = ifr->ifr_mtu;
4291944Sdg		break;
4301944Sdg
43135563Sphk	case SIOCSIFFLAGS:
43235563Sphk		break;
43335563Sphk
434189863Srwatson	case SIOCSIFCAP:
435189863Srwatson		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
436189863Srwatson		if ((mask & IFCAP_RXCSUM) != 0)
437189863Srwatson			ifp->if_capenable ^= IFCAP_RXCSUM;
438189863Srwatson		if ((mask & IFCAP_TXCSUM) != 0)
439189863Srwatson			ifp->if_capenable ^= IFCAP_TXCSUM;
440189863Srwatson		if (ifp->if_capenable & IFCAP_TXCSUM)
441189873Srwatson			ifp->if_hwassist = LO_CSUM_FEATURES;
442189863Srwatson		else
443189863Srwatson			ifp->if_hwassist = 0;
444189863Srwatson		break;
445189863Srwatson
4461541Srgrimes	default:
4471541Srgrimes		error = EINVAL;
4481541Srgrimes	}
4491541Srgrimes	return (error);
4501541Srgrimes}
451