xref: /freebsd/sys/net/if_loop.c (revision 26f9a76710a312a951848542b9ca1f44100450e2)
1 /*
2  * Copyright (c) 1982, 1986, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)if_loop.c	8.1 (Berkeley) 6/10/93
34  */
35 
36 /*
37  * Loopback interface driver for protocol testing and timing.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/errno.h>
46 #include <sys/ioctl.h>
47 #include <sys/time.h>
48 #include <machine/cpu.h>
49 
50 #include <net/if.h>
51 #include <net/if_types.h>
52 #include <net/netisr.h>
53 #include <net/route.h>
54 #include <net/bpf.h>
55 
56 #ifdef	INET
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip.h>
61 #endif
62 
63 #ifdef NS
64 #include <netns/ns.h>
65 #include <netns/ns_if.h>
66 #endif
67 
68 #ifdef ISO
69 #include <netiso/iso.h>
70 #include <netiso/iso_var.h>
71 #endif
72 
73 #include "bpfilter.h"
74 
75 #define	LOMTU	(1024+512)
76 
77 struct	ifnet loif;
78 
79 /* ARGSUSED */
80 void
81 loopattach(void)
82 {
83 	register struct ifnet *ifp = &loif;
84 
85 	ifp->if_name = "lo";
86 	ifp->if_mtu = LOMTU;
87 	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
88 	ifp->if_ioctl = loioctl;
89 	ifp->if_output = looutput;
90 	ifp->if_type = IFT_LOOP;
91 	ifp->if_hdrlen = 0;
92 	ifp->if_addrlen = 0;
93 	if_attach(ifp);
94 #if NBPFILTER > 0
95 	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
96 #endif
97 }
98 
99 TEXT_SET(pseudo_set, loopattach);
100 
101 int
102 looutput(ifp, m, dst, rt)
103 	struct ifnet *ifp;
104 	register struct mbuf *m;
105 	struct sockaddr *dst;
106 	register struct rtentry *rt;
107 {
108 	int s, isr;
109 	register struct ifqueue *ifq = 0;
110 
111 	if ((m->m_flags & M_PKTHDR) == 0)
112 		panic("looutput no HDR");
113 	ifp->if_lastchange = time;
114 #if NBPFILTER > 0
115 	if (loif.if_bpf) {
116 		/*
117 		 * We need to prepend the address family as
118 		 * a four byte field.  Cons up a dummy header
119 		 * to pacify bpf.  This is safe because bpf
120 		 * will only read from the mbuf (i.e., it won't
121 		 * try to free it or keep a pointer a to it).
122 		 */
123 		struct mbuf m0;
124 		u_int af = dst->sa_family;
125 
126 		m0.m_next = m;
127 		m0.m_len = 4;
128 		m0.m_data = (char *)&af;
129 
130 		bpf_mtap(loif.if_bpf, &m0);
131 	}
132 #endif
133 	m->m_pkthdr.rcvif = ifp;
134 
135 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
136 		m_freem(m);
137 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
138 		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
139 	}
140 	ifp->if_opackets++;
141 	ifp->if_obytes += m->m_pkthdr.len;
142 	switch (dst->sa_family) {
143 
144 #ifdef INET
145 	case AF_INET:
146 		ifq = &ipintrq;
147 		isr = NETISR_IP;
148 		break;
149 #endif
150 #ifdef NS
151 	case AF_NS:
152 		ifq = &nsintrq;
153 		isr = NETISR_NS;
154 		break;
155 #endif
156 #ifdef ISO
157 	case AF_ISO:
158 		ifq = &clnlintrq;
159 		isr = NETISR_ISO;
160 		break;
161 #endif
162 	default:
163 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
164 			dst->sa_family);
165 		m_freem(m);
166 		return (EAFNOSUPPORT);
167 	}
168 	s = splimp();
169 	if (IF_QFULL(ifq)) {
170 		IF_DROP(ifq);
171 		m_freem(m);
172 		splx(s);
173 		return (ENOBUFS);
174 	}
175 	IF_ENQUEUE(ifq, m);
176 	schednetisr(isr);
177 	ifp->if_ipackets++;
178 	ifp->if_ibytes += m->m_pkthdr.len;
179 	splx(s);
180 	return (0);
181 }
182 
183 /* ARGSUSED */
184 void
185 lortrequest(cmd, rt, sa)
186 	int cmd;
187 	struct rtentry *rt;
188 	struct sockaddr *sa;
189 {
190 
191 	if (rt)
192 		rt->rt_rmx.rmx_mtu = LOMTU;
193 }
194 
195 /*
196  * Process an ioctl request.
197  */
198 /* ARGSUSED */
199 int
200 loioctl(ifp, cmd, data)
201 	register struct ifnet *ifp;
202 	int cmd;
203 	caddr_t data;
204 {
205 	register struct ifaddr *ifa;
206 	register struct ifreq *ifr;
207 	register int error = 0;
208 
209 	switch (cmd) {
210 
211 	case SIOCSIFADDR:
212 		ifp->if_flags |= IFF_UP;
213 		ifa = (struct ifaddr *)data;
214 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
215 			ifa->ifa_rtrequest = lortrequest;
216 		/*
217 		 * Everything else is done at a higher level.
218 		 */
219 		break;
220 
221 	case SIOCADDMULTI:
222 	case SIOCDELMULTI:
223 		ifr = (struct ifreq *)data;
224 		if (ifr == 0) {
225 			error = EAFNOSUPPORT;		/* XXX */
226 			break;
227 		}
228 		switch (ifr->ifr_addr.sa_family) {
229 
230 #ifdef INET
231 		case AF_INET:
232 			break;
233 #endif
234 
235 		default:
236 			error = EAFNOSUPPORT;
237 			break;
238 		}
239 		break;
240 
241 	default:
242 		error = EINVAL;
243 	}
244 	return (error);
245 }
246