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.17 (Berkeley) 07/06/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 "kernel.h" 17 #include "mbuf.h" 18 #include "socket.h" 19 #include "errno.h" 20 #include "ioctl.h" 21 #include "machine/cpu.h" 22 #include "time.h" 23 24 #include "if.h" 25 #include "if_types.h" 26 #include "netisr.h" 27 #include "route.h" 28 #include "bpf.h" 29 30 #ifdef INET 31 #include "netinet/in.h" 32 #include "netinet/in_systm.h" 33 #include "netinet/in_var.h" 34 #include "netinet/ip.h" 35 #endif 36 37 #ifdef NS 38 #include "netns/ns.h" 39 #include "netns/ns_if.h" 40 #endif 41 42 #ifdef ISO 43 #include "netiso/iso.h" 44 #include "netiso/iso_var.h" 45 #endif 46 47 #include "bpfilter.h" 48 49 #define LOMTU (1024+512) 50 51 struct ifnet loif; 52 int looutput(), loioctl(); 53 54 loattach() 55 { 56 register struct ifnet *ifp = &loif; 57 58 ifp->if_name = "lo"; 59 ifp->if_mtu = LOMTU; 60 #ifdef MULTICAST 61 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 62 #else 63 ifp->if_flags = IFF_LOOPBACK; 64 #endif 65 ifp->if_ioctl = loioctl; 66 ifp->if_output = looutput; 67 ifp->if_type = IFT_LOOP; 68 ifp->if_hdrlen = 0; 69 ifp->if_addrlen = 0; 70 if_attach(ifp); 71 #if NBPFILTER > 0 72 bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); 73 #endif 74 } 75 76 looutput(ifp, m, dst, rt) 77 struct ifnet *ifp; 78 register struct mbuf *m; 79 struct sockaddr *dst; 80 register struct rtentry *rt; 81 { 82 int s, isr; 83 register struct ifqueue *ifq = 0; 84 85 if ((m->m_flags & M_PKTHDR) == 0) 86 panic("looutput no HDR"); 87 ifp->if_lastchange = time; 88 #if NBPFILTER > 0 89 if (loif.if_bpf) { 90 /* 91 * We need to prepend the address family as 92 * a four byte field. Cons up a dummy header 93 * to pacify bpf. This is safe because bpf 94 * will only read from the mbuf (i.e., it won't 95 * try to free it or keep a pointer a to it). 96 */ 97 struct mbuf m0; 98 u_int af = dst->sa_family; 99 100 m0.m_next = m; 101 m0.m_len = 4; 102 m0.m_data = (char *)⁡ 103 104 bpf_mtap(loif.if_bpf, &m0); 105 } 106 #endif 107 m->m_pkthdr.rcvif = ifp; 108 109 if (rt && rt->rt_flags & RTF_REJECT) { 110 m_freem(m); 111 return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 112 } 113 ifp->if_opackets++; 114 ifp->if_obytes += m->m_pkthdr.len; 115 switch (dst->sa_family) { 116 117 #ifdef INET 118 case AF_INET: 119 ifq = &ipintrq; 120 isr = NETISR_IP; 121 break; 122 #endif 123 #ifdef NS 124 case AF_NS: 125 ifq = &nsintrq; 126 isr = NETISR_NS; 127 break; 128 #endif 129 #ifdef ISO 130 case AF_ISO: 131 ifq = &clnlintrq; 132 isr = NETISR_ISO; 133 break; 134 #endif 135 default: 136 printf("lo%d: can't handle af%d\n", ifp->if_unit, 137 dst->sa_family); 138 m_freem(m); 139 return (EAFNOSUPPORT); 140 } 141 s = splimp(); 142 if (IF_QFULL(ifq)) { 143 IF_DROP(ifq); 144 m_freem(m); 145 splx(s); 146 return (ENOBUFS); 147 } 148 IF_ENQUEUE(ifq, m); 149 schednetisr(isr); 150 ifp->if_ipackets++; 151 ifp->if_ibytes += m->m_pkthdr.len; 152 splx(s); 153 return (0); 154 } 155 156 /* ARGSUSED */ 157 void 158 lortrequest(cmd, rt, sa) 159 int cmd; 160 struct rtentry *rt; 161 struct sockaddr *sa; 162 { 163 164 if (rt) 165 rt->rt_rmx.rmx_mtu = LOMTU; 166 } 167 168 /* 169 * Process an ioctl request. 170 */ 171 /* ARGSUSED */ 172 loioctl(ifp, cmd, data) 173 register struct ifnet *ifp; 174 int cmd; 175 caddr_t data; 176 { 177 register struct ifaddr *ifa; 178 #ifdef MULTICAST 179 register struct ifreq *ifr; 180 #endif 181 register int error = 0; 182 183 switch (cmd) { 184 185 case SIOCSIFADDR: 186 ifp->if_flags |= IFF_UP; 187 ifa = (struct ifaddr *)data; 188 if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) 189 ifa->ifa_rtrequest = lortrequest; 190 /* 191 * Everything else is done at a higher level. 192 */ 193 break; 194 195 #ifdef MULTICAST 196 case SIOCADDMULTI: 197 case SIOCDELMULTI: 198 ifr = (struct ifreq *)data; 199 if (ifr == 0) { 200 error = EAFNOSUPPORT; /* XXX */ 201 break; 202 } 203 switch (ifr->ifr_addr.sa_family) { 204 205 #ifdef INET 206 case AF_INET: 207 break; 208 #endif 209 210 default: 211 error = EAFNOSUPPORT; 212 break; 213 } 214 break; 215 #endif 216 217 default: 218 error = EINVAL; 219 } 220 return (error); 221 } 222