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