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