]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_loop.c
6cfcb8a891964de37a5e9a19a725b407bcffbf09
[apple/xnu.git] / bsd / net / if_loop.c
1 /*
2 * Copyright (c) 2000 Apple Computer, 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 /*
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>
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
101 #include <net/dlil.h>
102 #include <net/kpi_protocol.h>
103
104 #if NETAT
105 extern 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
115 struct lo_statics_str {
116 int bpf_mode;
117 bpf_packet_func bpf_callback;
118 };
119
120 void loopattach(void *dummy);
121
122 static struct lo_statics_str lo_statics[NLOOP];
123 int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
124
125 #ifdef TINY_LOMTU
126 #define LOMTU (1024+512)
127 #else
128 #define LOMTU 16384
129 #endif
130
131 struct ifnet loif[NLOOP];
132 struct ifnet *lo_ifp = &loif[0];
133
134 struct loopback_header {
135 u_long protocol;
136 };
137
138 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 header = mtod(*m, struct loopback_header*);
169 header->protocol = *(const u_long*)frame_type;
170 return 0;
171 }
172
173 static errno_t
174 lo_add_proto(
175 __unused struct ifnet *ifp,
176 __unused u_long protocol_family,
177 __unused struct ddesc_head_str *demux_desc_head)
178 {
179 return 0;
180 }
181
182
183 static errno_t
184 lo_del_proto(
185 __unused ifnet_t ifp,
186 __unused protocol_family_t protocol)
187 {
188 return 0;
189 }
190
191 static int
192 lo_output(
193 struct ifnet *ifp,
194 struct mbuf *m)
195 {
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;
207
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));
219
220 #if NBPFILTER > 0
221 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
222 struct mbuf m0, *n;
223
224 n = m;
225 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
226 struct loopback_header *header;
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 */
234 header = (struct loopback_header*)m->m_pkthdr.header;
235 m0.m_next = m;
236 m0.m_len = 4;
237 m0.m_data = (char *)&header->protocol;
238 n = &m0;
239 }
240
241 lo_statics[ifp->if_unit].bpf_callback(ifp, n);
242 }
243 #endif
244
245 return dlil_input(ifp, m, m);
246 }
247
248
249 /*
250 * This is a common pre-output route used by INET and INET6. This could
251 * (should?) be split into separate pre-output routines for each protocol.
252 */
253
254 static int
255 lo_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)
263
264 {
265 register struct rtentry *rt = (struct rtentry *) route;
266
267 if (((*m)->m_flags & M_PKTHDR) == 0)
268 panic("looutput no HDR");
269
270 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
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);
277 }
278
279 *(u_long *)frame_type = protocol_family;
280
281 return 0;
282 }
283
284 /*
285 * lo_input - This should work for all attached protocols that use the
286 * ifq/schednetisr input mechanism.
287 */
288 static int
289 lo_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)
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) {
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 */
326 static errno_t
327 loioctl(
328 ifnet_t ifp,
329 u_int32_t cmd,
330 void* data)
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:
339 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
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;
379 break;
380 }
381 return (error);
382 }
383 #endif /* NLOOP > 0 */
384
385
386 static int lo_attach_proto(struct ifnet *ifp, u_long protocol_family)
387 {
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);
400
401 if (stat && stat != EEXIST) {
402 printf("lo_attach_proto: dlil_attach_protocol for %d returned=%d\n",
403 protocol_family, stat);
404 }
405
406 return stat;
407 }
408
409 void lo_reg_if_mods()
410 {
411 int error;
412
413 /* Register protocol registration functions */
414 if ((error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
415 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
416
417 if ((error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
418 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
419 }
420
421 static errno_t
422 lo_set_bpf_tap(
423 ifnet_t ifp,
424 bpf_tap_mode mode,
425 bpf_packet_func bpf_callback)
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 */
445 void
446 loopattach(
447 __unused void *dummy)
448 {
449 struct ifnet *ifp;
450 int i = 0;
451
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;
457 bzero(ifp, sizeof(struct ifnet));
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;
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;
468 ifp->if_set_bpf_tap = lo_set_bpf_tap;
469 ifp->if_output = lo_output;
470 ifp->if_type = IFT_LOOP;
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;
474 dlil_if_attach(ifp);
475 #if NBPFILTER > 0
476 bpfattach(ifp, DLT_NULL, sizeof(u_int));
477 #endif
478 }
479 loopattach_done = 1;
480 }