123174Smckusick /* 229071Skarels * Copyright (c) 1982, 1986 Regents of the University of California. 333183Sbostic * All rights reserved. 423174Smckusick * 544464Sbostic * %sccs.include.redist.c% 633183Sbostic * 7*59123Storek * @(#)if_loop.c 7.21 (Berkeley) 04/17/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 54*59123Storek /* ARGSUSED */ 55*59123Storek void 56*59123Storek loopattach(n) 57*59123Storek int n; 585122Swnj { 595122Swnj register struct ifnet *ifp = &loif; 605122Swnj 61*59123Storek #ifdef lint 62*59123Storek n = n; /* Highlander: there can only be one... */ 63*59123Storek #endif 645172Swnj ifp->if_name = "lo"; 655122Swnj ifp->if_mtu = LOMTU; 6654718Ssklower ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 6713066Ssam ifp->if_ioctl = loioctl; 685122Swnj ifp->if_output = looutput; 6937472Ssklower ifp->if_type = IFT_LOOP; 7037472Ssklower ifp->if_hdrlen = 0; 7137472Ssklower ifp->if_addrlen = 0; 725161Swnj if_attach(ifp); 7354718Ssklower #if NBPFILTER > 0 7454718Ssklower bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); 7554718Ssklower #endif 765122Swnj } 775122Swnj 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 *)⁡ 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 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 */ 17513066Ssam loioctl(ifp, cmd, data) 17613066Ssam register struct ifnet *ifp; 17713066Ssam int cmd; 17813066Ssam caddr_t data; 17913066Ssam { 18048727Ssklower register struct ifaddr *ifa; 18154718Ssklower register struct ifreq *ifr; 18254718Ssklower register int error = 0; 18313066Ssam 18413066Ssam switch (cmd) { 18513066Ssam 18613066Ssam case SIOCSIFADDR: 18718370Skarels ifp->if_flags |= IFF_UP; 18848727Ssklower ifa = (struct ifaddr *)data; 18948727Ssklower if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) 19048727Ssklower ifa->ifa_rtrequest = lortrequest; 19118370Skarels /* 19218370Skarels * Everything else is done at a higher level. 19318370Skarels */ 19413066Ssam break; 19513066Ssam 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 21613066Ssam default: 21713066Ssam error = EINVAL; 21813066Ssam } 21913066Ssam return (error); 22013066Ssam } 221