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.18 (Berkeley) 10/11/92 8 */ 9 10 /* 11 * Loopback interface driver for protocol testing and timing. 12 */ 13 14 #include <sys/param.h> 15 #include <sys/systm.h> 16 #include <sys/kernel.h> 17 #include <sys/mbuf.h> 18 #include <sys/socket.h> 19 #include <sys/errno.h> 20 #include <sys/ioctl.h> 21 #include <sys/time.h> 22 #include <machine/cpu.h> 23 24 #include <net/if.h> 25 #include <net/if_types.h> 26 #include <net/netisr.h> 27 #include <net/route.h> 28 #include <net/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