1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)if_loop.c 6.10 (Berkeley) 06/04/86 7 */ 8 9 /* 10 * Loopback interface driver for protocol testing and timing. 11 */ 12 13 #include "param.h" 14 #include "systm.h" 15 #include "mbuf.h" 16 #include "socket.h" 17 #include "errno.h" 18 #include "ioctl.h" 19 20 #include "../net/if.h" 21 #include "../net/netisr.h" 22 #include "../net/route.h" 23 24 #ifdef INET 25 #include "../netinet/in.h" 26 #include "../netinet/in_systm.h" 27 #include "../netinet/in_var.h" 28 #include "../netinet/ip.h" 29 #endif 30 31 #ifdef vax 32 #include "../vax/mtpr.h" 33 #endif 34 35 #ifdef NS 36 #include "../netns/ns.h" 37 #include "../netns/ns_if.h" 38 #endif 39 40 #define LOMTU (1024+512) 41 42 struct ifnet loif; 43 int looutput(), loioctl(); 44 45 loattach() 46 { 47 register struct ifnet *ifp = &loif; 48 49 ifp->if_name = "lo"; 50 ifp->if_mtu = LOMTU; 51 ifp->if_flags = IFF_LOOPBACK; 52 ifp->if_ioctl = loioctl; 53 ifp->if_output = looutput; 54 if_attach(ifp); 55 } 56 57 looutput(ifp, m0, dst) 58 struct ifnet *ifp; 59 register struct mbuf *m0; 60 struct sockaddr *dst; 61 { 62 int s; 63 register struct ifqueue *ifq; 64 struct mbuf *m; 65 66 /* 67 * Place interface pointer before the data 68 * for the receiving protocol. 69 */ 70 if (m0->m_off <= MMAXOFF && 71 m0->m_off >= MMINOFF + sizeof(struct ifnet *)) { 72 m0->m_off -= sizeof(struct ifnet *); 73 m0->m_len += sizeof(struct ifnet *); 74 } else { 75 MGET(m, M_DONTWAIT, MT_HEADER); 76 if (m == (struct mbuf *)0) 77 return (ENOBUFS); 78 m->m_off = MMINOFF; 79 m->m_len = sizeof(struct ifnet *); 80 m->m_next = m0; 81 m0 = m; 82 } 83 *(mtod(m0, struct ifnet **)) = ifp; 84 s = splimp(); 85 ifp->if_opackets++; 86 switch (dst->sa_family) { 87 88 #ifdef INET 89 case AF_INET: 90 ifq = &ipintrq; 91 if (IF_QFULL(ifq)) { 92 IF_DROP(ifq); 93 m_freem(m0); 94 splx(s); 95 return (ENOBUFS); 96 } 97 IF_ENQUEUE(ifq, m0); 98 schednetisr(NETISR_IP); 99 break; 100 #endif 101 #ifdef NS 102 case AF_NS: 103 ifq = &nsintrq; 104 if (IF_QFULL(ifq)) { 105 IF_DROP(ifq); 106 m_freem(m0); 107 splx(s); 108 return (ENOBUFS); 109 } 110 IF_ENQUEUE(ifq, m0); 111 schednetisr(NETISR_NS); 112 break; 113 #endif 114 default: 115 splx(s); 116 printf("lo%d: can't handle af%d\n", ifp->if_unit, 117 dst->sa_family); 118 m_freem(m0); 119 return (EAFNOSUPPORT); 120 } 121 ifp->if_ipackets++; 122 splx(s); 123 return (0); 124 } 125 126 /* 127 * Process an ioctl request. 128 */ 129 /* ARGSUSED */ 130 loioctl(ifp, cmd, data) 131 register struct ifnet *ifp; 132 int cmd; 133 caddr_t data; 134 { 135 int error = 0; 136 137 switch (cmd) { 138 139 case SIOCSIFADDR: 140 ifp->if_flags |= IFF_UP; 141 /* 142 * Everything else is done at a higher level. 143 */ 144 break; 145 146 default: 147 error = EINVAL; 148 } 149 return (error); 150 } 151