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