]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_loop.c
ee62c35a12cee8b13673405946688c1e8626af87
[apple/xnu.git] / bsd / net / if_loop.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
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@
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
63 * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.5 2001/07/03 11:01:41 ume Exp $
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>
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
103 #include <net/dlil.h>
104 #include <net/kpi_protocol.h>
105
106 #if NETAT
107 extern 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
117 struct lo_statics_str {
118 int bpf_mode;
119 bpf_packet_func bpf_callback;
120 };
121
122 void loopattach(void *dummy);
123
124 static struct lo_statics_str lo_statics[NLOOP];
125 int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
126
127 #ifdef TINY_LOMTU
128 #define LOMTU (1024+512)
129 #else
130 #define LOMTU 16384
131 #endif
132
133 struct ifnet loif[NLOOP];
134 struct ifnet *lo_ifp = &loif[0];
135
136 struct loopback_header {
137 u_long protocol;
138 };
139
140 void lo_reg_if_mods(void);
141
142 /* Local forward declerations */
143
144 static errno_t
145 lo_demux(
146 __unused ifnet_t ifp,
147 __unused mbuf_t m,
148 char *frame_header,
149 protocol_family_t *protocol_family)
150 {
151 struct loopback_header *header = (struct loopback_header *)frame_header;
152
153 *protocol_family = header->protocol;
154
155 return 0;
156 }
157
158
159 static errno_t
160 lo_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)
166 {
167 struct loopback_header *header;
168
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;
172 return 0;
173 }
174
175 static errno_t
176 lo_add_proto(
177 __unused struct ifnet *ifp,
178 __unused u_long protocol_family,
179 __unused struct ddesc_head_str *demux_desc_head)
180 {
181 return 0;
182 }
183
184
185 static errno_t
186 lo_del_proto(
187 __unused ifnet_t ifp,
188 __unused protocol_family_t protocol)
189 {
190 return 0;
191 }
192
193 static int
194 lo_output(
195 struct ifnet *ifp,
196 struct mbuf *m)
197 {
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;
209
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));
221
222 #if NBPFILTER > 0
223 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
224 struct mbuf m0, *n;
225
226 n = m;
227 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
228 struct loopback_header *header;
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 */
236 header = (struct loopback_header*)m->m_pkthdr.header;
237 m0.m_next = m;
238 m0.m_len = 4;
239 m0.m_data = (char *)&header->protocol;
240 n = &m0;
241 }
242
243 lo_statics[ifp->if_unit].bpf_callback(ifp, n);
244 }
245 #endif
246
247 return dlil_input(ifp, m, m);
248 }
249
250
251 /*
252 * This is a common pre-output route used by INET and INET6. This could
253 * (should?) be split into separate pre-output routines for each protocol.
254 */
255
256 static int
257 lo_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)
265
266 {
267 register struct rtentry *rt = (struct rtentry *) route;
268
269 if (((*m)->m_flags & M_PKTHDR) == 0)
270 panic("looutput no HDR");
271
272 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
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);
279 }
280
281 *(u_long *)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 int
291 lo_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)
297 {
298 if (proto_input(protocol_family, m) != 0)
299 m_freem(m);
300 return (0);
301 }
302
303
304
305
306 /* ARGSUSED */
307 static void
308 lortrequest(
309 __unused int cmd,
310 struct rtentry *rt,
311 __unused struct sockaddr *sa)
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 */
328 static errno_t
329 loioctl(
330 ifnet_t ifp,
331 u_int32_t cmd,
332 void* data)
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:
341 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
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;
381 break;
382 }
383 return (error);
384 }
385 #endif /* NLOOP > 0 */
386
387
388 static int lo_attach_proto(struct ifnet *ifp, u_long protocol_family)
389 {
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);
402
403 if (stat && stat != EEXIST) {
404 printf("lo_attach_proto: dlil_attach_protocol for %d returned=%d\n",
405 protocol_family, stat);
406 }
407
408 return stat;
409 }
410
411 void lo_reg_if_mods()
412 {
413 int error;
414
415 /* Register protocol registration functions */
416 if ((error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
417 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
418
419 if ((error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
420 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
421 }
422
423 static errno_t
424 lo_set_bpf_tap(
425 ifnet_t ifp,
426 bpf_tap_mode mode,
427 bpf_packet_func bpf_callback)
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 */
447 void
448 loopattach(
449 __unused void *dummy)
450 {
451 struct ifnet *ifp;
452 int i = 0;
453
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;
459 bzero(ifp, sizeof(struct ifnet));
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;
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;
470 ifp->if_set_bpf_tap = lo_set_bpf_tap;
471 ifp->if_output = lo_output;
472 ifp->if_type = IFT_LOOP;
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;
476 dlil_if_attach(ifp);
477 #if NBPFILTER > 0
478 bpfattach(ifp, DLT_NULL, sizeof(u_int));
479 #endif
480 }
481 loopattach_done = 1;
482 }