xref: /csrg-svn/sys/net/if_loop.c (revision 68168)
123174Smckusick /*
263211Sbostic  * Copyright (c) 1982, 1986, 1993
363211Sbostic  *	The Regents of the University of California.  All rights reserved.
423174Smckusick  *
544464Sbostic  * %sccs.include.redist.c%
633183Sbostic  *
7*68168Scgd  *	@(#)if_loop.c	8.2 (Berkeley) 01/09/95
823174Smckusick  */
95122Swnj 
105122Swnj /*
115122Swnj  * Loopback interface driver for protocol testing and timing.
125122Swnj  */
135122Swnj 
1456529Sbostic #include <sys/param.h>
1556529Sbostic #include <sys/systm.h>
1656529Sbostic #include <sys/kernel.h>
1756529Sbostic #include <sys/mbuf.h>
1856529Sbostic #include <sys/socket.h>
1956529Sbostic #include <sys/errno.h>
2056529Sbostic #include <sys/ioctl.h>
2156529Sbostic #include <sys/time.h>
2256529Sbostic #include <machine/cpu.h>
2310907Ssam 
2456529Sbostic #include <net/if.h>
2556529Sbostic #include <net/if_types.h>
2656529Sbostic #include <net/netisr.h>
2756529Sbostic #include <net/route.h>
2856529Sbostic #include <net/bpf.h>
2910907Ssam 
3024771Skarels #ifdef	INET
3156529Sbostic #include <netinet/in.h>
3256529Sbostic #include <netinet/in_systm.h>
3356529Sbostic #include <netinet/in_var.h>
3456529Sbostic #include <netinet/ip.h>
3524771Skarels #endif
365122Swnj 
3718815Ssklower #ifdef NS
3856529Sbostic #include <netns/ns.h>
3956529Sbostic #include <netns/ns_if.h>
4018815Ssklower #endif
4118815Ssklower 
4237472Ssklower #ifdef ISO
4356529Sbostic #include <netiso/iso.h>
4456529Sbostic #include <netiso/iso_var.h>
4537472Ssklower #endif
4637472Ssklower 
4754718Ssklower #include "bpfilter.h"
4854718Ssklower 
495207Swnj #define	LOMTU	(1024+512)
505122Swnj 
515122Swnj struct	ifnet loif;
525122Swnj 
5359123Storek /* ARGSUSED */
5459123Storek void
loopattach(n)5559123Storek loopattach(n)
5659123Storek 	int n;
575122Swnj {
585122Swnj 	register struct ifnet *ifp = &loif;
595122Swnj 
6059123Storek #ifdef lint
6159123Storek 	n = n;			/* Highlander: there can only be one... */
6259123Storek #endif
635172Swnj 	ifp->if_name = "lo";
645122Swnj 	ifp->if_mtu = LOMTU;
6554718Ssklower 	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
6613066Ssam 	ifp->if_ioctl = loioctl;
675122Swnj 	ifp->if_output = looutput;
6837472Ssklower 	ifp->if_type = IFT_LOOP;
6937472Ssklower 	ifp->if_hdrlen = 0;
7037472Ssklower 	ifp->if_addrlen = 0;
715161Swnj 	if_attach(ifp);
7254718Ssklower #if NBPFILTER > 0
7354718Ssklower 	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
7454718Ssklower #endif
755122Swnj }
765122Swnj 
7761362Sbostic int
looutput(ifp,m,dst,rt)7845198Ssklower looutput(ifp, m, dst, rt)
795122Swnj 	struct ifnet *ifp;
8035795Skarels 	register struct mbuf *m;
816337Ssam 	struct sockaddr *dst;
8245198Ssklower 	register struct rtentry *rt;
835122Swnj {
8445523Ssklower 	int s, isr;
8545523Ssklower 	register struct ifqueue *ifq = 0;
865122Swnj 
8735795Skarels 	if ((m->m_flags & M_PKTHDR) == 0)
8835795Skarels 		panic("looutput no HDR");
8954718Ssklower 	ifp->if_lastchange = time;
9054718Ssklower #if NBPFILTER > 0
9154718Ssklower 	if (loif.if_bpf) {
9254718Ssklower 		/*
9354718Ssklower 		 * We need to prepend the address family as
9454718Ssklower 		 * a four byte field.  Cons up a dummy header
9554718Ssklower 		 * to pacify bpf.  This is safe because bpf
9654718Ssklower 		 * will only read from the mbuf (i.e., it won't
9754718Ssklower 		 * try to free it or keep a pointer a to it).
9854718Ssklower 		 */
9954718Ssklower 		struct mbuf m0;
10054718Ssklower 		u_int af = dst->sa_family;
10154718Ssklower 
10254718Ssklower 		m0.m_next = m;
10354718Ssklower 		m0.m_len = 4;
10454718Ssklower 		m0.m_data = (char *)&af;
10554718Ssklower 
10654718Ssklower 		bpf_mtap(loif.if_bpf, &m0);
10754718Ssklower 	}
10854718Ssklower #endif
10935795Skarels 	m->m_pkthdr.rcvif = ifp;
11035795Skarels 
11159009Ssklower 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
11245198Ssklower 		m_freem(m);
11359009Ssklower 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
11459009Ssklower 		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
11545198Ssklower 	}
1165172Swnj 	ifp->if_opackets++;
11739187Ssklower 	ifp->if_obytes += m->m_pkthdr.len;
1186337Ssam 	switch (dst->sa_family) {
1195122Swnj 
1205122Swnj #ifdef INET
1216337Ssam 	case AF_INET:
1226209Swnj 		ifq = &ipintrq;
12345523Ssklower 		isr = NETISR_IP;
1245122Swnj 		break;
1255122Swnj #endif
12618815Ssklower #ifdef NS
12718815Ssklower 	case AF_NS:
12818815Ssklower 		ifq = &nsintrq;
12945523Ssklower 		isr = NETISR_NS;
13018815Ssklower 		break;
13118815Ssklower #endif
13237472Ssklower #ifdef ISO
13337472Ssklower 	case AF_ISO:
13437472Ssklower 		ifq = &clnlintrq;
13545523Ssklower 		isr = NETISR_ISO;
13637472Ssklower 		break;
13737472Ssklower #endif
1385122Swnj 	default:
1396337Ssam 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
1406337Ssam 			dst->sa_family);
14135795Skarels 		m_freem(m);
1426544Sfeldman 		return (EAFNOSUPPORT);
1435122Swnj 	}
14448727Ssklower 	s = splimp();
14545523Ssklower 	if (IF_QFULL(ifq)) {
14645523Ssklower 		IF_DROP(ifq);
14745523Ssklower 		m_freem(m);
14845523Ssklower 		splx(s);
14945523Ssklower 		return (ENOBUFS);
15045523Ssklower 	}
15145523Ssklower 	IF_ENQUEUE(ifq, m);
15245523Ssklower 	schednetisr(isr);
1535172Swnj 	ifp->if_ipackets++;
15439187Ssklower 	ifp->if_ibytes += m->m_pkthdr.len;
1555122Swnj 	splx(s);
1566544Sfeldman 	return (0);
1575122Swnj }
15813066Ssam 
15948727Ssklower /* ARGSUSED */
16054718Ssklower void
lortrequest(cmd,rt,sa)16148727Ssklower lortrequest(cmd, rt, sa)
16252947Storek 	int cmd;
16352947Storek 	struct rtentry *rt;
16452947Storek 	struct sockaddr *sa;
16548727Ssklower {
16652947Storek 
16748727Ssklower 	if (rt)
16848727Ssklower 		rt->rt_rmx.rmx_mtu = LOMTU;
16948727Ssklower }
17048727Ssklower 
17113066Ssam /*
17213066Ssam  * Process an ioctl request.
17313066Ssam  */
17418370Skarels /* ARGSUSED */
17561362Sbostic int
loioctl(ifp,cmd,data)17613066Ssam loioctl(ifp, cmd, data)
17713066Ssam 	register struct ifnet *ifp;
178*68168Scgd 	u_long cmd;
17913066Ssam 	caddr_t data;
18013066Ssam {
18148727Ssklower 	register struct ifaddr *ifa;
18254718Ssklower 	register struct ifreq *ifr;
18354718Ssklower 	register int error = 0;
18413066Ssam 
18513066Ssam 	switch (cmd) {
18613066Ssam 
18713066Ssam 	case SIOCSIFADDR:
18818370Skarels 		ifp->if_flags |= IFF_UP;
18948727Ssklower 		ifa = (struct ifaddr *)data;
19048727Ssklower 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
19148727Ssklower 			ifa->ifa_rtrequest = lortrequest;
19218370Skarels 		/*
19318370Skarels 		 * Everything else is done at a higher level.
19418370Skarels 		 */
19513066Ssam 		break;
19613066Ssam 
19754718Ssklower 	case SIOCADDMULTI:
19854718Ssklower 	case SIOCDELMULTI:
19954718Ssklower 		ifr = (struct ifreq *)data;
20054718Ssklower 		if (ifr == 0) {
20154718Ssklower 			error = EAFNOSUPPORT;		/* XXX */
20254718Ssklower 			break;
20354718Ssklower 		}
20454718Ssklower 		switch (ifr->ifr_addr.sa_family) {
20554718Ssklower 
20654718Ssklower #ifdef INET
20754718Ssklower 		case AF_INET:
20854718Ssklower 			break;
20954718Ssklower #endif
21054718Ssklower 
21154718Ssklower 		default:
21254718Ssklower 			error = EAFNOSUPPORT;
21354718Ssklower 			break;
21454718Ssklower 		}
21554718Ssklower 		break;
21654718Ssklower 
21713066Ssam 	default:
21813066Ssam 		error = EINVAL;
21913066Ssam 	}
22013066Ssam 	return (error);
22113066Ssam }
222