1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)if_loop.c 7.11 (Berkeley) 09/04/90 8 */ 9 10 /* 11 * Loopback interface driver for protocol testing and timing. 12 */ 13 14 #include "param.h" 15 #include "systm.h" 16 #include "mbuf.h" 17 #include "socket.h" 18 #include "errno.h" 19 #include "ioctl.h" 20 21 #include "../net/if.h" 22 #include "../net/if_types.h" 23 #include "../net/netisr.h" 24 #include "../net/route.h" 25 26 #include "machine/mtpr.h" 27 28 #ifdef INET 29 #include "../netinet/in.h" 30 #include "../netinet/in_systm.h" 31 #include "../netinet/in_var.h" 32 #include "../netinet/ip.h" 33 #endif 34 35 #ifdef NS 36 #include "../netns/ns.h" 37 #include "../netns/ns_if.h" 38 #endif 39 40 #ifdef ISO 41 #include "../netiso/iso.h" 42 #include "../netiso/iso_var.h" 43 #endif 44 45 #define LOMTU (1024+512) 46 47 struct ifnet loif; 48 int looutput(), loioctl(); 49 50 loattach() 51 { 52 register struct ifnet *ifp = &loif; 53 54 ifp->if_name = "lo"; 55 ifp->if_mtu = LOMTU; 56 ifp->if_flags = IFF_LOOPBACK; 57 ifp->if_ioctl = loioctl; 58 ifp->if_output = looutput; 59 ifp->if_type = IFT_LOOP; 60 ifp->if_hdrlen = 0; 61 ifp->if_addrlen = 0; 62 if_attach(ifp); 63 } 64 65 looutput(ifp, m, dst, rt) 66 struct ifnet *ifp; 67 register struct mbuf *m; 68 struct sockaddr *dst; 69 register struct rtentry *rt; 70 { 71 int s; 72 register struct ifqueue *ifq; 73 74 if ((m->m_flags & M_PKTHDR) == 0) 75 panic("looutput no HDR"); 76 m->m_pkthdr.rcvif = ifp; 77 78 if (rt && rt->rt_flags & RTF_REJECT) { 79 m_freem(m); 80 return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 81 } 82 s = splimp(); 83 ifp->if_opackets++; 84 ifp->if_obytes += m->m_pkthdr.len; 85 switch (dst->sa_family) { 86 87 #ifdef INET 88 case AF_INET: 89 ifq = &ipintrq; 90 if (IF_QFULL(ifq)) { 91 IF_DROP(ifq); 92 m_freem(m); 93 splx(s); 94 return (ENOBUFS); 95 } 96 IF_ENQUEUE(ifq, m); 97 schednetisr(NETISR_IP); 98 break; 99 #endif 100 #ifdef NS 101 case AF_NS: 102 ifq = &nsintrq; 103 if (IF_QFULL(ifq)) { 104 IF_DROP(ifq); 105 m_freem(m); 106 splx(s); 107 return (ENOBUFS); 108 } 109 IF_ENQUEUE(ifq, m); 110 schednetisr(NETISR_NS); 111 break; 112 #endif 113 #ifdef ISO 114 case AF_ISO: 115 ifq = &clnlintrq; 116 if (IF_QFULL(ifq)) { 117 IF_DROP(ifq); 118 m_freem(m); 119 splx(s); 120 return (ENOBUFS); 121 } 122 IF_ENQUEUE(ifq, m); 123 schednetisr(NETISR_ISO); 124 break; 125 #endif 126 default: 127 splx(s); 128 printf("lo%d: can't handle af%d\n", ifp->if_unit, 129 dst->sa_family); 130 m_freem(m); 131 return (EAFNOSUPPORT); 132 } 133 ifp->if_ipackets++; 134 ifp->if_ibytes += m->m_pkthdr.len; 135 splx(s); 136 return (0); 137 } 138 139 /* 140 * Process an ioctl request. 141 */ 142 /* ARGSUSED */ 143 loioctl(ifp, cmd, data) 144 register struct ifnet *ifp; 145 int cmd; 146 caddr_t data; 147 { 148 int error = 0; 149 150 switch (cmd) { 151 152 case SIOCSIFADDR: 153 ifp->if_flags |= IFF_UP; 154 /* 155 * Everything else is done at a higher level. 156 */ 157 break; 158 159 default: 160 error = EINVAL; 161 } 162 return (error); 163 } 164