/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * %sccs.include.redist.c% * * @(#)if_loop.c 7.12 (Berkeley) 11/06/90 */ /* * Loopback interface driver for protocol testing and timing. */ #include "param.h" #include "systm.h" #include "mbuf.h" #include "socket.h" #include "errno.h" #include "ioctl.h" #include "../net/if.h" #include "../net/if_types.h" #include "../net/netisr.h" #include "../net/route.h" #include "machine/mtpr.h" #ifdef INET #include "../netinet/in.h" #include "../netinet/in_systm.h" #include "../netinet/in_var.h" #include "../netinet/ip.h" #endif #ifdef NS #include "../netns/ns.h" #include "../netns/ns_if.h" #endif #ifdef ISO #include "../netiso/iso.h" #include "../netiso/iso_var.h" #endif #ifdef CCITT #include "../netccitt/x25.h" #include "../netccitt/hdlc.h" #include "../netccitt/hd_var.h" #endif #define LOMTU (1024+512) struct ifnet loif; int looutput(), loioctl(); loattach() { register struct ifnet *ifp = &loif; ifp->if_name = "lo"; ifp->if_mtu = LOMTU; ifp->if_flags = IFF_LOOPBACK; ifp->if_ioctl = loioctl; ifp->if_output = looutput; ifp->if_type = IFT_LOOP; ifp->if_hdrlen = 0; ifp->if_addrlen = 0; if_attach(ifp); } looutput(ifp, m, dst, rt) struct ifnet *ifp; register struct mbuf *m; struct sockaddr *dst; register struct rtentry *rt; { int s, isr; register struct ifqueue *ifq = 0; if ((m->m_flags & M_PKTHDR) == 0) panic("looutput no HDR"); m->m_pkthdr.rcvif = ifp; if (rt && rt->rt_flags & RTF_REJECT) { m_freem(m); return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); } s = splimp(); ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; switch (dst->sa_family) { #ifdef INET case AF_INET: ifq = &ipintrq; isr = NETISR_IP; break; #endif #ifdef NS case AF_NS: ifq = &nsintrq; isr = NETISR_NS; break; #endif #ifdef ISO case AF_ISO: ifq = &clnlintrq; isr = NETISR_ISO; break; #endif #ifdef CCITT case AF_CCITT: ifq = &hdintrq; isr = NETISR_CCITT; break; #endif default: splx(s); printf("lo%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); m_freem(m); return (EAFNOSUPPORT); } if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(ifq, m); schednetisr(isr); ifp->if_ipackets++; ifp->if_ibytes += m->m_pkthdr.len; splx(s); return (0); } /* * Process an ioctl request. */ /* ARGSUSED */ loioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data; { int error = 0; switch (cmd) { #ifdef CCITT case SIOCSIFCONF_X25: #endif case SIOCSIFADDR: ifp->if_flags |= IFF_UP; /* * Everything else is done at a higher level. */ break; default: error = EINVAL; } return (error); }