]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_loop.c
xnu-792.tar.gz
[apple/xnu.git] / bsd / net / if_loop.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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
55 * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.5 2001/07/03 11:01:41 ume Exp $
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>
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
95 #include <net/dlil.h>
96 #include <net/kpi_protocol.h>
97
98 #if NETAT
99 extern 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
109 struct lo_statics_str {
110 int bpf_mode;
111 bpf_packet_func bpf_callback;
112 };
113
114 void loopattach(void *dummy);
115
116 static struct lo_statics_str lo_statics[NLOOP];
117 int loopattach_done = 0; /* used to sync ip6_init2 loopback configuration */
118
119 #ifdef TINY_LOMTU
120 #define LOMTU (1024+512)
121 #else
122 #define LOMTU 16384
123 #endif
124
125 struct ifnet loif[NLOOP];
126 struct ifnet *lo_ifp = &loif[0];
127
128 struct loopback_header {
129 u_long protocol;
130 };
131
132 void lo_reg_if_mods(void);
133
134 /* Local forward declerations */
135
136 static errno_t
137 lo_demux(
138 __unused ifnet_t ifp,
139 __unused mbuf_t m,
140 char *frame_header,
141 protocol_family_t *protocol_family)
142 {
143 struct loopback_header *header = (struct loopback_header *)frame_header;
144
145 *protocol_family = header->protocol;
146
147 return 0;
148 }
149
150
151 static errno_t
152 lo_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)
158 {
159 struct loopback_header *header;
160
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;
164 return 0;
165 }
166
167 static errno_t
168 lo_add_proto(
169 __unused struct ifnet *ifp,
170 __unused u_long protocol_family,
171 __unused struct ddesc_head_str *demux_desc_head)
172 {
173 return 0;
174 }
175
176
177 static errno_t
178 lo_del_proto(
179 __unused ifnet_t ifp,
180 __unused protocol_family_t protocol)
181 {
182 return 0;
183 }
184
185 static int
186 lo_output(
187 struct ifnet *ifp,
188 struct mbuf *m)
189 {
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;
201
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));
213
214 #if NBPFILTER > 0
215 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
216 struct mbuf m0, *n;
217
218 n = m;
219 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
220 struct loopback_header *header;
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 */
228 header = (struct loopback_header*)m->m_pkthdr.header;
229 m0.m_next = m;
230 m0.m_len = 4;
231 m0.m_data = (char *)&header->protocol;
232 n = &m0;
233 }
234
235 lo_statics[ifp->if_unit].bpf_callback(ifp, n);
236 }
237 #endif
238
239 return dlil_input(ifp, m, m);
240 }
241
242
243 /*
244 * This is a common pre-output route used by INET and INET6. This could
245 * (should?) be split into separate pre-output routines for each protocol.
246 */
247
248 static int
249 lo_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)
257
258 {
259 register struct rtentry *rt = (struct rtentry *) route;
260
261 if (((*m)->m_flags & M_PKTHDR) == 0)
262 panic("looutput no HDR");
263
264 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
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);
271 }
272
273 *(u_long *)frame_type = protocol_family;
274
275 return 0;
276 }
277
278 /*
279 * lo_input - This should work for all attached protocols that use the
280 * ifq/schednetisr input mechanism.
281 */
282 static int
283 lo_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)
289 {
290 if (proto_input(protocol_family, m) != 0)
291 m_freem(m);
292 return (0);
293 }
294
295
296
297
298 /* ARGSUSED */
299 static void
300 lortrequest(
301 __unused int cmd,
302 struct rtentry *rt,
303 __unused struct sockaddr *sa)
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 */
320 static errno_t
321 loioctl(
322 ifnet_t ifp,
323 u_int32_t cmd,
324 void* data)
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:
333 ifnet_set_flags(ifp, IFF_UP | IFF_RUNNING, IFF_UP | IFF_RUNNING);
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;
373 break;
374 }
375 return (error);
376 }
377 #endif /* NLOOP > 0 */
378
379
380 static int lo_attach_proto(struct ifnet *ifp, u_long protocol_family)
381 {
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);
394
395 if (stat && stat != EEXIST) {
396 printf("lo_attach_proto: dlil_attach_protocol for %d returned=%d\n",
397 protocol_family, stat);
398 }
399
400 return stat;
401 }
402
403 void lo_reg_if_mods()
404 {
405 int error;
406
407 /* Register protocol registration functions */
408 if ((error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
409 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
410
411 if ((error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, lo_attach_proto, NULL)) != 0)
412 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
413 }
414
415 static errno_t
416 lo_set_bpf_tap(
417 ifnet_t ifp,
418 bpf_tap_mode mode,
419 bpf_packet_func bpf_callback)
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 */
439 void
440 loopattach(
441 __unused void *dummy)
442 {
443 struct ifnet *ifp;
444 int i = 0;
445
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;
451 bzero(ifp, sizeof(struct ifnet));
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;
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;
462 ifp->if_set_bpf_tap = lo_set_bpf_tap;
463 ifp->if_output = lo_output;
464 ifp->if_type = IFT_LOOP;
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;
468 dlil_if_attach(ifp);
469 #if NBPFILTER > 0
470 bpfattach(ifp, DLT_NULL, sizeof(u_int));
471 #endif
472 }
473 loopattach_done = 1;
474 }