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