if_loop.c revision 1.51 1 /* $NetBSD: if_loop.c,v 1.51 2004/08/19 20:58:24 christos Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * 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. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1982, 1986, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)if_loop.c 8.2 (Berkeley) 1/9/95
61 */
62
63 /*
64 * Loopback interface driver for protocol testing and timing.
65 */
66
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: if_loop.c,v 1.51 2004/08/19 20:58:24 christos Exp $");
69
70 #include "opt_inet.h"
71 #include "opt_atalk.h"
72 #include "opt_iso.h"
73 #include "opt_ns.h"
74 #include "opt_ipx.h"
75 #include "opt_mbuftrace.h"
76
77 #include "bpfilter.h"
78 #include "loop.h"
79
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/kernel.h>
83 #include <sys/mbuf.h>
84 #include <sys/socket.h>
85 #include <sys/errno.h>
86 #include <sys/ioctl.h>
87 #include <sys/time.h>
88
89 #include <machine/cpu.h>
90
91 #include <net/if.h>
92 #include <net/if_types.h>
93 #include <net/netisr.h>
94 #include <net/route.h>
95
96 #ifdef INET
97 #include <netinet/in.h>
98 #include <netinet/in_systm.h>
99 #include <netinet/in_var.h>
100 #include <netinet/ip.h>
101 #endif
102
103 #ifdef INET6
104 #ifndef INET
105 #include <netinet/in.h>
106 #endif
107 #include <netinet6/in6_var.h>
108 #include <netinet/ip6.h>
109 #endif
110
111 #ifdef NS
112 #include <netns/ns.h>
113 #include <netns/ns_if.h>
114 #endif
115
116 #ifdef IPX
117 #include <netipx/ipx.h>
118 #include <netipx/ipx_if.h>
119 #endif
120
121 #ifdef ISO
122 #include <netiso/iso.h>
123 #include <netiso/iso_var.h>
124 #endif
125
126 #ifdef NETATALK
127 #include <netatalk/at.h>
128 #include <netatalk/at_var.h>
129 #endif
130
131 #if NBPFILTER > 0
132 #include <net/bpf.h>
133 #endif
134
135 #if defined(LARGE_LOMTU)
136 #define LOMTU (131072 + MHLEN + MLEN)
137 #define LOMTU_MAX LOMTU
138 #else
139 #define LOMTU (32768 + MHLEN + MLEN)
140 #define LOMTU_MAX (65536 + MHLEN + MLEN)
141 #endif
142
143 struct ifnet loif[NLOOP];
144 #ifdef MBUFTRACE
145 struct mowner lomowner[NLOOP];
146 #endif
147
148 #ifdef ALTQ
149 void lostart(struct ifnet *);
150 #endif
151
152 void
153 loopattach(n)
154 int n;
155 {
156 int i;
157 struct ifnet *ifp;
158
159 for (i = 0; i < NLOOP; i++) {
160 ifp = &loif[i];
161 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "lo%d", i);
162 ifp->if_softc = NULL;
163 ifp->if_mtu = LOMTU;
164 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
165 ifp->if_ioctl = loioctl;
166 ifp->if_output = looutput;
167 #ifdef ALTQ
168 ifp->if_start = lostart;
169 #endif
170 ifp->if_type = IFT_LOOP;
171 ifp->if_hdrlen = 0;
172 ifp->if_addrlen = 0;
173 ifp->if_dlt = DLT_NULL;
174 IFQ_SET_READY(&ifp->if_snd);
175 if_attach(ifp);
176 if_alloc_sadl(ifp);
177 #if NBPFILTER > 0
178 bpfattach(ifp, DLT_NULL, sizeof(u_int));
179 #endif
180 #ifdef MBUFTRACE
181 ifp->if_mowner = &lomowner[i];
182 strlcpy(ifp->if_mowner->mo_name, ifp->if_xname,
183 sizeof(ifp->if_mowner->mo_name));
184 MOWNER_ATTACH(&lomowner[i]);
185 #endif
186 }
187 }
188
189 int
190 looutput(ifp, m, dst, rt)
191 struct ifnet *ifp;
192 struct mbuf *m;
193 struct sockaddr *dst;
194 struct rtentry *rt;
195 {
196 int s, isr;
197 struct ifqueue *ifq = 0;
198
199 MCLAIM(m, ifp->if_mowner);
200 if ((m->m_flags & M_PKTHDR) == 0)
201 panic("looutput: no header mbuf");
202 #if NBPFILTER > 0
203 if (ifp->if_bpf && (ifp->if_flags & IFF_LOOPBACK))
204 bpf_mtap_af(ifp->if_bpf, dst->sa_family, m);
205 #endif
206 m->m_pkthdr.rcvif = ifp;
207
208 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
209 m_freem(m);
210 return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
211 rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
212 }
213
214 ifp->if_opackets++;
215 ifp->if_obytes += m->m_pkthdr.len;
216
217 #ifdef ALTQ
218 /*
219 * ALTQ on the loopback interface is just for debugging. It's
220 * used only for loopback interfaces, not for a simplex interface.
221 */
222 if ((ALTQ_IS_ENABLED(&ifp->if_snd) || TBR_IS_ENABLED(&ifp->if_snd)) &&
223 ifp->if_start == lostart) {
224 struct altq_pktattr pktattr;
225 int error;
226
227 /*
228 * If the queueing discipline needs packet classification,
229 * do it before prepending the link headers.
230 */
231 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family, &pktattr);
232
233 M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
234 if (m == NULL)
235 return (ENOBUFS);
236 *(mtod(m, uint32_t *)) = dst->sa_family;
237
238 s = splnet();
239 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error);
240 (*ifp->if_start)(ifp);
241 splx(s);
242 return (error);
243 }
244 #endif /* ALTQ */
245
246 m_tag_delete_nonpersistent(m);
247
248 switch (dst->sa_family) {
249
250 #ifdef INET
251 case AF_INET:
252 ifq = &ipintrq;
253 isr = NETISR_IP;
254 break;
255 #endif
256 #ifdef INET6
257 case AF_INET6:
258 m->m_flags |= M_LOOP;
259 ifq = &ip6intrq;
260 isr = NETISR_IPV6;
261 break;
262 #endif
263 #ifdef NS
264 case AF_NS:
265 ifq = &nsintrq;
266 isr = NETISR_NS;
267 break;
268 #endif
269 #ifdef ISO
270 case AF_ISO:
271 ifq = &clnlintrq;
272 isr = NETISR_ISO;
273 break;
274 #endif
275 #ifdef IPX
276 case AF_IPX:
277 ifq = &ipxintrq;
278 isr = NETISR_IPX;
279 break;
280 #endif
281 #ifdef NETATALK
282 case AF_APPLETALK:
283 ifq = &atintrq2;
284 isr = NETISR_ATALK;
285 break;
286 #endif
287 default:
288 printf("%s: can't handle af%d\n", ifp->if_xname,
289 dst->sa_family);
290 m_freem(m);
291 return (EAFNOSUPPORT);
292 }
293 s = splnet();
294 if (IF_QFULL(ifq)) {
295 IF_DROP(ifq);
296 m_freem(m);
297 splx(s);
298 return (ENOBUFS);
299 }
300 IF_ENQUEUE(ifq, m);
301 schednetisr(isr);
302 ifp->if_ipackets++;
303 ifp->if_ibytes += m->m_pkthdr.len;
304 splx(s);
305 return (0);
306 }
307
308 #ifdef ALTQ
309 void
310 lostart(struct ifnet *ifp)
311 {
312 struct ifqueue *ifq;
313 struct mbuf *m;
314 uint32_t af;
315 int s, isr;
316
317 for (;;) {
318 IFQ_DEQUEUE(&ifp->if_snd, m);
319 if (m == NULL)
320 return;
321
322 af = *(mtod(m, uint32_t *));
323 m_adj(m, sizeof(uint32_t));
324
325 switch (af) {
326 #ifdef INET
327 case AF_INET:
328 ifq = &ipintrq;
329 isr = NETISR_IP;
330 break;
331 #endif
332 #ifdef INET6
333 case AF_INET6:
334 m->m_flags |= M_LOOP;
335 ifq = &ip6intrq;
336 isr = NETISR_IPV6;
337 break;
338 #endif
339 #ifdef IPX
340 case AF_IPX:
341 ifq = &ipxintrq;
342 isr = NETISR_IPX;
343 break;
344 #endif
345 #ifdef NS
346 case AF_NS:
347 ifq = &nsintrq;
348 isr = NETISR_NS;
349 break;
350 #endif
351 #ifdef ISO
352 case AF_ISO:
353 ifq = &clnlintrq;
354 isr = NETISR_ISO;
355 break;
356 #endif
357 #ifdef NETATALK
358 case AF_APPLETALK:
359 ifq = &atintrq2;
360 isr = NETISR_ATALK;
361 break;
362 #endif
363 default:
364 printf("%s: can't handle af%d\n", ifp->if_xname, af);
365 m_freem(m);
366 return;
367 }
368
369 s = splnet();
370 if (IF_QFULL(ifq)) {
371 IF_DROP(ifq);
372 splx(s);
373 m_freem(m);
374 return;
375 }
376 IF_ENQUEUE(ifq, m);
377 schednetisr(isr);
378 ifp->if_ipackets++;
379 ifp->if_ibytes += m->m_pkthdr.len;
380 splx(s);
381 }
382 }
383 #endif /* ALTQ */
384
385 /* ARGSUSED */
386 void
387 lortrequest(cmd, rt, info)
388 int cmd;
389 struct rtentry *rt;
390 struct rt_addrinfo *info;
391 {
392
393 struct ifnet *ifp = &loif[0];
394 if (rt)
395 rt->rt_rmx.rmx_mtu = ifp->if_mtu;
396
397 }
398
399 /*
400 * Process an ioctl request.
401 */
402 /* ARGSUSED */
403 int
404 loioctl(ifp, cmd, data)
405 struct ifnet *ifp;
406 u_long cmd;
407 caddr_t data;
408 {
409 struct ifaddr *ifa;
410 struct ifreq *ifr;
411 int error = 0;
412
413 switch (cmd) {
414
415 case SIOCSIFADDR:
416 ifp->if_flags |= IFF_UP;
417 ifa = (struct ifaddr *)data;
418 if (ifa != 0 /*&& ifa->ifa_addr->sa_family == AF_ISO*/)
419 ifa->ifa_rtrequest = lortrequest;
420 /*
421 * Everything else is done at a higher level.
422 */
423 break;
424
425 case SIOCSIFMTU:
426 ifr = (struct ifreq *)data;
427 if ((unsigned)ifr->ifr_mtu > LOMTU_MAX)
428 error = EINVAL;
429 else {
430 /* XXX update rt mtu for AF_ISO? */
431 ifp->if_mtu = ifr->ifr_mtu;
432 }
433 break;
434
435 case SIOCADDMULTI:
436 case SIOCDELMULTI:
437 ifr = (struct ifreq *)data;
438 if (ifr == 0) {
439 error = EAFNOSUPPORT; /* XXX */
440 break;
441 }
442 switch (ifr->ifr_addr.sa_family) {
443
444 #ifdef INET
445 case AF_INET:
446 break;
447 #endif
448 #ifdef INET6
449 case AF_INET6:
450 break;
451 #endif
452
453 default:
454 error = EAFNOSUPPORT;
455 break;
456 }
457 break;
458
459 default:
460 error = EINVAL;
461 }
462 return (error);
463 }
464