xref: /csrg-svn/sys/net/if_loop.c (revision 56529)
123174Smckusick /*
229071Skarels  * Copyright (c) 1982, 1986 Regents of the University of California.
333183Sbostic  * All rights reserved.
423174Smckusick  *
544464Sbostic  * %sccs.include.redist.c%
633183Sbostic  *
7*56529Sbostic  *	@(#)if_loop.c	7.18 (Berkeley) 10/11/92
823174Smckusick  */
95122Swnj 
105122Swnj /*
115122Swnj  * Loopback interface driver for protocol testing and timing.
125122Swnj  */
135122Swnj 
14*56529Sbostic #include <sys/param.h>
15*56529Sbostic #include <sys/systm.h>
16*56529Sbostic #include <sys/kernel.h>
17*56529Sbostic #include <sys/mbuf.h>
18*56529Sbostic #include <sys/socket.h>
19*56529Sbostic #include <sys/errno.h>
20*56529Sbostic #include <sys/ioctl.h>
21*56529Sbostic #include <sys/time.h>
22*56529Sbostic #include <machine/cpu.h>
2310907Ssam 
24*56529Sbostic #include <net/if.h>
25*56529Sbostic #include <net/if_types.h>
26*56529Sbostic #include <net/netisr.h>
27*56529Sbostic #include <net/route.h>
28*56529Sbostic #include <net/bpf.h>
2910907Ssam 
3024771Skarels #ifdef	INET
31*56529Sbostic #include <netinet/in.h>
32*56529Sbostic #include <netinet/in_systm.h>
33*56529Sbostic #include <netinet/in_var.h>
34*56529Sbostic #include <netinet/ip.h>
3524771Skarels #endif
365122Swnj 
3718815Ssklower #ifdef NS
38*56529Sbostic #include <netns/ns.h>
39*56529Sbostic #include <netns/ns_if.h>
4018815Ssklower #endif
4118815Ssklower 
4237472Ssklower #ifdef ISO
43*56529Sbostic #include <netiso/iso.h>
44*56529Sbostic #include <netiso/iso_var.h>
4537472Ssklower #endif
4637472Ssklower 
4754718Ssklower #include "bpfilter.h"
4854718Ssklower 
495207Swnj #define	LOMTU	(1024+512)
505122Swnj 
515122Swnj struct	ifnet loif;
5213066Ssam int	looutput(), loioctl();
535122Swnj 
545122Swnj loattach()
555122Swnj {
565122Swnj 	register struct ifnet *ifp = &loif;
575122Swnj 
585172Swnj 	ifp->if_name = "lo";
595122Swnj 	ifp->if_mtu = LOMTU;
6054718Ssklower #ifdef MULTICAST
6154718Ssklower 	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
6254718Ssklower #else
6326091Skarels 	ifp->if_flags = IFF_LOOPBACK;
6454718Ssklower #endif
6513066Ssam 	ifp->if_ioctl = loioctl;
665122Swnj 	ifp->if_output = looutput;
6737472Ssklower 	ifp->if_type = IFT_LOOP;
6837472Ssklower 	ifp->if_hdrlen = 0;
6937472Ssklower 	ifp->if_addrlen = 0;
705161Swnj 	if_attach(ifp);
7154718Ssklower #if NBPFILTER > 0
7254718Ssklower 	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
7354718Ssklower #endif
745122Swnj }
755122Swnj 
7645198Ssklower looutput(ifp, m, dst, rt)
775122Swnj 	struct ifnet *ifp;
7835795Skarels 	register struct mbuf *m;
796337Ssam 	struct sockaddr *dst;
8045198Ssklower 	register struct rtentry *rt;
815122Swnj {
8245523Ssklower 	int s, isr;
8345523Ssklower 	register struct ifqueue *ifq = 0;
845122Swnj 
8535795Skarels 	if ((m->m_flags & M_PKTHDR) == 0)
8635795Skarels 		panic("looutput no HDR");
8754718Ssklower 	ifp->if_lastchange = time;
8854718Ssklower #if NBPFILTER > 0
8954718Ssklower 	if (loif.if_bpf) {
9054718Ssklower 		/*
9154718Ssklower 		 * We need to prepend the address family as
9254718Ssklower 		 * a four byte field.  Cons up a dummy header
9354718Ssklower 		 * to pacify bpf.  This is safe because bpf
9454718Ssklower 		 * will only read from the mbuf (i.e., it won't
9554718Ssklower 		 * try to free it or keep a pointer a to it).
9654718Ssklower 		 */
9754718Ssklower 		struct mbuf m0;
9854718Ssklower 		u_int af = dst->sa_family;
9954718Ssklower 
10054718Ssklower 		m0.m_next = m;
10154718Ssklower 		m0.m_len = 4;
10254718Ssklower 		m0.m_data = (char *)&af;
10354718Ssklower 
10454718Ssklower 		bpf_mtap(loif.if_bpf, &m0);
10554718Ssklower 	}
10654718Ssklower #endif
10735795Skarels 	m->m_pkthdr.rcvif = ifp;
10835795Skarels 
10945198Ssklower 	if (rt && rt->rt_flags & RTF_REJECT) {
11045198Ssklower 		m_freem(m);
11145198Ssklower 		return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
11245198Ssklower 	}
1135172Swnj 	ifp->if_opackets++;
11439187Ssklower 	ifp->if_obytes += m->m_pkthdr.len;
1156337Ssam 	switch (dst->sa_family) {
1165122Swnj 
1175122Swnj #ifdef INET
1186337Ssam 	case AF_INET:
1196209Swnj 		ifq = &ipintrq;
12045523Ssklower 		isr = NETISR_IP;
1215122Swnj 		break;
1225122Swnj #endif
12318815Ssklower #ifdef NS
12418815Ssklower 	case AF_NS:
12518815Ssklower 		ifq = &nsintrq;
12645523Ssklower 		isr = NETISR_NS;
12718815Ssklower 		break;
12818815Ssklower #endif
12937472Ssklower #ifdef ISO
13037472Ssklower 	case AF_ISO:
13137472Ssklower 		ifq = &clnlintrq;
13245523Ssklower 		isr = NETISR_ISO;
13337472Ssklower 		break;
13437472Ssklower #endif
1355122Swnj 	default:
1366337Ssam 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
1376337Ssam 			dst->sa_family);
13835795Skarels 		m_freem(m);
1396544Sfeldman 		return (EAFNOSUPPORT);
1405122Swnj 	}
14148727Ssklower 	s = splimp();
14245523Ssklower 	if (IF_QFULL(ifq)) {
14345523Ssklower 		IF_DROP(ifq);
14445523Ssklower 		m_freem(m);
14545523Ssklower 		splx(s);
14645523Ssklower 		return (ENOBUFS);
14745523Ssklower 	}
14845523Ssklower 	IF_ENQUEUE(ifq, m);
14945523Ssklower 	schednetisr(isr);
1505172Swnj 	ifp->if_ipackets++;
15139187Ssklower 	ifp->if_ibytes += m->m_pkthdr.len;
1525122Swnj 	splx(s);
1536544Sfeldman 	return (0);
1545122Swnj }
15513066Ssam 
15648727Ssklower /* ARGSUSED */
15754718Ssklower void
15848727Ssklower lortrequest(cmd, rt, sa)
15952947Storek 	int cmd;
16052947Storek 	struct rtentry *rt;
16152947Storek 	struct sockaddr *sa;
16248727Ssklower {
16352947Storek 
16448727Ssklower 	if (rt)
16548727Ssklower 		rt->rt_rmx.rmx_mtu = LOMTU;
16648727Ssklower }
16748727Ssklower 
16813066Ssam /*
16913066Ssam  * Process an ioctl request.
17013066Ssam  */
17118370Skarels /* ARGSUSED */
17213066Ssam loioctl(ifp, cmd, data)
17313066Ssam 	register struct ifnet *ifp;
17413066Ssam 	int cmd;
17513066Ssam 	caddr_t data;
17613066Ssam {
17748727Ssklower 	register struct ifaddr *ifa;
17854718Ssklower #ifdef MULTICAST
17954718Ssklower 	register struct ifreq *ifr;
18054718Ssklower #endif
18154718Ssklower 	register int error = 0;
18213066Ssam 
18313066Ssam 	switch (cmd) {
18413066Ssam 
18513066Ssam 	case SIOCSIFADDR:
18618370Skarels 		ifp->if_flags |= IFF_UP;
18748727Ssklower 		ifa = (struct ifaddr *)data;
18848727Ssklower 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
18948727Ssklower 			ifa->ifa_rtrequest = lortrequest;
19018370Skarels 		/*
19118370Skarels 		 * Everything else is done at a higher level.
19218370Skarels 		 */
19313066Ssam 		break;
19413066Ssam 
19554718Ssklower #ifdef MULTICAST
19654718Ssklower 	case SIOCADDMULTI:
19754718Ssklower 	case SIOCDELMULTI:
19854718Ssklower 		ifr = (struct ifreq *)data;
19954718Ssklower 		if (ifr == 0) {
20054718Ssklower 			error = EAFNOSUPPORT;		/* XXX */
20154718Ssklower 			break;
20254718Ssklower 		}
20354718Ssklower 		switch (ifr->ifr_addr.sa_family) {
20454718Ssklower 
20554718Ssklower #ifdef INET
20654718Ssklower 		case AF_INET:
20754718Ssklower 			break;
20854718Ssklower #endif
20954718Ssklower 
21054718Ssklower 		default:
21154718Ssklower 			error = EAFNOSUPPORT;
21254718Ssklower 			break;
21354718Ssklower 		}
21454718Ssklower 		break;
21554718Ssklower #endif
21654718Ssklower 
21713066Ssam 	default:
21813066Ssam 		error = EINVAL;
21913066Ssam 	}
22013066Ssam 	return (error);
22113066Ssam }
222