]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_loop.c
5ba5b11a5dfe7747be0ece40199f6e05282c5e3d
[apple/xnu.git] / bsd / net / if_loop.c
1 /*
2 * Copyright (c) 2000-2010 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 #include <sys/mcache.h>
83
84 #include <net/if.h>
85 #include <net/if_types.h>
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
95 #if INET6
96 #if !INET
97 #include <netinet/in.h>
98 #endif
99 #include <netinet6/in6_var.h>
100 #include <netinet/ip6.h>
101 #endif
102
103 #include <net/dlil.h>
104 #include <net/kpi_protocol.h>
105
106 #if NETAT
107 extern struct ifqueue atalkintrq;
108 #endif
109
110 #if CONFIG_MACF_NET
111 #include <security/mac_framework.h>
112 #endif
113
114 #define NLOOP_ATTACHMENTS (NLOOP * 12)
115
116 struct lo_statics_str {
117 int bpf_mode;
118 bpf_packet_func bpf_callback;
119 };
120
121 void loopattach(void);
122
123 static struct lo_statics_str lo_statics[NLOOP];
124 int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
125
126 #ifdef TINY_LOMTU
127 #define LOMTU (1024+512)
128 #else
129 #define LOMTU 16384
130 #endif
131
132 ifnet_t lo_ifp = NULL;
133
134 struct loopback_header {
135 protocol_family_t protocol;
136 };
137
138 static void lo_reg_if_mods(void);
139
140 /* Local forward declerations */
141
142 static errno_t
143 lo_demux(
144 __unused ifnet_t ifp,
145 __unused mbuf_t m,
146 char *frame_header,
147 protocol_family_t *protocol_family)
148 {
149 struct loopback_header *header = (struct loopback_header *)frame_header;
150
151 *protocol_family = header->protocol;
152
153 return 0;
154 }
155
156
157 static errno_t
158 lo_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)
164 {
165 struct loopback_header *header;
166
167 M_PREPEND(*m, sizeof(struct loopback_header), M_WAITOK);
168 if (*m == NULL)
169 return EJUSTRETURN; /* Tell caller not to try to free passed-in mbuf */
170 header = mtod(*m, struct loopback_header*);
171 header->protocol = *(const u_int32_t*)frame_type;
172 return 0;
173 }
174
175 static errno_t
176 lo_add_proto(
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)
181 {
182 return 0;
183 }
184
185
186 static errno_t
187 lo_del_proto(
188 __unused ifnet_t ifp,
189 __unused protocol_family_t protocol)
190 {
191 return 0;
192 }
193
194 static int
195 lo_output(
196 ifnet_t ifp,
197 mbuf_t m_list)
198 {
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");
204
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;
212
213 atomic_add_64(&ifp->if_ibytes, m->m_pkthdr.len);
214 atomic_add_64(&ifp->if_obytes, m->m_pkthdr.len);
215
216 atomic_add_64(&ifp->if_opackets, 1);
217 atomic_add_64(&ifp->if_ipackets, 1);
218
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));
234 }
235 }
236
237 return ifnet_input(ifp, m_list, NULL);
238 }
239
240
241 /*
242 * This is a common pre-output route used by INET and INET6. This could
243 * (should?) be split into separate pre-output routines for each protocol.
244 */
245
246 static errno_t
247 lo_pre_output(
248 __unused ifnet_t ifp,
249 protocol_family_t protocol_family,
250 mbuf_t *m,
251 __unused const struct sockaddr *dst,
252 void *route,
253 char *frame_type,
254 __unused char *dst_addr)
255
256 {
257 register struct rtentry *rt = route;
258
259 (*m)->m_flags |= M_LOOP;
260
261 if (((*m)->m_flags & M_PKTHDR) == 0)
262 panic("looutput no HDR");
263
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 }
274 }
275 }
276
277 *(protocol_family_t*)frame_type = protocol_family;
278
279 return 0;
280 }
281
282 /*
283 * lo_input - This should work for all attached protocols that use the
284 * ifq/schednetisr input mechanism.
285 */
286 static errno_t
287 lo_input(
288 __unused ifnet_t ifp,
289 __unused protocol_family_t protocol_family,
290 mbuf_t m)
291 {
292 if (proto_input(protocol_family, m) != 0)
293 m_freem(m);
294 return (0);
295 }
296
297
298
299
300 /* ARGSUSED */
301 static void
302 lortrequest(
303 __unused int cmd,
304 struct rtentry *rt,
305 __unused struct sockaddr *sa)
306 {
307 if (rt != NULL) {
308 RT_LOCK_ASSERT_HELD(rt);
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 */
323 static errno_t
324 loioctl(
325 ifnet_t ifp,
326 u_long cmd,
327 void* data)
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:
336 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
337 ifa = (struct ifaddr *)data;
338 IFA_LOCK_SPIN(ifa);
339 ifa->ifa_rtrequest = lortrequest;
340 IFA_UNLOCK(ifa);
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;
378 break;
379 }
380 return (error);
381 }
382 #endif /* NLOOP > 0 */
383
384
385 static errno_t lo_attach_proto(ifnet_t ifp, protocol_family_t protocol_family)
386 {
387 struct ifnet_attach_proto_param_v2 proto;
388 errno_t result = 0;
389
390 bzero(&proto, sizeof(proto));
391 proto.input = lo_input;
392 proto.pre_output = lo_pre_output;
393
394 result = ifnet_attach_protocol_v2(ifp, protocol_family, &proto);
395
396 if (result && result != EEXIST) {
397 printf("lo_attach_proto: ifnet_attach_protocol for %u returned=%d\n",
398 protocol_family, result);
399 }
400
401 return result;
402 }
403
404 static void lo_reg_if_mods(void)
405 {
406 int error;
407
408 /* Register protocol registration functions */
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);
411
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);
414 }
415
416 static errno_t
417 lo_set_bpf_tap(
418 ifnet_t ifp,
419 bpf_tap_mode mode,
420 bpf_packet_func bpf_callback)
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 */
440 void
441 loopattach(void)
442 {
443 struct ifnet_init_params lo_init;
444 errno_t result = 0;
445
446 #if NLOOP != 1
447 More than one loopback interface is not supported.
448 #endif
449
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);
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);
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 }