/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * %sccs.include.redist.c% * * @(#)if_loop.c 7.16 (Berkeley) 03/15/92 */ /* * 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 "machine/cpu.h" #include "if.h" #include "if_types.h" #include "netisr.h" #include "route.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 #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); } 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 default: printf("lo%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); m_freem(m); return (EAFNOSUPPORT); } s = splimp(); 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); } /* ARGSUSED */ lortrequest(cmd, rt, sa) int cmd; struct rtentry *rt; struct sockaddr *sa; { if (rt) rt->rt_rmx.rmx_mtu = LOMTU; } /* * Process an ioctl request. */ /* ARGSUSED */ loioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data; { register struct ifaddr *ifa; int error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; ifa = (struct ifaddr *)data; if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) ifa->ifa_rtrequest = lortrequest; /* * Everything else is done at a higher level. */ break; default: error = EINVAL; } return (error); }