]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_loop.c
xnu-792.6.76.tar.gz
[apple/xnu.git] / bsd / net / if_loop.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
37839358
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1982, 1986, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)if_loop.c 8.1 (Berkeley) 6/10/93
9bccf70c 55 * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.5 2001/07/03 11:01:41 ume Exp $
1c79356b
A
56 */
57
58/*
59 * Loopback interface driver for protocol testing and timing.
60 */
61#include "loop.h"
62#if NLOOP > 0
63
64#include <sys/param.h>
65#include <sys/systm.h>
66#include <sys/kernel.h>
67#include <sys/mbuf.h>
68#include <sys/socket.h>
69#include <sys/sockio.h>
70
71#include <net/if.h>
72#include <net/if_types.h>
1c79356b
A
73#include <net/route.h>
74#include <net/bpf.h>
75#include <sys/malloc.h>
76
77#if INET
78#include <netinet/in.h>
79#include <netinet/in_var.h>
80#endif
81
82#if IPX
83#include <netipx/ipx.h>
84#include <netipx/ipx_if.h>
85#endif
86
87#if INET6
88#ifndef INET
89#include <netinet/in.h>
90#endif
91#include <netinet6/in6_var.h>
92#include <netinet/ip6.h>
93#endif
94
1c79356b 95#include <net/dlil.h>
91447636 96#include <net/kpi_protocol.h>
1c79356b
A
97
98#if NETAT
99extern struct ifqueue atalkintrq;
100#endif
101
102#include "bpfilter.h"
103#if NBPFILTER > 0
104#include <net/bpfdesc.h>
105#endif
106
107#define NLOOP_ATTACHMENTS (NLOOP * 12)
108
109struct lo_statics_str {
91447636
A
110 int bpf_mode;
111 bpf_packet_func bpf_callback;
1c79356b
A
112};
113
91447636 114void loopattach(void *dummy);
1c79356b 115
91447636
A
116static struct lo_statics_str lo_statics[NLOOP];
117int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
1c79356b
A
118
119#ifdef TINY_LOMTU
120#define LOMTU (1024+512)
121#else
122#define LOMTU 16384
123#endif
124
125struct ifnet loif[NLOOP];
91447636 126struct ifnet *lo_ifp = &loif[0];
1c79356b 127
91447636
A
128struct loopback_header {
129 u_long protocol;
130};
1c79356b 131
91447636 132void lo_reg_if_mods(void);
1c79356b 133
91447636 134/* Local forward declerations */
1c79356b 135
91447636
A
136static errno_t
137lo_demux(
138 __unused ifnet_t ifp,
139 __unused mbuf_t m,
140 char *frame_header,
141 protocol_family_t *protocol_family)
1c79356b 142{
91447636
A
143 struct loopback_header *header = (struct loopback_header *)frame_header;
144
145 *protocol_family = header->protocol;
146
147 return 0;
1c79356b
A
148}
149
150
91447636
A
151static errno_t
152lo_framer(
153 __unused ifnet_t ifp,
154 mbuf_t *m,
155 __unused const struct sockaddr *dest,
156 __unused const char *dest_linkaddr,
157 const char *frame_type)
1c79356b 158{
91447636 159 struct loopback_header *header;
1c79356b 160
91447636
A
161 M_PREPEND(*m, sizeof(struct loopback_header), M_WAITOK);
162 header = mtod(*m, struct loopback_header*);
163 header->protocol = *(const u_long*)frame_type;
1c79356b
A
164 return 0;
165}
166
91447636
A
167static errno_t
168lo_add_proto(
169 __unused struct ifnet *ifp,
170 __unused u_long protocol_family,
171 __unused struct ddesc_head_str *demux_desc_head)
1c79356b
A
172{
173 return 0;
174}
175
176
91447636
A
177static errno_t
178lo_del_proto(
179 __unused ifnet_t ifp,
180 __unused protocol_family_t protocol)
1c79356b 181{
91447636 182 return 0;
1c79356b
A
183}
184
185static int
91447636
A
186lo_output(
187 struct ifnet *ifp,
188 struct mbuf *m)
189{
1c79356b
A
190
191 if ((m->m_flags & M_PKTHDR) == 0)
192 panic("lo_output: no HDR");
193
194 /*
195 * Don't overwrite the rcvif field if it is in use.
196 * This is used to match multicast packets, sent looping
197 * back, with the appropriate group record on input.
198 */
199 if (m->m_pkthdr.rcvif == NULL)
200 m->m_pkthdr.rcvif = ifp;
1c79356b 201
91447636
A
202 ifp->if_ibytes += m->m_pkthdr.len;
203 ifp->if_obytes += m->m_pkthdr.len;
204
205 ifp->if_opackets++;
206 ifp->if_ipackets++;
207
208 m->m_pkthdr.header = mtod(m, char *);
209 m->m_pkthdr.csum_data = 0xffff; /* loopback checksums are always OK */
210 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
211 CSUM_IP_CHECKED | CSUM_IP_VALID;
212 m_adj(m, sizeof(struct loopback_header));
1c79356b
A
213
214#if NBPFILTER > 0
215 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
216 struct mbuf m0, *n;
217
1c79356b
A
218 n = m;
219 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
91447636 220 struct loopback_header *header;
1c79356b
A
221 /*
222 * We need to prepend the address family as
223 * a four byte field. Cons up a dummy header
224 * to pacify bpf. This is safe because bpf
225 * will only read from the mbuf (i.e., it won't
226 * try to free it or keep a pointer a to it).
227 */
91447636 228 header = (struct loopback_header*)m->m_pkthdr.header;
1c79356b
A
229 m0.m_next = m;
230 m0.m_len = 4;
91447636 231 m0.m_data = (char *)&header->protocol;
1c79356b
A
232 n = &m0;
233 }
234
91447636 235 lo_statics[ifp->if_unit].bpf_callback(ifp, n);
1c79356b
A
236 }
237#endif
238
1c79356b
A
239 return dlil_input(ifp, m, m);
240}
241
242
243/*
91447636 244 * This is a common pre-output route used by INET and INET6. This could
1c79356b
A
245 * (should?) be split into separate pre-output routines for each protocol.
246 */
247
248static int
91447636
A
249lo_pre_output(
250 __unused struct ifnet *ifp,
251 u_long protocol_family,
252 struct mbuf **m,
253 __unused const struct sockaddr *dst,
254 caddr_t route,
255 char *frame_type,
256 __unused char *dst_addr)
1c79356b
A
257
258{
1c79356b
A
259 register struct rtentry *rt = (struct rtentry *) route;
260
1c79356b
A
261 if (((*m)->m_flags & M_PKTHDR) == 0)
262 panic("looutput no HDR");
263
264 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
91447636
A
265 if (rt->rt_flags & RTF_BLACKHOLE) {
266 m_freem(*m);
267 return EJUSTRETURN;
268 }
269 else
270 return ((rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH);
1c79356b 271 }
91447636
A
272
273 *(u_long *)frame_type = protocol_family;
1c79356b
A
274
275 return 0;
276}
277
1c79356b
A
278/*
279 * lo_input - This should work for all attached protocols that use the
280 * ifq/schednetisr input mechanism.
281 */
91447636
A
282static int
283lo_input(
284 struct mbuf *m,
285 __unused char *fh,
286 __unused struct ifnet *ifp,
287 __unused u_long protocol_family,
288 __unused int sync_ok)
1c79356b 289{
91447636 290 if (proto_input(protocol_family, m) != 0)
1c79356b 291 m_freem(m);
1c79356b
A
292 return (0);
293}
294
295
296
297
298/* ARGSUSED */
299static void
91447636
A
300lortrequest(
301 __unused int cmd,
302 struct rtentry *rt,
303 __unused struct sockaddr *sa)
1c79356b
A
304{
305 if (rt) {
306 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
307 /*
308 * For optimal performance, the send and receive buffers
309 * should be at least twice the MTU plus a little more for
310 * overhead.
311 */
312 rt->rt_rmx.rmx_recvpipe =
313 rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
314 }
315}
316
317/*
318 * Process an ioctl request.
319 */
91447636
A
320static errno_t
321loioctl(
322 ifnet_t ifp,
323 u_int32_t cmd,
324 void* data)
1c79356b
A
325{
326 register struct ifaddr *ifa;
327 register struct ifreq *ifr = (struct ifreq *)data;
328 register int error = 0;
329
330 switch (cmd) {
331
332 case SIOCSIFADDR:
91447636 333 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
1c79356b
A
334 ifa = (struct ifaddr *)data;
335 ifa->ifa_rtrequest = lortrequest;
336 /*
337 * Everything else is done at a higher level.
338 */
339 break;
340
341 case SIOCADDMULTI:
342 case SIOCDELMULTI:
343 if (ifr == 0) {
344 error = EAFNOSUPPORT; /* XXX */
345 break;
346 }
347 switch (ifr->ifr_addr.sa_family) {
348
349#if INET
350 case AF_INET:
351 break;
352#endif
353#if INET6
354 case AF_INET6:
355 break;
356#endif
357
358 default:
359 error = EAFNOSUPPORT;
360 break;
361 }
362 break;
363
364 case SIOCSIFMTU:
365 ifp->if_mtu = ifr->ifr_mtu;
366 break;
367
368 case SIOCSIFFLAGS:
369 break;
370
371 default:
372 error = EOPNOTSUPP;
4a249263 373 break;
1c79356b
A
374 }
375 return (error);
376}
377#endif /* NLOOP > 0 */
378
379
91447636 380static int lo_attach_proto(struct ifnet *ifp, u_long protocol_family)
1c79356b 381{
91447636
A
382 struct dlil_proto_reg_str reg;
383 int stat =0 ;
384
385 bzero(&reg, sizeof(reg));
386 TAILQ_INIT(&reg.demux_desc_head);
387 reg.interface_family = ifp->if_family;
388 reg.unit_number = ifp->if_unit;
389 reg.input = lo_input;
390 reg.pre_output = lo_pre_output;
391 reg.protocol_family = protocol_family;
392
393 stat = dlil_attach_protocol(&reg);
1c79356b 394
91447636
A
395 if (stat && stat != EEXIST) {
396 printf("lo_attach_proto: dlil_attach_protocol for %d returned=%d\n",
397 protocol_family, stat);
9bccf70c 398 }
91447636
A
399
400 return stat;
9bccf70c
A
401}
402
55e303ae
A
403void lo_reg_if_mods()
404{
55e303ae
A
405 int error;
406
55e303ae 407 /* Register protocol registration functions */
91447636 408 if ((error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
55e303ae
A
409 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
410
91447636 411 if ((error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
55e303ae 412 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
55e303ae 413}
1c79356b 414
91447636
A
415static errno_t
416lo_set_bpf_tap(
417 ifnet_t ifp,
418 bpf_tap_mode mode,
419 bpf_packet_func bpf_callback)
1c79356b
A
420{
421
422 /*
423 * NEED MUTEX HERE XXX
424 */
425 if (mode == BPF_TAP_DISABLE) {
426 lo_statics[ifp->if_unit].bpf_mode = mode;
427 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
428 }
429 else {
430 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
431 lo_statics[ifp->if_unit].bpf_mode = mode;
432 }
433
434 return 0;
435}
436
437
438/* ARGSUSED */
439void
91447636
A
440loopattach(
441 __unused void *dummy)
1c79356b 442{
91447636
A
443 struct ifnet *ifp;
444 int i = 0;
1c79356b 445
1c79356b
A
446 lo_reg_if_mods();
447
448 for (ifp = loif; i < NLOOP; ifp++) {
449 lo_statics[i].bpf_callback = 0;
450 lo_statics[i].bpf_mode = BPF_TAP_DISABLE;
91447636 451 bzero(ifp, sizeof(struct ifnet));
1c79356b
A
452 ifp->if_name = "lo";
453 ifp->if_family = APPLE_IF_FAM_LOOPBACK;
454 ifp->if_unit = i++;
455 ifp->if_mtu = LOMTU;
456 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
91447636
A
457 ifp->if_ioctl = loioctl;
458 ifp->if_demux = lo_demux;
459 ifp->if_framer = lo_framer;
460 ifp->if_add_proto = lo_add_proto;
461 ifp->if_del_proto = lo_del_proto;
1c79356b
A
462 ifp->if_set_bpf_tap = lo_set_bpf_tap;
463 ifp->if_output = lo_output;
464 ifp->if_type = IFT_LOOP;
91447636
A
465 ifp->if_hwassist = IF_HWASSIST_CSUM_IP | IF_HWASSIST_CSUM_TCP | IF_HWASSIST_CSUM_UDP;
466 ifp->if_hdrlen = sizeof(struct loopback_header);
467 lo_ifp = ifp;
1c79356b
A
468 dlil_if_attach(ifp);
469#if NBPFILTER > 0
470 bpfattach(ifp, DLT_NULL, sizeof(u_int));
471#endif
472 }
91447636 473 loopattach_done = 1;
1c79356b 474}