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