]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_loop.c
xnu-517.3.15.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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1982, 1986, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * @(#)if_loop.c 8.1 (Berkeley) 6/10/93
58 * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.5 2001/07/03 11:01:41 ume Exp $
59 */
60
61 /*
62 * Loopback interface driver for protocol testing and timing.
63 */
64 #include "loop.h"
65 #if NLOOP > 0
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/mbuf.h>
71 #include <sys/socket.h>
72 #include <sys/sockio.h>
73
74 #include <net/if.h>
75 #include <net/if_types.h>
76 #include <net/netisr.h>
77 #include <net/route.h>
78 #include <net/bpf.h>
79 #include <sys/malloc.h>
80
81 #if INET
82 #include <netinet/in.h>
83 #include <netinet/in_var.h>
84 #endif
85
86 #if IPX
87 #include <netipx/ipx.h>
88 #include <netipx/ipx_if.h>
89 #endif
90
91 #if INET6
92 #ifndef INET
93 #include <netinet/in.h>
94 #endif
95 #include <netinet6/in6_var.h>
96 #include <netinet/ip6.h>
97 #endif
98
99 #include <net/dlil.h>
100
101 #if NETAT
102 extern struct ifqueue atalkintrq;
103 #endif
104
105 #include "bpfilter.h"
106 #if NBPFILTER > 0
107 #include <net/bpfdesc.h>
108 #endif
109
110 #define NLOOP_ATTACHMENTS (NLOOP * 12)
111
112 struct lo_statics_str {
113 int bpf_mode;
114 int (*bpf_callback)(struct ifnet *, struct mbuf *);
115 };
116
117 static struct if_proto *lo_array[NLOOP_ATTACHMENTS];
118 static struct lo_statics_str lo_statics[NLOOP];
119 static lo_count = 0;
120
121
122 #ifdef TINY_LOMTU
123 #define LOMTU (1024+512)
124 #else
125 #define LOMTU 16384
126 #endif
127
128 struct ifnet loif[NLOOP];
129
130 void lo_reg_if_mods();
131
132
133
134
135 int lo_demux(ifp, m, frame_header, proto)
136 struct ifnet *ifp;
137 struct mbuf *m;
138 char *frame_header;
139 struct if_proto **proto;
140 {
141 int i;
142 struct if_proto **proto_ptr;
143
144 proto_ptr = mtod(m, struct if_proto **);
145 *proto = *proto_ptr;
146 m_adj(m, sizeof(u_long));
147 return 0;
148 }
149
150
151 int lo_framer(ifp, m, dest, dest_linkaddr, frame_type)
152 struct ifnet *ifp;
153 struct mbuf **m;
154 struct sockaddr *dest;
155 char *dest_linkaddr;
156 char *frame_type;
157
158 {
159 char *to_ptr;
160
161 M_PREPEND(*m, (4 * sizeof(u_long)), M_WAITOK);
162 to_ptr = mtod(*m, char *);
163 bcopy(dest_linkaddr, to_ptr, (4 * sizeof(u_long)));
164 return 0;
165 }
166
167 static
168 int lo_add_if(struct ifnet *ifp)
169 {
170 ifp->if_demux = lo_demux;
171 ifp->if_framer = lo_framer;
172 ifp->if_event = 0;
173 return 0;
174 }
175
176 static
177 int lo_del_if(struct ifnet *ifp)
178 {
179 return 0;
180 }
181
182
183
184
185 static
186 int lo_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
187 {
188 int i;
189
190 for (i=0; i < lo_count; i++)
191 if (lo_array[i] == 0) {
192 lo_array[lo_count] = proto;
193 return 0;
194 }
195
196 if ((i == lo_count) && (lo_count == NLOOP_ATTACHMENTS))
197 panic("lo_add_proto -- Too many attachments\n");
198
199 lo_array[lo_count++] = proto;
200 return 0;
201 }
202
203
204 static
205 int lo_del_proto(struct if_proto *proto, u_long dl_tag)
206 {
207 int i;
208
209 for (i=0; i < lo_count; i++)
210 if (lo_array[i] == proto) {
211 lo_array[i] = 0;
212 return 0;
213 }
214
215 return ENOENT;
216 }
217
218 static int
219 lo_output(ifp, m)
220 struct ifnet *ifp;
221 register struct mbuf *m;
222 { u_int *prepend_ptr;
223 u_int af;
224 u_long saved_header[3];
225
226 if ((m->m_flags & M_PKTHDR) == 0)
227 panic("lo_output: no HDR");
228
229 /*
230 * Don't overwrite the rcvif field if it is in use.
231 * This is used to match multicast packets, sent looping
232 * back, with the appropriate group record on input.
233 */
234 if (m->m_pkthdr.rcvif == NULL)
235 m->m_pkthdr.rcvif = ifp;
236 prepend_ptr = mtod(m, u_int *);
237 af = *prepend_ptr;
238 m_adj(m, sizeof(u_int));
239
240
241 #if NBPFILTER > 0
242 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
243 struct mbuf m0, *n;
244
245 bcopy(mtod(m, caddr_t), &saved_header[0], (3 * sizeof(u_long)));
246 m_adj(m, (3 * sizeof(u_long)));
247
248 n = m;
249 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
250 /*
251 * We need to prepend the address family as
252 * a four byte field. Cons up a dummy header
253 * to pacify bpf. This is safe because bpf
254 * will only read from the mbuf (i.e., it won't
255 * try to free it or keep a pointer a to it).
256 */
257 m0.m_next = m;
258 m0.m_len = 4;
259 m0.m_data = (char *)&af;
260 n = &m0;
261 }
262
263 (*lo_statics[ifp->if_unit].bpf_callback)(ifp, n);
264
265 M_PREPEND(m, (3 * sizeof(u_long)), M_WAITOK);
266 bcopy(&saved_header[0], mtod(m, caddr_t), (3 * sizeof(u_long)));
267
268 }
269 #endif
270
271 ifp->if_ibytes += m->m_pkthdr.len;
272 ifp->if_obytes += m->m_pkthdr.len;
273
274 ifp->if_opackets++;
275 ifp->if_ipackets++;
276
277 m->m_pkthdr.header = mtod(m, char *);
278 m->m_pkthdr.csum_data = 0xffff; /* loopback checksums are always OK */
279 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
280 CSUM_IP_CHECKED | CSUM_IP_VALID;
281 return dlil_input(ifp, m, m);
282 }
283
284
285 /*
286 * This is a common pre-output route used by INET, AT, etc. This could
287 * (should?) be split into separate pre-output routines for each protocol.
288 */
289
290 static int
291 lo_pre_output(ifp, m, dst, route, frame_type, dst_addr, dl_tag)
292 struct ifnet *ifp;
293 register struct mbuf **m;
294 struct sockaddr *dst;
295 void *route;
296 char *frame_type;
297 char *dst_addr;
298 u_long dl_tag;
299
300 {
301 int s, isr;
302 register struct ifqueue *ifq = 0;
303 u_long *prepend_ptr;
304 register struct rtentry *rt = (struct rtentry *) route;
305
306 prepend_ptr = (u_long *) dst_addr;
307 if (((*m)->m_flags & M_PKTHDR) == 0)
308 panic("looutput no HDR");
309
310 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
311 if (rt->rt_flags & RTF_BLACKHOLE) {
312 m_freem(*m);
313 return EJUSTRETURN;
314 }
315 else
316 return ((rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH);
317 }
318
319 switch (dst->sa_family) {
320 #if INET
321 case AF_INET:
322 ifq = &ipintrq;
323 isr = NETISR_IP;
324 break;
325 #endif
326 #if INET6
327 case AF_INET6:
328 (*m)->m_flags |= M_LOOP;
329 ifq = &ip6intrq;
330 isr = NETISR_IPV6;
331 break;
332 #endif
333 #if IPX
334 case AF_IPX:
335 ifq = &ipxintrq;
336 isr = NETISR_IPX;
337 break;
338 #endif
339 #if NS
340 case AF_NS:
341 ifq = &nsintrq;
342 isr = NETISR_NS;
343 break;
344 #endif
345 #if ISO
346 case AF_ISO:
347 ifq = &clnlintrq;
348 isr = NETISR_ISO;
349 break;
350 #endif
351 #if NETAT
352 case AF_APPLETALK:
353 ifq = &atalkintrq;
354 isr = NETISR_APPLETALK;
355 break;
356 #endif /* NETAT */
357 default:
358 return (EAFNOSUPPORT);
359 }
360
361 *prepend_ptr++ = dst->sa_family; /* For lo_output(BPF) */
362 *prepend_ptr++ = dlttoproto(dl_tag); /* For lo_demux */
363 *prepend_ptr++ = (u_long) ifq; /* For lo_input */
364 *prepend_ptr = isr; /* For lo_input */
365
366 return 0;
367 }
368
369
370
371
372 /*
373 * lo_input - This should work for all attached protocols that use the
374 * ifq/schednetisr input mechanism.
375 */
376
377
378 int
379 lo_input(m, fh, ifp, dl_tag, sync_ok)
380 register struct mbuf *m;
381 char *fh;
382 struct ifnet *ifp;
383 u_long dl_tag;
384 int sync_ok;
385
386 {
387 u_long *prepend_ptr;
388 int s, isr;
389 register struct ifqueue *ifq = 0;
390
391 prepend_ptr = mtod(m, u_long *);
392 ifq = (struct ifqueue *) *prepend_ptr++;
393 isr = *prepend_ptr;
394 m_adj(m, (2 * sizeof(u_long)));
395
396 s = splimp();
397 if (IF_QFULL(ifq)) {
398 IF_DROP(ifq);
399 m_freem(m);
400 splx(s);
401 return (EJUSTRETURN);
402 }
403
404 IF_ENQUEUE(ifq, m);
405 schednetisr(isr);
406 splx(s);
407 return (0);
408 }
409
410
411
412
413 /* ARGSUSED */
414 static void
415 lortrequest(cmd, rt, sa)
416 int cmd;
417 struct rtentry *rt;
418 struct sockaddr *sa;
419 {
420 if (rt) {
421 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
422 /*
423 * For optimal performance, the send and receive buffers
424 * should be at least twice the MTU plus a little more for
425 * overhead.
426 */
427 rt->rt_rmx.rmx_recvpipe =
428 rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
429 }
430 }
431
432 /*
433 * Process an ioctl request.
434 */
435 static int
436 lo_if_ioctl(struct ifnet *ifp, u_long cmd, void * data)
437 {
438 register struct ifaddr *ifa;
439 register struct ifreq *ifr = (struct ifreq *)data;
440 register int error = 0;
441
442 switch (cmd) {
443
444 case SIOCSIFADDR:
445 ifp->if_flags |= IFF_UP | IFF_RUNNING;
446 ifa = (struct ifaddr *)data;
447 ifa->ifa_rtrequest = lortrequest;
448 /*
449 * Everything else is done at a higher level.
450 */
451 break;
452
453 case SIOCADDMULTI:
454 case SIOCDELMULTI:
455 if (ifr == 0) {
456 error = EAFNOSUPPORT; /* XXX */
457 break;
458 }
459 switch (ifr->ifr_addr.sa_family) {
460
461 #if INET
462 case AF_INET:
463 break;
464 #endif
465 #if INET6
466 case AF_INET6:
467 break;
468 #endif
469
470 default:
471 error = EAFNOSUPPORT;
472 break;
473 }
474 break;
475
476 case SIOCSIFMTU:
477 ifp->if_mtu = ifr->ifr_mtu;
478 break;
479
480 case SIOCSIFFLAGS:
481 break;
482
483 default:
484 error = EOPNOTSUPP;
485 break;
486 }
487 return (error);
488 }
489
490 static int
491 loioctl(u_long dl_tag, struct ifnet *ifp, u_long cmd, caddr_t data)
492 {
493 return (lo_if_ioctl(ifp, cmd, data));
494 }
495
496 #endif /* NLOOP > 0 */
497
498
499 int lo_shutdown()
500 {
501 return 0;
502 }
503
504 int lo_attach_inet(struct ifnet *ifp, u_long *dl_tag)
505 {
506 struct dlil_proto_reg_str reg;
507 struct dlil_demux_desc desc;
508 short native=0;
509 int stat =0 ;
510 int i;
511
512 for (i=0; i < lo_count; i++) {
513 if ((lo_array[i]) && (lo_array[i]->ifp == ifp)) {
514 if (lo_array[i]->protocol_family == PF_INET) {
515 *dl_tag = lo_array[i]->dl_tag;
516 return (0);
517 }
518 }
519 }
520
521 TAILQ_INIT(&reg.demux_desc_head);
522 desc.type = DLIL_DESC_RAW;
523 desc.variants.bitmask.proto_id_length = 0;
524 desc.variants.bitmask.proto_id = 0;
525 desc.variants.bitmask.proto_id_mask = 0;
526 desc.native_type = (char *) &native;
527 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
528 reg.interface_family = ifp->if_family;
529 reg.unit_number = ifp->if_unit;
530 reg.input = lo_input;
531 reg.pre_output = lo_pre_output;
532 reg.event = 0;
533 reg.offer = 0;
534 reg.ioctl = loioctl;
535 reg.default_proto = 0;
536 reg.protocol_family = PF_INET;
537
538 stat = dlil_attach_protocol(&reg, dl_tag);
539
540 if (stat)
541 printf("lo_attach_inet: dlil_attach_protocol returned=%d\n", stat);
542
543 return stat;
544 }
545
546 int lo_attach_inet6(struct ifnet *ifp, u_long *dl_tag)
547 {
548 struct dlil_proto_reg_str reg;
549 struct dlil_demux_desc desc;
550 short native=0;
551 int stat;
552 int i;
553
554 for (i=0; i < lo_count; i++) {
555 if ((lo_array[i]) && (lo_array[i]->ifp == ifp)) {
556 if (lo_array[i]->protocol_family == PF_INET6) {
557 *dl_tag = lo_array[i]->dl_tag;
558 return (0);
559 }
560 }
561 }
562
563 TAILQ_INIT(&reg.demux_desc_head);
564 desc.type = DLIL_DESC_RAW;
565 desc.variants.bitmask.proto_id_length = 0;
566 desc.variants.bitmask.proto_id = 0;
567 desc.variants.bitmask.proto_id_mask = 0;
568 desc.native_type = (char *) &native;
569 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
570 reg.interface_family = ifp->if_family;
571 reg.unit_number = ifp->if_unit;
572 reg.input = lo_input;
573 reg.pre_output = lo_pre_output;
574 reg.event = 0;
575 reg.offer = 0;
576 reg.ioctl = loioctl;
577 reg.default_proto = 0;
578 reg.protocol_family = PF_INET6;
579
580 stat = dlil_attach_protocol(&reg, dl_tag);
581
582 if (stat)
583 printf("lo_attach_inet6: dlil_attach_protocol returned=%d\n", stat);
584
585 return stat;
586 }
587
588 void lo_reg_if_mods()
589 {
590 struct dlil_ifmod_reg_str lo_ifmod;
591 struct dlil_protomod_reg_str lo_protoreg;
592 int error;
593
594 bzero(&lo_ifmod, sizeof(lo_ifmod));
595 lo_ifmod.add_if = lo_add_if;
596 lo_ifmod.del_if = lo_del_if;
597 lo_ifmod.add_proto = lo_add_proto;
598 lo_ifmod.del_proto = lo_del_proto;
599 lo_ifmod.ifmod_ioctl = 0;
600 lo_ifmod.shutdown = lo_shutdown;
601
602 if (dlil_reg_if_modules(APPLE_IF_FAM_LOOPBACK, &lo_ifmod))
603 panic("Couldn't register lo modules\n");
604
605 /* Register protocol registration functions */
606
607 bzero(&lo_protoreg, sizeof(lo_protoreg));
608 lo_protoreg.attach_proto = lo_attach_inet;
609 lo_protoreg.detach_proto = NULL; /* no detach function for loopback */
610
611 if ( error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, &lo_protoreg) != 0)
612 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
613
614 lo_protoreg.attach_proto = lo_attach_inet6;
615 lo_protoreg.detach_proto = NULL;
616
617 if ( error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, &lo_protoreg) != 0)
618 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
619
620 }
621
622 int lo_set_bpf_tap(struct ifnet *ifp, int mode, int (*bpf_callback)(struct ifnet *, struct mbuf *))
623 {
624
625 /*
626 * NEED MUTEX HERE XXX
627 */
628 if (mode == BPF_TAP_DISABLE) {
629 lo_statics[ifp->if_unit].bpf_mode = mode;
630 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
631 }
632 else {
633 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
634 lo_statics[ifp->if_unit].bpf_mode = mode;
635 }
636
637 return 0;
638 }
639
640
641 /* ARGSUSED */
642 void
643 loopattach(dummy)
644 void *dummy;
645 {
646 register struct ifnet *ifp;
647 register int i = 0;
648
649 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
650 lo_reg_if_mods();
651
652 for (ifp = loif; i < NLOOP; ifp++) {
653 lo_statics[i].bpf_callback = 0;
654 lo_statics[i].bpf_mode = BPF_TAP_DISABLE;
655 ifp->if_name = "lo";
656 ifp->if_family = APPLE_IF_FAM_LOOPBACK;
657 ifp->if_unit = i++;
658 ifp->if_mtu = LOMTU;
659 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
660 ifp->if_ioctl = lo_if_ioctl;
661 ifp->if_set_bpf_tap = lo_set_bpf_tap;
662 ifp->if_output = lo_output;
663 ifp->if_type = IFT_LOOP;
664 ifp->if_hwassist = 0; /* HW cksum on send side breaks Classic loopback */
665 dlil_if_attach(ifp);
666 #if NBPFILTER > 0
667 bpfattach(ifp, DLT_NULL, sizeof(u_int));
668 #endif
669 }
670 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
671 }