]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_loop.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / bsd / net / if_loop.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
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.
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
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
A
62 */
63
64/*
65 * Loopback interface driver for protocol testing and timing.
66 */
67#include "loop.h"
68#if NLOOP > 0
69
70#include <sys/param.h>
71#include <sys/systm.h>
72#include <sys/kernel.h>
73#include <sys/mbuf.h>
74#include <sys/socket.h>
75#include <sys/sockio.h>
76
77#include <net/if.h>
78#include <net/if_types.h>
1c79356b
A
79#include <net/route.h>
80#include <net/bpf.h>
81#include <sys/malloc.h>
82
83#if INET
84#include <netinet/in.h>
85#include <netinet/in_var.h>
86#endif
87
88#if IPX
89#include <netipx/ipx.h>
90#include <netipx/ipx_if.h>
91#endif
92
93#if INET6
94#ifndef INET
95#include <netinet/in.h>
96#endif
97#include <netinet6/in6_var.h>
98#include <netinet/ip6.h>
99#endif
100
1c79356b 101#include <net/dlil.h>
91447636 102#include <net/kpi_protocol.h>
1c79356b
A
103
104#if NETAT
105extern struct ifqueue atalkintrq;
106#endif
107
108#include "bpfilter.h"
109#if NBPFILTER > 0
110#include <net/bpfdesc.h>
111#endif
112
113#define NLOOP_ATTACHMENTS (NLOOP * 12)
114
115struct lo_statics_str {
91447636
A
116 int bpf_mode;
117 bpf_packet_func bpf_callback;
1c79356b
A
118};
119
91447636 120void loopattach(void *dummy);
1c79356b 121
91447636
A
122static struct lo_statics_str lo_statics[NLOOP];
123int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
1c79356b
A
124
125#ifdef TINY_LOMTU
126#define LOMTU (1024+512)
127#else
128#define LOMTU 16384
129#endif
130
131struct ifnet loif[NLOOP];
91447636 132struct ifnet *lo_ifp = &loif[0];
1c79356b 133
91447636
A
134struct loopback_header {
135 u_long protocol;
136};
1c79356b 137
91447636 138void 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
A
167 M_PREPEND(*m, sizeof(struct loopback_header), M_WAITOK);
168 header = mtod(*m, struct loopback_header*);
169 header->protocol = *(const u_long*)frame_type;
1c79356b
A
170 return 0;
171}
172
91447636
A
173static errno_t
174lo_add_proto(
175 __unused struct ifnet *ifp,
176 __unused u_long protocol_family,
177 __unused struct ddesc_head_str *demux_desc_head)
1c79356b
A
178{
179 return 0;
180}
181
182
91447636
A
183static errno_t
184lo_del_proto(
185 __unused ifnet_t ifp,
186 __unused protocol_family_t protocol)
1c79356b 187{
91447636 188 return 0;
1c79356b
A
189}
190
191static int
91447636
A
192lo_output(
193 struct ifnet *ifp,
194 struct mbuf *m)
195{
1c79356b
A
196
197 if ((m->m_flags & M_PKTHDR) == 0)
198 panic("lo_output: no HDR");
199
200 /*
201 * Don't overwrite the rcvif field if it is in use.
202 * This is used to match multicast packets, sent looping
203 * back, with the appropriate group record on input.
204 */
205 if (m->m_pkthdr.rcvif == NULL)
206 m->m_pkthdr.rcvif = ifp;
1c79356b 207
91447636
A
208 ifp->if_ibytes += m->m_pkthdr.len;
209 ifp->if_obytes += m->m_pkthdr.len;
210
211 ifp->if_opackets++;
212 ifp->if_ipackets++;
213
214 m->m_pkthdr.header = mtod(m, char *);
215 m->m_pkthdr.csum_data = 0xffff; /* loopback checksums are always OK */
216 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
217 CSUM_IP_CHECKED | CSUM_IP_VALID;
218 m_adj(m, sizeof(struct loopback_header));
1c79356b
A
219
220#if NBPFILTER > 0
221 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
222 struct mbuf m0, *n;
223
1c79356b
A
224 n = m;
225 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
91447636 226 struct loopback_header *header;
1c79356b
A
227 /*
228 * We need to prepend the address family as
229 * a four byte field. Cons up a dummy header
230 * to pacify bpf. This is safe because bpf
231 * will only read from the mbuf (i.e., it won't
232 * try to free it or keep a pointer a to it).
233 */
91447636 234 header = (struct loopback_header*)m->m_pkthdr.header;
1c79356b
A
235 m0.m_next = m;
236 m0.m_len = 4;
91447636 237 m0.m_data = (char *)&header->protocol;
1c79356b
A
238 n = &m0;
239 }
240
91447636 241 lo_statics[ifp->if_unit].bpf_callback(ifp, n);
1c79356b
A
242 }
243#endif
244
1c79356b
A
245 return dlil_input(ifp, m, m);
246}
247
248
249/*
91447636 250 * This is a common pre-output route used by INET and INET6. This could
1c79356b
A
251 * (should?) be split into separate pre-output routines for each protocol.
252 */
253
254static int
91447636
A
255lo_pre_output(
256 __unused struct ifnet *ifp,
257 u_long protocol_family,
258 struct mbuf **m,
259 __unused const struct sockaddr *dst,
260 caddr_t route,
261 char *frame_type,
262 __unused char *dst_addr)
1c79356b
A
263
264{
1c79356b
A
265 register struct rtentry *rt = (struct rtentry *) route;
266
1c79356b
A
267 if (((*m)->m_flags & M_PKTHDR) == 0)
268 panic("looutput no HDR");
269
270 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
91447636
A
271 if (rt->rt_flags & RTF_BLACKHOLE) {
272 m_freem(*m);
273 return EJUSTRETURN;
274 }
275 else
276 return ((rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH);
1c79356b 277 }
91447636
A
278
279 *(u_long *)frame_type = protocol_family;
1c79356b
A
280
281 return 0;
282}
283
1c79356b
A
284/*
285 * lo_input - This should work for all attached protocols that use the
286 * ifq/schednetisr input mechanism.
287 */
91447636
A
288static int
289lo_input(
290 struct mbuf *m,
291 __unused char *fh,
292 __unused struct ifnet *ifp,
293 __unused u_long protocol_family,
294 __unused int sync_ok)
1c79356b 295{
91447636 296 if (proto_input(protocol_family, m) != 0)
1c79356b 297 m_freem(m);
1c79356b
A
298 return (0);
299}
300
301
302
303
304/* ARGSUSED */
305static void
91447636
A
306lortrequest(
307 __unused int cmd,
308 struct rtentry *rt,
309 __unused struct sockaddr *sa)
1c79356b
A
310{
311 if (rt) {
312 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
313 /*
314 * For optimal performance, the send and receive buffers
315 * should be at least twice the MTU plus a little more for
316 * overhead.
317 */
318 rt->rt_rmx.rmx_recvpipe =
319 rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
320 }
321}
322
323/*
324 * Process an ioctl request.
325 */
91447636
A
326static errno_t
327loioctl(
328 ifnet_t ifp,
329 u_int32_t cmd,
330 void* data)
1c79356b
A
331{
332 register struct ifaddr *ifa;
333 register struct ifreq *ifr = (struct ifreq *)data;
334 register int error = 0;
335
336 switch (cmd) {
337
338 case SIOCSIFADDR:
91447636 339 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
1c79356b
A
340 ifa = (struct ifaddr *)data;
341 ifa->ifa_rtrequest = lortrequest;
342 /*
343 * Everything else is done at a higher level.
344 */
345 break;
346
347 case SIOCADDMULTI:
348 case SIOCDELMULTI:
349 if (ifr == 0) {
350 error = EAFNOSUPPORT; /* XXX */
351 break;
352 }
353 switch (ifr->ifr_addr.sa_family) {
354
355#if INET
356 case AF_INET:
357 break;
358#endif
359#if INET6
360 case AF_INET6:
361 break;
362#endif
363
364 default:
365 error = EAFNOSUPPORT;
366 break;
367 }
368 break;
369
370 case SIOCSIFMTU:
371 ifp->if_mtu = ifr->ifr_mtu;
372 break;
373
374 case SIOCSIFFLAGS:
375 break;
376
377 default:
378 error = EOPNOTSUPP;
4a249263 379 break;
1c79356b
A
380 }
381 return (error);
382}
383#endif /* NLOOP > 0 */
384
385
91447636 386static int lo_attach_proto(struct ifnet *ifp, u_long protocol_family)
1c79356b 387{
91447636
A
388 struct dlil_proto_reg_str reg;
389 int stat =0 ;
390
391 bzero(&reg, sizeof(reg));
392 TAILQ_INIT(&reg.demux_desc_head);
393 reg.interface_family = ifp->if_family;
394 reg.unit_number = ifp->if_unit;
395 reg.input = lo_input;
396 reg.pre_output = lo_pre_output;
397 reg.protocol_family = protocol_family;
398
399 stat = dlil_attach_protocol(&reg);
1c79356b 400
91447636
A
401 if (stat && stat != EEXIST) {
402 printf("lo_attach_proto: dlil_attach_protocol for %d returned=%d\n",
403 protocol_family, stat);
9bccf70c 404 }
91447636
A
405
406 return stat;
9bccf70c
A
407}
408
55e303ae
A
409void lo_reg_if_mods()
410{
55e303ae
A
411 int error;
412
55e303ae 413 /* Register protocol registration functions */
91447636 414 if ((error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
55e303ae
A
415 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
416
91447636 417 if ((error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
55e303ae 418 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
55e303ae 419}
1c79356b 420
91447636
A
421static errno_t
422lo_set_bpf_tap(
423 ifnet_t ifp,
424 bpf_tap_mode mode,
425 bpf_packet_func bpf_callback)
1c79356b
A
426{
427
428 /*
429 * NEED MUTEX HERE XXX
430 */
431 if (mode == BPF_TAP_DISABLE) {
432 lo_statics[ifp->if_unit].bpf_mode = mode;
433 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
434 }
435 else {
436 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
437 lo_statics[ifp->if_unit].bpf_mode = mode;
438 }
439
440 return 0;
441}
442
443
444/* ARGSUSED */
445void
91447636
A
446loopattach(
447 __unused void *dummy)
1c79356b 448{
91447636
A
449 struct ifnet *ifp;
450 int i = 0;
1c79356b 451
1c79356b
A
452 lo_reg_if_mods();
453
454 for (ifp = loif; i < NLOOP; ifp++) {
455 lo_statics[i].bpf_callback = 0;
456 lo_statics[i].bpf_mode = BPF_TAP_DISABLE;
91447636 457 bzero(ifp, sizeof(struct ifnet));
1c79356b
A
458 ifp->if_name = "lo";
459 ifp->if_family = APPLE_IF_FAM_LOOPBACK;
460 ifp->if_unit = i++;
461 ifp->if_mtu = LOMTU;
462 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
91447636
A
463 ifp->if_ioctl = loioctl;
464 ifp->if_demux = lo_demux;
465 ifp->if_framer = lo_framer;
466 ifp->if_add_proto = lo_add_proto;
467 ifp->if_del_proto = lo_del_proto;
1c79356b
A
468 ifp->if_set_bpf_tap = lo_set_bpf_tap;
469 ifp->if_output = lo_output;
470 ifp->if_type = IFT_LOOP;
91447636
A
471 ifp->if_hwassist = IF_HWASSIST_CSUM_IP | IF_HWASSIST_CSUM_TCP | IF_HWASSIST_CSUM_UDP;
472 ifp->if_hdrlen = sizeof(struct loopback_header);
473 lo_ifp = ifp;
1c79356b
A
474 dlil_if_attach(ifp);
475#if NBPFILTER > 0
476 bpfattach(ifp, DLT_NULL, sizeof(u_int));
477#endif
478 }
91447636 479 loopattach_done = 1;
1c79356b 480}