/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * Redistribution is only permitted until one year after the first shipment * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and * binary forms are permitted provided that: (1) source distributions retain * this entire copyright notice and comment, and (2) distributions including * binaries display the following acknowledgement: This product includes * software developed by the University of California, Berkeley and its * contributors'' in the documentation or other materials provided with the * distribution and in all advertising materials mentioning features or use * of this software. Neither the name of the University nor the names of * its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#)if_loop.c 7.10 (Berkeley) 6/28/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 #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); } struct mbuf *Loop_Sanity; looutput(ifp, m, dst) struct ifnet *ifp; register struct mbuf *m; struct sockaddr *dst; { int s; register struct ifqueue *ifq; if ((m->m_flags & M_PKTHDR) == 0) panic("looutput no HDR"); m->m_pkthdr.rcvif = ifp; {struct mbuf *mm; int mlen = 0; for (mm = m; m; m = m->m_next) /* XXX debugging code -- sklower */ mlen += m->m_len; m = mm; if (mlen != m->m_pkthdr.len) { if (Loop_Sanity) m_freem(Loop_Sanity); Loop_Sanity = m_copy(m, 0, (int)M_COPYALL); } } s = splimp(); ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; switch (dst->sa_family) { #ifdef INET case AF_INET: ifq = &ipintrq; if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(ifq, m); schednetisr(NETISR_IP); break; #endif #ifdef NS case AF_NS: ifq = &nsintrq; if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(ifq, m); schednetisr(NETISR_NS); break; #endif #ifdef ISO case AF_ISO: ifq = &clnlintrq; if (IF_QFULL(ifq)) { IF_DROP(ifq); m_freem(m); splx(s); return (ENOBUFS); } IF_ENQUEUE(ifq, m); schednetisr(NETISR_ISO); 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); } 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) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; /* * Everything else is done at a higher level. */ break; default: error = EINVAL; } return (error); }