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 *)⁡ 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