/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#)if_loop.c 7.9 (Berkeley) 09/20/89 */ /* * 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); }