1 /* 2 * Copyright (c) 1982 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.8 (Berkeley) 12/19/85 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/ip.h" 28 #include "../netinet/ip_var.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_ioctl = loioctl; 52 ifp->if_output = looutput; 53 if_attach(ifp); 54 } 55 56 looutput(ifp, m0, dst) 57 struct ifnet *ifp; 58 register struct mbuf *m0; 59 struct sockaddr *dst; 60 { 61 int s; 62 register struct ifqueue *ifq; 63 struct mbuf *m; 64 65 /* 66 * Place interface pointer before the data 67 * for the receiving protocol. 68 */ 69 if (m0->m_off <= MMAXOFF && 70 m0->m_off >= MMINOFF + sizeof(struct ifnet *)) { 71 m0->m_off -= sizeof(struct ifnet *); 72 m0->m_len += sizeof(struct ifnet *); 73 } else { 74 MGET(m, M_DONTWAIT, MT_HEADER); 75 if (m == (struct mbuf *)0) 76 return (ENOBUFS); 77 m->m_off = MMINOFF; 78 m->m_len = sizeof(struct ifnet *); 79 m->m_next = m0; 80 m0 = m; 81 } 82 *(mtod(m0, struct ifnet **)) = ifp; 83 s = splimp(); 84 ifp->if_opackets++; 85 switch (dst->sa_family) { 86 87 #ifdef INET 88 case AF_INET: 89 ifq = &ipintrq; 90 if (IF_QFULL(ifq)) { 91 IF_DROP(ifq); 92 m_freem(m0); 93 splx(s); 94 return (ENOBUFS); 95 } 96 IF_ENQUEUE(ifq, m0); 97 schednetisr(NETISR_IP); 98 break; 99 #endif 100 #ifdef NS 101 case AF_NS: 102 ifq = &nsintrq; 103 if (IF_QFULL(ifq)) { 104 IF_DROP(ifq); 105 m_freem(m0); 106 splx(s); 107 return (ENOBUFS); 108 } 109 IF_ENQUEUE(ifq, m0); 110 schednetisr(NETISR_NS); 111 break; 112 #endif 113 default: 114 splx(s); 115 printf("lo%d: can't handle af%d\n", ifp->if_unit, 116 dst->sa_family); 117 m_freem(m0); 118 return (EAFNOSUPPORT); 119 } 120 ifp->if_ipackets++; 121 splx(s); 122 return (0); 123 } 124 125 /* 126 * Process an ioctl request. 127 */ 128 /* ARGSUSED */ 129 loioctl(ifp, cmd, data) 130 register struct ifnet *ifp; 131 int cmd; 132 caddr_t data; 133 { 134 int error = 0; 135 136 switch (cmd) { 137 138 case SIOCSIFADDR: 139 ifp->if_flags |= IFF_UP; 140 /* 141 * Everything else is done at a higher level. 142 */ 143 break; 144 145 default: 146 error = EINVAL; 147 } 148 return (error); 149 } 150