123174Smckusick /* 229071Skarels * Copyright (c) 1982, 1986 Regents of the University of California. 333183Sbostic * All rights reserved. 423174Smckusick * 544464Sbostic * %sccs.include.redist.c% 633183Sbostic * 7*59009Ssklower * @(#)if_loop.c 7.20 (Berkeley) 04/08/93 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; 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 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 6113066Ssam ifp->if_ioctl = loioctl; 625122Swnj ifp->if_output = looutput; 6337472Ssklower ifp->if_type = IFT_LOOP; 6437472Ssklower ifp->if_hdrlen = 0; 6537472Ssklower ifp->if_addrlen = 0; 665161Swnj if_attach(ifp); 6754718Ssklower #if NBPFILTER > 0 6854718Ssklower bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); 6954718Ssklower #endif 705122Swnj } 715122Swnj 7245198Ssklower looutput(ifp, m, dst, rt) 735122Swnj struct ifnet *ifp; 7435795Skarels register struct mbuf *m; 756337Ssam struct sockaddr *dst; 7645198Ssklower register struct rtentry *rt; 775122Swnj { 7845523Ssklower int s, isr; 7945523Ssklower register struct ifqueue *ifq = 0; 805122Swnj 8135795Skarels if ((m->m_flags & M_PKTHDR) == 0) 8235795Skarels panic("looutput no HDR"); 8354718Ssklower ifp->if_lastchange = time; 8454718Ssklower #if NBPFILTER > 0 8554718Ssklower if (loif.if_bpf) { 8654718Ssklower /* 8754718Ssklower * We need to prepend the address family as 8854718Ssklower * a four byte field. Cons up a dummy header 8954718Ssklower * to pacify bpf. This is safe because bpf 9054718Ssklower * will only read from the mbuf (i.e., it won't 9154718Ssklower * try to free it or keep a pointer a to it). 9254718Ssklower */ 9354718Ssklower struct mbuf m0; 9454718Ssklower u_int af = dst->sa_family; 9554718Ssklower 9654718Ssklower m0.m_next = m; 9754718Ssklower m0.m_len = 4; 9854718Ssklower m0.m_data = (char *)⁡ 9954718Ssklower 10054718Ssklower bpf_mtap(loif.if_bpf, &m0); 10154718Ssklower } 10254718Ssklower #endif 10335795Skarels m->m_pkthdr.rcvif = ifp; 10435795Skarels 105*59009Ssklower if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 10645198Ssklower m_freem(m); 107*59009Ssklower return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 108*59009Ssklower rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 10945198Ssklower } 1105172Swnj ifp->if_opackets++; 11139187Ssklower ifp->if_obytes += m->m_pkthdr.len; 1126337Ssam switch (dst->sa_family) { 1135122Swnj 1145122Swnj #ifdef INET 1156337Ssam case AF_INET: 1166209Swnj ifq = &ipintrq; 11745523Ssklower isr = NETISR_IP; 1185122Swnj break; 1195122Swnj #endif 12018815Ssklower #ifdef NS 12118815Ssklower case AF_NS: 12218815Ssklower ifq = &nsintrq; 12345523Ssklower isr = NETISR_NS; 12418815Ssklower break; 12518815Ssklower #endif 12637472Ssklower #ifdef ISO 12737472Ssklower case AF_ISO: 12837472Ssklower ifq = &clnlintrq; 12945523Ssklower isr = NETISR_ISO; 13037472Ssklower break; 13137472Ssklower #endif 1325122Swnj default: 1336337Ssam printf("lo%d: can't handle af%d\n", ifp->if_unit, 1346337Ssam dst->sa_family); 13535795Skarels m_freem(m); 1366544Sfeldman return (EAFNOSUPPORT); 1375122Swnj } 13848727Ssklower s = splimp(); 13945523Ssklower if (IF_QFULL(ifq)) { 14045523Ssklower IF_DROP(ifq); 14145523Ssklower m_freem(m); 14245523Ssklower splx(s); 14345523Ssklower return (ENOBUFS); 14445523Ssklower } 14545523Ssklower IF_ENQUEUE(ifq, m); 14645523Ssklower schednetisr(isr); 1475172Swnj ifp->if_ipackets++; 14839187Ssklower ifp->if_ibytes += m->m_pkthdr.len; 1495122Swnj splx(s); 1506544Sfeldman return (0); 1515122Swnj } 15213066Ssam 15348727Ssklower /* ARGSUSED */ 15454718Ssklower void 15548727Ssklower lortrequest(cmd, rt, sa) 15652947Storek int cmd; 15752947Storek struct rtentry *rt; 15852947Storek struct sockaddr *sa; 15948727Ssklower { 16052947Storek 16148727Ssklower if (rt) 16248727Ssklower rt->rt_rmx.rmx_mtu = LOMTU; 16348727Ssklower } 16448727Ssklower 16513066Ssam /* 16613066Ssam * Process an ioctl request. 16713066Ssam */ 16818370Skarels /* ARGSUSED */ 16913066Ssam loioctl(ifp, cmd, data) 17013066Ssam register struct ifnet *ifp; 17113066Ssam int cmd; 17213066Ssam caddr_t data; 17313066Ssam { 17448727Ssklower register struct ifaddr *ifa; 17554718Ssklower register struct ifreq *ifr; 17654718Ssklower register int error = 0; 17713066Ssam 17813066Ssam switch (cmd) { 17913066Ssam 18013066Ssam case SIOCSIFADDR: 18118370Skarels ifp->if_flags |= IFF_UP; 18248727Ssklower ifa = (struct ifaddr *)data; 18348727Ssklower if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) 18448727Ssklower ifa->ifa_rtrequest = lortrequest; 18518370Skarels /* 18618370Skarels * Everything else is done at a higher level. 18718370Skarels */ 18813066Ssam break; 18913066Ssam 19054718Ssklower case SIOCADDMULTI: 19154718Ssklower case SIOCDELMULTI: 19254718Ssklower ifr = (struct ifreq *)data; 19354718Ssklower if (ifr == 0) { 19454718Ssklower error = EAFNOSUPPORT; /* XXX */ 19554718Ssklower break; 19654718Ssklower } 19754718Ssklower switch (ifr->ifr_addr.sa_family) { 19854718Ssklower 19954718Ssklower #ifdef INET 20054718Ssklower case AF_INET: 20154718Ssklower break; 20254718Ssklower #endif 20354718Ssklower 20454718Ssklower default: 20554718Ssklower error = EAFNOSUPPORT; 20654718Ssklower break; 20754718Ssklower } 20854718Ssklower break; 20954718Ssklower 21013066Ssam default: 21113066Ssam error = EINVAL; 21213066Ssam } 21313066Ssam return (error); 21413066Ssam } 215