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.16 (Berkeley) 03/15/92 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 #include "machine/cpu.h" 21 22 #include "if.h" 23 #include "if_types.h" 24 #include "netisr.h" 25 #include "route.h" 26 27 #ifdef INET 28 #include "netinet/in.h" 29 #include "netinet/in_systm.h" 30 #include "netinet/in_var.h" 31 #include "netinet/ip.h" 32 #endif 33 34 #ifdef NS 35 #include "netns/ns.h" 36 #include "netns/ns_if.h" 37 #endif 38 39 #ifdef ISO 40 #include "netiso/iso.h" 41 #include "netiso/iso_var.h" 42 #endif 43 44 #define LOMTU (1024+512) 45 46 struct ifnet loif; 47 int looutput(), loioctl(); 48 49 loattach() 50 { 51 register struct ifnet *ifp = &loif; 52 53 ifp->if_name = "lo"; 54 ifp->if_mtu = LOMTU; 55 ifp->if_flags = IFF_LOOPBACK; 56 ifp->if_ioctl = loioctl; 57 ifp->if_output = looutput; 58 ifp->if_type = IFT_LOOP; 59 ifp->if_hdrlen = 0; 60 ifp->if_addrlen = 0; 61 if_attach(ifp); 62 } 63 64 looutput(ifp, m, dst, rt) 65 struct ifnet *ifp; 66 register struct mbuf *m; 67 struct sockaddr *dst; 68 register struct rtentry *rt; 69 { 70 int s, isr; 71 register struct ifqueue *ifq = 0; 72 73 if ((m->m_flags & M_PKTHDR) == 0) 74 panic("looutput no HDR"); 75 m->m_pkthdr.rcvif = ifp; 76 77 if (rt && rt->rt_flags & RTF_REJECT) { 78 m_freem(m); 79 return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 80 } 81 ifp->if_opackets++; 82 ifp->if_obytes += m->m_pkthdr.len; 83 switch (dst->sa_family) { 84 85 #ifdef INET 86 case AF_INET: 87 ifq = &ipintrq; 88 isr = NETISR_IP; 89 break; 90 #endif 91 #ifdef NS 92 case AF_NS: 93 ifq = &nsintrq; 94 isr = NETISR_NS; 95 break; 96 #endif 97 #ifdef ISO 98 case AF_ISO: 99 ifq = &clnlintrq; 100 isr = NETISR_ISO; 101 break; 102 #endif 103 default: 104 printf("lo%d: can't handle af%d\n", ifp->if_unit, 105 dst->sa_family); 106 m_freem(m); 107 return (EAFNOSUPPORT); 108 } 109 s = splimp(); 110 if (IF_QFULL(ifq)) { 111 IF_DROP(ifq); 112 m_freem(m); 113 splx(s); 114 return (ENOBUFS); 115 } 116 IF_ENQUEUE(ifq, m); 117 schednetisr(isr); 118 ifp->if_ipackets++; 119 ifp->if_ibytes += m->m_pkthdr.len; 120 splx(s); 121 return (0); 122 } 123 124 /* ARGSUSED */ 125 lortrequest(cmd, rt, sa) 126 int cmd; 127 struct rtentry *rt; 128 struct sockaddr *sa; 129 { 130 131 if (rt) 132 rt->rt_rmx.rmx_mtu = LOMTU; 133 } 134 135 /* 136 * Process an ioctl request. 137 */ 138 /* ARGSUSED */ 139 loioctl(ifp, cmd, data) 140 register struct ifnet *ifp; 141 int cmd; 142 caddr_t data; 143 { 144 register struct ifaddr *ifa; 145 int error = 0; 146 147 switch (cmd) { 148 149 case SIOCSIFADDR: 150 ifp->if_flags |= IFF_UP; 151 ifa = (struct ifaddr *)data; 152 if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) 153 ifa->ifa_rtrequest = lortrequest; 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