]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_loop.c
xnu-1699.22.81.tar.gz
[apple/xnu.git] / bsd / net / if_loop.c
CommitLineData
1c79356b 1/*
6d2010ae 2 * Copyright (c) 2000-2010 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>
6d2010ae 82#include <sys/mcache.h>
1c79356b
A
83
84#include <net/if.h>
85#include <net/if_types.h>
1c79356b
A
86#include <net/route.h>
87#include <net/bpf.h>
88#include <sys/malloc.h>
89
90#if INET
91#include <netinet/in.h>
92#include <netinet/in_var.h>
93#endif
94
1c79356b 95#if INET6
2d21ac55 96#if !INET
1c79356b
A
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
2d21ac55
A
110#if CONFIG_MACF_NET
111#include <security/mac_framework.h>
112#endif
113
1c79356b
A
114#define NLOOP_ATTACHMENTS (NLOOP * 12)
115
116struct lo_statics_str {
91447636
A
117 int bpf_mode;
118 bpf_packet_func bpf_callback;
1c79356b
A
119};
120
2d21ac55 121void loopattach(void);
1c79356b 122
91447636
A
123static struct lo_statics_str lo_statics[NLOOP];
124int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
1c79356b
A
125
126#ifdef TINY_LOMTU
127#define LOMTU (1024+512)
128#else
129#define LOMTU 16384
130#endif
131
2d21ac55 132ifnet_t lo_ifp = NULL;
1c79356b 133
91447636 134struct loopback_header {
2d21ac55 135 protocol_family_t protocol;
91447636 136};
1c79356b 137
2d21ac55 138static void lo_reg_if_mods(void);
1c79356b 139
91447636 140/* Local forward declerations */
1c79356b 141
91447636
A
142static errno_t
143lo_demux(
144 __unused ifnet_t ifp,
145 __unused mbuf_t m,
146 char *frame_header,
147 protocol_family_t *protocol_family)
1c79356b 148{
91447636
A
149 struct loopback_header *header = (struct loopback_header *)frame_header;
150
151 *protocol_family = header->protocol;
152
153 return 0;
1c79356b
A
154}
155
156
91447636
A
157static errno_t
158lo_framer(
159 __unused ifnet_t ifp,
160 mbuf_t *m,
161 __unused const struct sockaddr *dest,
162 __unused const char *dest_linkaddr,
163 const char *frame_type)
1c79356b 164{
91447636 165 struct loopback_header *header;
1c79356b 166
91447636 167 M_PREPEND(*m, sizeof(struct loopback_header), M_WAITOK);
b0d623f7
A
168 if (*m == NULL)
169 return EJUSTRETURN; /* Tell caller not to try to free passed-in mbuf */
91447636 170 header = mtod(*m, struct loopback_header*);
b0d623f7 171 header->protocol = *(const u_int32_t*)frame_type;
1c79356b
A
172 return 0;
173}
174
91447636
A
175static errno_t
176lo_add_proto(
2d21ac55
A
177 __unused ifnet_t interface,
178 __unused protocol_family_t protocol_family,
179 __unused const struct ifnet_demux_desc *demux_array,
180 __unused u_int32_t demux_count)
1c79356b
A
181{
182 return 0;
183}
184
185
91447636
A
186static errno_t
187lo_del_proto(
188 __unused ifnet_t ifp,
189 __unused protocol_family_t protocol)
1c79356b 190{
91447636 191 return 0;
1c79356b
A
192}
193
194static int
91447636 195lo_output(
2d21ac55
A
196 ifnet_t ifp,
197 mbuf_t m_list)
91447636 198{
2d21ac55
A
199 mbuf_t m;
200
201 for (m = m_list; m; m = m->m_nextpkt) {
202 if ((m->m_flags & M_PKTHDR) == 0)
203 panic("lo_output: no HDR");
1c79356b 204
2d21ac55
A
205 /*
206 * Don't overwrite the rcvif field if it is in use.
207 * This is used to match multicast packets, sent looping
208 * back, with the appropriate group record on input.
209 */
210 if (m->m_pkthdr.rcvif == NULL)
211 m->m_pkthdr.rcvif = ifp;
91447636 212
6d2010ae
A
213 atomic_add_64(&ifp->if_ibytes, m->m_pkthdr.len);
214 atomic_add_64(&ifp->if_obytes, m->m_pkthdr.len);
91447636 215
6d2010ae
A
216 atomic_add_64(&ifp->if_opackets, 1);
217 atomic_add_64(&ifp->if_ipackets, 1);
1c79356b 218
2d21ac55
A
219 m->m_pkthdr.header = mtod(m, char *);
220 if (apple_hwcksum_tx != 0) {
221 /* loopback checksums are always OK */
222 m->m_pkthdr.csum_data = 0xffff;
223 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
224 CSUM_IP_CHECKED | CSUM_IP_VALID;
225 }
226 m_adj(m, sizeof(struct loopback_header));
227
228 {
229 /* We need to prepend the address family as a four byte field. */
230 u_int32_t protocol_family =
231 ((struct loopback_header*)m->m_pkthdr.header)->protocol;
232
233 bpf_tap_out(ifp, DLT_NULL, m, &protocol_family, sizeof(protocol_family));
1c79356b 234 }
1c79356b 235 }
1c79356b 236
2d21ac55 237 return ifnet_input(ifp, m_list, NULL);
1c79356b
A
238}
239
240
241/*
91447636 242 * This is a common pre-output route used by INET and INET6. This could
1c79356b
A
243 * (should?) be split into separate pre-output routines for each protocol.
244 */
245
2d21ac55 246static errno_t
91447636 247lo_pre_output(
2d21ac55
A
248 __unused ifnet_t ifp,
249 protocol_family_t protocol_family,
250 mbuf_t *m,
91447636 251 __unused const struct sockaddr *dst,
2d21ac55
A
252 void *route,
253 char *frame_type,
254 __unused char *dst_addr)
1c79356b
A
255
256{
2d21ac55
A
257 register struct rtentry *rt = route;
258
259 (*m)->m_flags |= M_LOOP;
1c79356b 260
1c79356b
A
261 if (((*m)->m_flags & M_PKTHDR) == 0)
262 panic("looutput no HDR");
263
b0d623f7
A
264 if (rt != NULL) {
265 u_int32_t rt_flags = rt->rt_flags;
266 if (rt_flags & (RTF_REJECT | RTF_BLACKHOLE)) {
267 if (rt_flags & RTF_BLACKHOLE) {
268 m_freem(*m);
269 return EJUSTRETURN;
270 } else {
271 return ((rt_flags & RTF_HOST) ?
272 EHOSTUNREACH : ENETUNREACH);
273 }
91447636 274 }
1c79356b 275 }
b0d623f7 276
2d21ac55 277 *(protocol_family_t*)frame_type = protocol_family;
1c79356b
A
278
279 return 0;
280}
281
1c79356b
A
282/*
283 * lo_input - This should work for all attached protocols that use the
284 * ifq/schednetisr input mechanism.
285 */
2d21ac55 286static errno_t
91447636 287lo_input(
2d21ac55
A
288 __unused ifnet_t ifp,
289 __unused protocol_family_t protocol_family,
290 mbuf_t m)
1c79356b 291{
91447636 292 if (proto_input(protocol_family, m) != 0)
1c79356b 293 m_freem(m);
1c79356b
A
294 return (0);
295}
296
297
298
299
300/* ARGSUSED */
301static void
91447636
A
302lortrequest(
303 __unused int cmd,
304 struct rtentry *rt,
305 __unused struct sockaddr *sa)
1c79356b 306{
b0d623f7
A
307 if (rt != NULL) {
308 RT_LOCK_ASSERT_HELD(rt);
1c79356b
A
309 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
310 /*
311 * For optimal performance, the send and receive buffers
312 * should be at least twice the MTU plus a little more for
313 * overhead.
314 */
315 rt->rt_rmx.rmx_recvpipe =
316 rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
317 }
318}
319
320/*
321 * Process an ioctl request.
322 */
91447636
A
323static errno_t
324loioctl(
325 ifnet_t ifp,
b0d623f7 326 u_long cmd,
91447636 327 void* data)
1c79356b
A
328{
329 register struct ifaddr *ifa;
330 register struct ifreq *ifr = (struct ifreq *)data;
331 register int error = 0;
332
333 switch (cmd) {
334
335 case SIOCSIFADDR:
91447636 336 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
1c79356b 337 ifa = (struct ifaddr *)data;
6d2010ae 338 IFA_LOCK_SPIN(ifa);
1c79356b 339 ifa->ifa_rtrequest = lortrequest;
6d2010ae 340 IFA_UNLOCK(ifa);
1c79356b
A
341 /*
342 * Everything else is done at a higher level.
343 */
344 break;
345
346 case SIOCADDMULTI:
347 case SIOCDELMULTI:
348 if (ifr == 0) {
349 error = EAFNOSUPPORT; /* XXX */
350 break;
351 }
352 switch (ifr->ifr_addr.sa_family) {
353
354#if INET
355 case AF_INET:
356 break;
357#endif
358#if INET6
359 case AF_INET6:
360 break;
361#endif
362
363 default:
364 error = EAFNOSUPPORT;
365 break;
366 }
367 break;
368
369 case SIOCSIFMTU:
370 ifp->if_mtu = ifr->ifr_mtu;
371 break;
372
373 case SIOCSIFFLAGS:
374 break;
375
376 default:
377 error = EOPNOTSUPP;
4a249263 378 break;
1c79356b
A
379 }
380 return (error);
381}
382#endif /* NLOOP > 0 */
383
384
2d21ac55 385static errno_t lo_attach_proto(ifnet_t ifp, protocol_family_t protocol_family)
1c79356b 386{
2d21ac55
A
387 struct ifnet_attach_proto_param_v2 proto;
388 errno_t result = 0;
91447636 389
2d21ac55
A
390 bzero(&proto, sizeof(proto));
391 proto.input = lo_input;
392 proto.pre_output = lo_pre_output;
91447636 393
2d21ac55 394 result = ifnet_attach_protocol_v2(ifp, protocol_family, &proto);
1c79356b 395
2d21ac55
A
396 if (result && result != EEXIST) {
397 printf("lo_attach_proto: ifnet_attach_protocol for %u returned=%d\n",
398 protocol_family, result);
9bccf70c 399 }
91447636 400
2d21ac55 401 return result;
9bccf70c
A
402}
403
2d21ac55 404static void lo_reg_if_mods(void)
55e303ae 405{
55e303ae
A
406 int error;
407
55e303ae 408 /* Register protocol registration functions */
2d21ac55
A
409 if ((error = proto_register_plumber(PF_INET, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
410 printf("proto_register_plumber failed for AF_INET error=%d\n", error);
55e303ae 411
2d21ac55
A
412 if ((error = proto_register_plumber(PF_INET6, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
413 printf("proto_register_plumber failed for AF_INET6 error=%d\n", error);
55e303ae 414}
1c79356b 415
91447636
A
416static errno_t
417lo_set_bpf_tap(
418 ifnet_t ifp,
419 bpf_tap_mode mode,
420 bpf_packet_func bpf_callback)
1c79356b
A
421{
422
423 /*
424 * NEED MUTEX HERE XXX
425 */
426 if (mode == BPF_TAP_DISABLE) {
427 lo_statics[ifp->if_unit].bpf_mode = mode;
428 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
429 }
430 else {
431 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
432 lo_statics[ifp->if_unit].bpf_mode = mode;
433 }
434
435 return 0;
436}
437
438
439/* ARGSUSED */
440void
2d21ac55 441loopattach(void)
1c79356b 442{
2d21ac55
A
443 struct ifnet_init_params lo_init;
444 errno_t result = 0;
1c79356b 445
2d21ac55
A
446#if NLOOP != 1
447More than one loopback interface is not supported.
448#endif
1c79356b 449
2d21ac55
A
450 lo_reg_if_mods();
451
452 lo_statics[0].bpf_callback = 0;
453 lo_statics[0].bpf_mode = BPF_TAP_DISABLE;
454
455 bzero(&lo_init, sizeof(lo_init));
456 lo_init.name = "lo";
457 lo_init.unit = 0;
458 lo_init.family = IFNET_FAMILY_LOOPBACK;
459 lo_init.type = IFT_LOOP;
460 lo_init.output = lo_output;
461 lo_init.demux = lo_demux;
462 lo_init.add_proto = lo_add_proto;
463 lo_init.del_proto = lo_del_proto;
464 lo_init.framer = lo_framer;
465 lo_init.softc = &lo_statics[0];
466 lo_init.ioctl = loioctl;
467 lo_init.set_bpf_tap = lo_set_bpf_tap;
468 result = ifnet_allocate(&lo_init, &lo_ifp);
469 if (result != 0) {
470 printf("ifnet_allocate for lo0 failed - %d\n", result);
471 return;
472 }
473
474 ifnet_set_mtu(lo_ifp, LOMTU);
475 ifnet_set_flags(lo_ifp, IFF_LOOPBACK | IFF_MULTICAST, IFF_LOOPBACK | IFF_MULTICAST);
6d2010ae
A
476 ifnet_set_offload(lo_ifp, IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP |
477 IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_IPV6_FRAGMENT |
478 IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT | IFNET_MULTIPAGES);
2d21ac55
A
479 ifnet_set_hdrlen(lo_ifp, sizeof(struct loopback_header));
480 ifnet_set_eflags(lo_ifp, IFEF_SENDLIST, IFEF_SENDLIST);
481
482#if CONFIG_MACF_NET
483 mac_ifnet_label_init(ifp);
1c79356b 484#endif
2d21ac55
A
485
486 result = ifnet_attach(lo_ifp, NULL);
487 if (result != 0) {
488 printf("ifnet_attach lo0 failed - %d\n", result);
489 return;
1c79356b 490 }
2d21ac55
A
491 bpfattach(lo_ifp, DLT_NULL, sizeof(u_int));
492
91447636 493 loopattach_done = 1;
1c79356b 494}