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