xref: /csrg-svn/sys/net/if_loop.c (revision 54718)
123174Smckusick /*
229071Skarels  * Copyright (c) 1982, 1986 Regents of the University of California.
333183Sbostic  * All rights reserved.
423174Smckusick  *
544464Sbostic  * %sccs.include.redist.c%
633183Sbostic  *
7*54718Ssklower  *	@(#)if_loop.c	7.17 (Berkeley) 07/06/92
823174Smckusick  */
95122Swnj 
105122Swnj /*
115122Swnj  * Loopback interface driver for protocol testing and timing.
125122Swnj  */
135122Swnj 
1417058Sbloom #include "param.h"
1517058Sbloom #include "systm.h"
16*54718Ssklower #include "kernel.h"
1717058Sbloom #include "mbuf.h"
1817058Sbloom #include "socket.h"
1917058Sbloom #include "errno.h"
2017058Sbloom #include "ioctl.h"
2152270Storek #include "machine/cpu.h"
22*54718Ssklower #include "time.h"
2310907Ssam 
2452270Storek #include "if.h"
2552270Storek #include "if_types.h"
2652270Storek #include "netisr.h"
2752270Storek #include "route.h"
28*54718Ssklower #include "bpf.h"
2910907Ssam 
3024771Skarels #ifdef	INET
3152271Ssklower #include "netinet/in.h"
3252271Ssklower #include "netinet/in_systm.h"
3352271Ssklower #include "netinet/in_var.h"
3452271Ssklower #include "netinet/ip.h"
3524771Skarels #endif
365122Swnj 
3718815Ssklower #ifdef NS
3852271Ssklower #include "netns/ns.h"
3952271Ssklower #include "netns/ns_if.h"
4018815Ssklower #endif
4118815Ssklower 
4237472Ssklower #ifdef ISO
4352271Ssklower #include "netiso/iso.h"
4452271Ssklower #include "netiso/iso_var.h"
4537472Ssklower #endif
4637472Ssklower 
47*54718Ssklower #include "bpfilter.h"
48*54718Ssklower 
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;
60*54718Ssklower #ifdef MULTICAST
61*54718Ssklower 	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
62*54718Ssklower #else
6326091Skarels 	ifp->if_flags = IFF_LOOPBACK;
64*54718Ssklower #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);
71*54718Ssklower #if NBPFILTER > 0
72*54718Ssklower 	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
73*54718Ssklower #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");
87*54718Ssklower 	ifp->if_lastchange = time;
88*54718Ssklower #if NBPFILTER > 0
89*54718Ssklower 	if (loif.if_bpf) {
90*54718Ssklower 		/*
91*54718Ssklower 		 * We need to prepend the address family as
92*54718Ssklower 		 * a four byte field.  Cons up a dummy header
93*54718Ssklower 		 * to pacify bpf.  This is safe because bpf
94*54718Ssklower 		 * will only read from the mbuf (i.e., it won't
95*54718Ssklower 		 * try to free it or keep a pointer a to it).
96*54718Ssklower 		 */
97*54718Ssklower 		struct mbuf m0;
98*54718Ssklower 		u_int af = dst->sa_family;
99*54718Ssklower 
100*54718Ssklower 		m0.m_next = m;
101*54718Ssklower 		m0.m_len = 4;
102*54718Ssklower 		m0.m_data = (char *)⁡
103*54718Ssklower 
104*54718Ssklower 		bpf_mtap(loif.if_bpf, &m0);
105*54718Ssklower 	}
106*54718Ssklower #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 */
157*54718Ssklower 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;
178*54718Ssklower #ifdef MULTICAST
179*54718Ssklower 	register struct ifreq *ifr;
180*54718Ssklower #endif
181*54718Ssklower 	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 
195*54718Ssklower #ifdef MULTICAST
196*54718Ssklower 	case SIOCADDMULTI:
197*54718Ssklower 	case SIOCDELMULTI:
198*54718Ssklower 		ifr = (struct ifreq *)data;
199*54718Ssklower 		if (ifr == 0) {
200*54718Ssklower 			error = EAFNOSUPPORT;		/* XXX */
201*54718Ssklower 			break;
202*54718Ssklower 		}
203*54718Ssklower 		switch (ifr->ifr_addr.sa_family) {
204*54718Ssklower 
205*54718Ssklower #ifdef INET
206*54718Ssklower 		case AF_INET:
207*54718Ssklower 			break;
208*54718Ssklower #endif
209*54718Ssklower 
210*54718Ssklower 		default:
211*54718Ssklower 			error = EAFNOSUPPORT;
212*54718Ssklower 			break;
213*54718Ssklower 		}
214*54718Ssklower 		break;
215*54718Ssklower #endif
216*54718Ssklower 
21713066Ssam 	default:
21813066Ssam 		error = EINVAL;
21913066Ssam 	}
22013066Ssam 	return (error);
22113066Ssam }
222