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