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