]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_loop.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / net / if_loop.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b
A
29 */
30/*
31 * Copyright (c) 1982, 1986, 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * @(#)if_loop.c 8.1 (Berkeley) 6/10/93
9bccf70c 63 * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.5 2001/07/03 11:01:41 ume Exp $
1c79356b
A
64 */
65
66/*
67 * Loopback interface driver for protocol testing and timing.
68 */
69#include "loop.h"
70#if NLOOP > 0
71
72#include <sys/param.h>
73#include <sys/systm.h>
74#include <sys/kernel.h>
75#include <sys/mbuf.h>
76#include <sys/socket.h>
77#include <sys/sockio.h>
78
79#include <net/if.h>
80#include <net/if_types.h>
1c79356b
A
81#include <net/route.h>
82#include <net/bpf.h>
83#include <sys/malloc.h>
84
85#if INET
86#include <netinet/in.h>
87#include <netinet/in_var.h>
88#endif
89
90#if IPX
91#include <netipx/ipx.h>
92#include <netipx/ipx_if.h>
93#endif
94
95#if INET6
96#ifndef INET
97#include <netinet/in.h>
98#endif
99#include <netinet6/in6_var.h>
100#include <netinet/ip6.h>
101#endif
102
1c79356b 103#include <net/dlil.h>
91447636 104#include <net/kpi_protocol.h>
1c79356b
A
105
106#if NETAT
107extern struct ifqueue atalkintrq;
108#endif
109
110#include "bpfilter.h"
111#if NBPFILTER > 0
112#include <net/bpfdesc.h>
113#endif
114
115#define NLOOP_ATTACHMENTS (NLOOP * 12)
116
117struct lo_statics_str {
91447636
A
118 int bpf_mode;
119 bpf_packet_func bpf_callback;
1c79356b
A
120};
121
91447636 122void loopattach(void *dummy);
1c79356b 123
91447636
A
124static struct lo_statics_str lo_statics[NLOOP];
125int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
1c79356b
A
126
127#ifdef TINY_LOMTU
128#define LOMTU (1024+512)
129#else
130#define LOMTU 16384
131#endif
132
133struct ifnet loif[NLOOP];
91447636 134struct ifnet *lo_ifp = &loif[0];
1c79356b 135
91447636
A
136struct loopback_header {
137 u_long protocol;
138};
1c79356b 139
91447636 140void lo_reg_if_mods(void);
1c79356b 141
91447636 142/* Local forward declerations */
1c79356b 143
91447636
A
144static errno_t
145lo_demux(
146 __unused ifnet_t ifp,
147 __unused mbuf_t m,
148 char *frame_header,
149 protocol_family_t *protocol_family)
1c79356b 150{
91447636
A
151 struct loopback_header *header = (struct loopback_header *)frame_header;
152
153 *protocol_family = header->protocol;
154
155 return 0;
1c79356b
A
156}
157
158
91447636
A
159static errno_t
160lo_framer(
161 __unused ifnet_t ifp,
162 mbuf_t *m,
163 __unused const struct sockaddr *dest,
164 __unused const char *dest_linkaddr,
165 const char *frame_type)
1c79356b 166{
91447636 167 struct loopback_header *header;
1c79356b 168
91447636
A
169 M_PREPEND(*m, sizeof(struct loopback_header), M_WAITOK);
170 header = mtod(*m, struct loopback_header*);
171 header->protocol = *(const u_long*)frame_type;
1c79356b
A
172 return 0;
173}
174
91447636
A
175static errno_t
176lo_add_proto(
177 __unused struct ifnet *ifp,
178 __unused u_long protocol_family,
179 __unused struct ddesc_head_str *demux_desc_head)
1c79356b
A
180{
181 return 0;
182}
183
184
91447636
A
185static errno_t
186lo_del_proto(
187 __unused ifnet_t ifp,
188 __unused protocol_family_t protocol)
1c79356b 189{
91447636 190 return 0;
1c79356b
A
191}
192
193static int
91447636
A
194lo_output(
195 struct ifnet *ifp,
196 struct mbuf *m)
197{
1c79356b
A
198
199 if ((m->m_flags & M_PKTHDR) == 0)
200 panic("lo_output: no HDR");
201
202 /*
203 * Don't overwrite the rcvif field if it is in use.
204 * This is used to match multicast packets, sent looping
205 * back, with the appropriate group record on input.
206 */
207 if (m->m_pkthdr.rcvif == NULL)
208 m->m_pkthdr.rcvif = ifp;
1c79356b 209
91447636
A
210 ifp->if_ibytes += m->m_pkthdr.len;
211 ifp->if_obytes += m->m_pkthdr.len;
212
213 ifp->if_opackets++;
214 ifp->if_ipackets++;
215
216 m->m_pkthdr.header = mtod(m, char *);
217 m->m_pkthdr.csum_data = 0xffff; /* loopback checksums are always OK */
218 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
219 CSUM_IP_CHECKED | CSUM_IP_VALID;
220 m_adj(m, sizeof(struct loopback_header));
1c79356b
A
221
222#if NBPFILTER > 0
223 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
224 struct mbuf m0, *n;
225
1c79356b
A
226 n = m;
227 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
91447636 228 struct loopback_header *header;
1c79356b
A
229 /*
230 * We need to prepend the address family as
231 * a four byte field. Cons up a dummy header
232 * to pacify bpf. This is safe because bpf
233 * will only read from the mbuf (i.e., it won't
234 * try to free it or keep a pointer a to it).
235 */
91447636 236 header = (struct loopback_header*)m->m_pkthdr.header;
1c79356b
A
237 m0.m_next = m;
238 m0.m_len = 4;
91447636 239 m0.m_data = (char *)&header->protocol;
1c79356b
A
240 n = &m0;
241 }
242
91447636 243 lo_statics[ifp->if_unit].bpf_callback(ifp, n);
1c79356b
A
244 }
245#endif
246
1c79356b
A
247 return dlil_input(ifp, m, m);
248}
249
250
251/*
91447636 252 * This is a common pre-output route used by INET and INET6. This could
1c79356b
A
253 * (should?) be split into separate pre-output routines for each protocol.
254 */
255
256static int
91447636
A
257lo_pre_output(
258 __unused struct ifnet *ifp,
259 u_long protocol_family,
260 struct mbuf **m,
261 __unused const struct sockaddr *dst,
262 caddr_t route,
263 char *frame_type,
264 __unused char *dst_addr)
1c79356b
A
265
266{
1c79356b
A
267 register struct rtentry *rt = (struct rtentry *) route;
268
1c79356b
A
269 if (((*m)->m_flags & M_PKTHDR) == 0)
270 panic("looutput no HDR");
271
272 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
91447636
A
273 if (rt->rt_flags & RTF_BLACKHOLE) {
274 m_freem(*m);
275 return EJUSTRETURN;
276 }
277 else
278 return ((rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH);
1c79356b 279 }
91447636
A
280
281 *(u_long *)frame_type = protocol_family;
1c79356b
A
282
283 return 0;
284}
285
1c79356b
A
286/*
287 * lo_input - This should work for all attached protocols that use the
288 * ifq/schednetisr input mechanism.
289 */
91447636
A
290static int
291lo_input(
292 struct mbuf *m,
293 __unused char *fh,
294 __unused struct ifnet *ifp,
295 __unused u_long protocol_family,
296 __unused int sync_ok)
1c79356b 297{
91447636 298 if (proto_input(protocol_family, m) != 0)
1c79356b 299 m_freem(m);
1c79356b
A
300 return (0);
301}
302
303
304
305
306/* ARGSUSED */
307static void
91447636
A
308lortrequest(
309 __unused int cmd,
310 struct rtentry *rt,
311 __unused struct sockaddr *sa)
1c79356b
A
312{
313 if (rt) {
314 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
315 /*
316 * For optimal performance, the send and receive buffers
317 * should be at least twice the MTU plus a little more for
318 * overhead.
319 */
320 rt->rt_rmx.rmx_recvpipe =
321 rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
322 }
323}
324
325/*
326 * Process an ioctl request.
327 */
91447636
A
328static errno_t
329loioctl(
330 ifnet_t ifp,
331 u_int32_t cmd,
332 void* data)
1c79356b
A
333{
334 register struct ifaddr *ifa;
335 register struct ifreq *ifr = (struct ifreq *)data;
336 register int error = 0;
337
338 switch (cmd) {
339
340 case SIOCSIFADDR:
91447636 341 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
1c79356b
A
342 ifa = (struct ifaddr *)data;
343 ifa->ifa_rtrequest = lortrequest;
344 /*
345 * Everything else is done at a higher level.
346 */
347 break;
348
349 case SIOCADDMULTI:
350 case SIOCDELMULTI:
351 if (ifr == 0) {
352 error = EAFNOSUPPORT; /* XXX */
353 break;
354 }
355 switch (ifr->ifr_addr.sa_family) {
356
357#if INET
358 case AF_INET:
359 break;
360#endif
361#if INET6
362 case AF_INET6:
363 break;
364#endif
365
366 default:
367 error = EAFNOSUPPORT;
368 break;
369 }
370 break;
371
372 case SIOCSIFMTU:
373 ifp->if_mtu = ifr->ifr_mtu;
374 break;
375
376 case SIOCSIFFLAGS:
377 break;
378
379 default:
380 error = EOPNOTSUPP;
4a249263 381 break;
1c79356b
A
382 }
383 return (error);
384}
385#endif /* NLOOP > 0 */
386
387
91447636 388static int lo_attach_proto(struct ifnet *ifp, u_long protocol_family)
1c79356b 389{
91447636
A
390 struct dlil_proto_reg_str reg;
391 int stat =0 ;
392
393 bzero(&reg, sizeof(reg));
394 TAILQ_INIT(&reg.demux_desc_head);
395 reg.interface_family = ifp->if_family;
396 reg.unit_number = ifp->if_unit;
397 reg.input = lo_input;
398 reg.pre_output = lo_pre_output;
399 reg.protocol_family = protocol_family;
400
401 stat = dlil_attach_protocol(&reg);
1c79356b 402
91447636
A
403 if (stat && stat != EEXIST) {
404 printf("lo_attach_proto: dlil_attach_protocol for %d returned=%d\n",
405 protocol_family, stat);
9bccf70c 406 }
91447636
A
407
408 return stat;
9bccf70c
A
409}
410
55e303ae
A
411void lo_reg_if_mods()
412{
55e303ae
A
413 int error;
414
55e303ae 415 /* Register protocol registration functions */
91447636 416 if ((error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
55e303ae
A
417 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
418
91447636 419 if ((error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
55e303ae 420 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
55e303ae 421}
1c79356b 422
91447636
A
423static errno_t
424lo_set_bpf_tap(
425 ifnet_t ifp,
426 bpf_tap_mode mode,
427 bpf_packet_func bpf_callback)
1c79356b
A
428{
429
430 /*
431 * NEED MUTEX HERE XXX
432 */
433 if (mode == BPF_TAP_DISABLE) {
434 lo_statics[ifp->if_unit].bpf_mode = mode;
435 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
436 }
437 else {
438 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
439 lo_statics[ifp->if_unit].bpf_mode = mode;
440 }
441
442 return 0;
443}
444
445
446/* ARGSUSED */
447void
91447636
A
448loopattach(
449 __unused void *dummy)
1c79356b 450{
91447636
A
451 struct ifnet *ifp;
452 int i = 0;
1c79356b 453
1c79356b
A
454 lo_reg_if_mods();
455
456 for (ifp = loif; i < NLOOP; ifp++) {
457 lo_statics[i].bpf_callback = 0;
458 lo_statics[i].bpf_mode = BPF_TAP_DISABLE;
91447636 459 bzero(ifp, sizeof(struct ifnet));
1c79356b
A
460 ifp->if_name = "lo";
461 ifp->if_family = APPLE_IF_FAM_LOOPBACK;
462 ifp->if_unit = i++;
463 ifp->if_mtu = LOMTU;
464 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
91447636
A
465 ifp->if_ioctl = loioctl;
466 ifp->if_demux = lo_demux;
467 ifp->if_framer = lo_framer;
468 ifp->if_add_proto = lo_add_proto;
469 ifp->if_del_proto = lo_del_proto;
1c79356b
A
470 ifp->if_set_bpf_tap = lo_set_bpf_tap;
471 ifp->if_output = lo_output;
472 ifp->if_type = IFT_LOOP;
91447636
A
473 ifp->if_hwassist = IF_HWASSIST_CSUM_IP | IF_HWASSIST_CSUM_TCP | IF_HWASSIST_CSUM_UDP;
474 ifp->if_hdrlen = sizeof(struct loopback_header);
475 lo_ifp = ifp;
1c79356b
A
476 dlil_if_attach(ifp);
477#if NBPFILTER > 0
478 bpfattach(ifp, DLT_NULL, sizeof(u_int));
479#endif
480 }
91447636 481 loopattach_done = 1;
1c79356b 482}