]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_loop.c
xnu-517.9.4.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/netisr.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
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 int (*bpf_callback)(struct ifnet *, struct mbuf *);
112 };
113
114 static struct if_proto *lo_array[NLOOP_ATTACHMENTS];
115 static struct lo_statics_str lo_statics[NLOOP];
116 static lo_count = 0;
117
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
127 void lo_reg_if_mods();
128
129
130
131
132 int lo_demux(ifp, m, frame_header, proto)
133 struct ifnet *ifp;
134 struct mbuf *m;
135 char *frame_header;
136 struct if_proto **proto;
137 {
138 int i;
139 struct if_proto **proto_ptr;
140
141 proto_ptr = mtod(m, struct if_proto **);
142 *proto = *proto_ptr;
143 m_adj(m, sizeof(u_long));
144 return 0;
145 }
146
147
148 int lo_framer(ifp, m, dest, dest_linkaddr, frame_type)
149 struct ifnet *ifp;
150 struct mbuf **m;
151 struct sockaddr *dest;
152 char *dest_linkaddr;
153 char *frame_type;
154
155 {
156 char *to_ptr;
157
158 M_PREPEND(*m, (4 * sizeof(u_long)), M_WAITOK);
159 to_ptr = mtod(*m, char *);
160 bcopy(dest_linkaddr, to_ptr, (4 * sizeof(u_long)));
161 return 0;
162 }
163
164 static
165 int lo_add_if(struct ifnet *ifp)
166 {
167 ifp->if_demux = lo_demux;
168 ifp->if_framer = lo_framer;
169 ifp->if_event = 0;
170 return 0;
171 }
172
173 static
174 int lo_del_if(struct ifnet *ifp)
175 {
176 return 0;
177 }
178
179
180
181
182 static
183 int lo_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
184 {
185 int i;
186
187 for (i=0; i < lo_count; i++)
188 if (lo_array[i] == 0) {
189 lo_array[lo_count] = proto;
190 return 0;
191 }
192
193 if ((i == lo_count) && (lo_count == NLOOP_ATTACHMENTS))
194 panic("lo_add_proto -- Too many attachments\n");
195
196 lo_array[lo_count++] = proto;
197 return 0;
198 }
199
200
201 static
202 int lo_del_proto(struct if_proto *proto, u_long dl_tag)
203 {
204 int i;
205
206 for (i=0; i < lo_count; i++)
207 if (lo_array[i] == proto) {
208 lo_array[i] = 0;
209 return 0;
210 }
211
212 return ENOENT;
213 }
214
215 static int
216 lo_output(ifp, m)
217 struct ifnet *ifp;
218 register struct mbuf *m;
219 { u_int *prepend_ptr;
220 u_int af;
221 u_long saved_header[3];
222
223 if ((m->m_flags & M_PKTHDR) == 0)
224 panic("lo_output: no HDR");
225
226 /*
227 * Don't overwrite the rcvif field if it is in use.
228 * This is used to match multicast packets, sent looping
229 * back, with the appropriate group record on input.
230 */
231 if (m->m_pkthdr.rcvif == NULL)
232 m->m_pkthdr.rcvif = ifp;
233 prepend_ptr = mtod(m, u_int *);
234 af = *prepend_ptr;
235 m_adj(m, sizeof(u_int));
236
237
238 #if NBPFILTER > 0
239 if (lo_statics[ifp->if_unit].bpf_mode != BPF_TAP_DISABLE) {
240 struct mbuf m0, *n;
241
242 bcopy(mtod(m, caddr_t), &saved_header[0], (3 * sizeof(u_long)));
243 m_adj(m, (3 * sizeof(u_long)));
244
245 n = m;
246 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
247 /*
248 * We need to prepend the address family as
249 * a four byte field. Cons up a dummy header
250 * to pacify bpf. This is safe because bpf
251 * will only read from the mbuf (i.e., it won't
252 * try to free it or keep a pointer a to it).
253 */
254 m0.m_next = m;
255 m0.m_len = 4;
256 m0.m_data = (char *)&af;
257 n = &m0;
258 }
259
260 (*lo_statics[ifp->if_unit].bpf_callback)(ifp, n);
261
262 M_PREPEND(m, (3 * sizeof(u_long)), M_WAITOK);
263 bcopy(&saved_header[0], mtod(m, caddr_t), (3 * sizeof(u_long)));
264
265 }
266 #endif
267
268 ifp->if_ibytes += m->m_pkthdr.len;
269 ifp->if_obytes += m->m_pkthdr.len;
270
271 ifp->if_opackets++;
272 ifp->if_ipackets++;
273
274 m->m_pkthdr.header = mtod(m, char *);
275 m->m_pkthdr.csum_data = 0xffff; /* loopback checksums are always OK */
276 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR |
277 CSUM_IP_CHECKED | CSUM_IP_VALID;
278 return dlil_input(ifp, m, m);
279 }
280
281
282 /*
283 * This is a common pre-output route used by INET, AT, etc. This could
284 * (should?) be split into separate pre-output routines for each protocol.
285 */
286
287 static int
288 lo_pre_output(ifp, m, dst, route, frame_type, dst_addr, dl_tag)
289 struct ifnet *ifp;
290 register struct mbuf **m;
291 struct sockaddr *dst;
292 void *route;
293 char *frame_type;
294 char *dst_addr;
295 u_long dl_tag;
296
297 {
298 int s, isr;
299 register struct ifqueue *ifq = 0;
300 u_long *prepend_ptr;
301 register struct rtentry *rt = (struct rtentry *) route;
302
303 prepend_ptr = (u_long *) dst_addr;
304 if (((*m)->m_flags & M_PKTHDR) == 0)
305 panic("looutput no HDR");
306
307 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
308 if (rt->rt_flags & RTF_BLACKHOLE) {
309 m_freem(*m);
310 return EJUSTRETURN;
311 }
312 else
313 return ((rt->rt_flags & RTF_HOST) ? EHOSTUNREACH : ENETUNREACH);
314 }
315
316 switch (dst->sa_family) {
317 #if INET
318 case AF_INET:
319 ifq = &ipintrq;
320 isr = NETISR_IP;
321 break;
322 #endif
323 #if INET6
324 case AF_INET6:
325 (*m)->m_flags |= M_LOOP;
326 ifq = &ip6intrq;
327 isr = NETISR_IPV6;
328 break;
329 #endif
330 #if IPX
331 case AF_IPX:
332 ifq = &ipxintrq;
333 isr = NETISR_IPX;
334 break;
335 #endif
336 #if NS
337 case AF_NS:
338 ifq = &nsintrq;
339 isr = NETISR_NS;
340 break;
341 #endif
342 #if ISO
343 case AF_ISO:
344 ifq = &clnlintrq;
345 isr = NETISR_ISO;
346 break;
347 #endif
348 #if NETAT
349 case AF_APPLETALK:
350 ifq = &atalkintrq;
351 isr = NETISR_APPLETALK;
352 break;
353 #endif /* NETAT */
354 default:
355 return (EAFNOSUPPORT);
356 }
357
358 *prepend_ptr++ = dst->sa_family; /* For lo_output(BPF) */
359 *prepend_ptr++ = dlttoproto(dl_tag); /* For lo_demux */
360 *prepend_ptr++ = (u_long) ifq; /* For lo_input */
361 *prepend_ptr = isr; /* For lo_input */
362
363 return 0;
364 }
365
366
367
368
369 /*
370 * lo_input - This should work for all attached protocols that use the
371 * ifq/schednetisr input mechanism.
372 */
373
374
375 int
376 lo_input(m, fh, ifp, dl_tag, sync_ok)
377 register struct mbuf *m;
378 char *fh;
379 struct ifnet *ifp;
380 u_long dl_tag;
381 int sync_ok;
382
383 {
384 u_long *prepend_ptr;
385 int s, isr;
386 register struct ifqueue *ifq = 0;
387
388 prepend_ptr = mtod(m, u_long *);
389 ifq = (struct ifqueue *) *prepend_ptr++;
390 isr = *prepend_ptr;
391 m_adj(m, (2 * sizeof(u_long)));
392
393 s = splimp();
394 if (IF_QFULL(ifq)) {
395 IF_DROP(ifq);
396 m_freem(m);
397 splx(s);
398 return (EJUSTRETURN);
399 }
400
401 IF_ENQUEUE(ifq, m);
402 schednetisr(isr);
403 splx(s);
404 return (0);
405 }
406
407
408
409
410 /* ARGSUSED */
411 static void
412 lortrequest(cmd, rt, sa)
413 int cmd;
414 struct rtentry *rt;
415 struct sockaddr *sa;
416 {
417 if (rt) {
418 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
419 /*
420 * For optimal performance, the send and receive buffers
421 * should be at least twice the MTU plus a little more for
422 * overhead.
423 */
424 rt->rt_rmx.rmx_recvpipe =
425 rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
426 }
427 }
428
429 /*
430 * Process an ioctl request.
431 */
432 static int
433 lo_if_ioctl(struct ifnet *ifp, u_long cmd, void * data)
434 {
435 register struct ifaddr *ifa;
436 register struct ifreq *ifr = (struct ifreq *)data;
437 register int error = 0;
438
439 switch (cmd) {
440
441 case SIOCSIFADDR:
442 ifp->if_flags |= IFF_UP | IFF_RUNNING;
443 ifa = (struct ifaddr *)data;
444 ifa->ifa_rtrequest = lortrequest;
445 /*
446 * Everything else is done at a higher level.
447 */
448 break;
449
450 case SIOCADDMULTI:
451 case SIOCDELMULTI:
452 if (ifr == 0) {
453 error = EAFNOSUPPORT; /* XXX */
454 break;
455 }
456 switch (ifr->ifr_addr.sa_family) {
457
458 #if INET
459 case AF_INET:
460 break;
461 #endif
462 #if INET6
463 case AF_INET6:
464 break;
465 #endif
466
467 default:
468 error = EAFNOSUPPORT;
469 break;
470 }
471 break;
472
473 case SIOCSIFMTU:
474 ifp->if_mtu = ifr->ifr_mtu;
475 break;
476
477 case SIOCSIFFLAGS:
478 break;
479
480 default:
481 error = EOPNOTSUPP;
482 break;
483 }
484 return (error);
485 }
486
487 static int
488 loioctl(u_long dl_tag, struct ifnet *ifp, u_long cmd, caddr_t data)
489 {
490 return (lo_if_ioctl(ifp, cmd, data));
491 }
492
493 #endif /* NLOOP > 0 */
494
495
496 int lo_shutdown()
497 {
498 return 0;
499 }
500
501 int lo_attach_inet(struct ifnet *ifp, u_long *dl_tag)
502 {
503 struct dlil_proto_reg_str reg;
504 struct dlil_demux_desc desc;
505 short native=0;
506 int stat =0 ;
507 int i;
508
509 for (i=0; i < lo_count; i++) {
510 if ((lo_array[i]) && (lo_array[i]->ifp == ifp)) {
511 if (lo_array[i]->protocol_family == PF_INET) {
512 *dl_tag = lo_array[i]->dl_tag;
513 return (0);
514 }
515 }
516 }
517
518 TAILQ_INIT(&reg.demux_desc_head);
519 desc.type = DLIL_DESC_RAW;
520 desc.variants.bitmask.proto_id_length = 0;
521 desc.variants.bitmask.proto_id = 0;
522 desc.variants.bitmask.proto_id_mask = 0;
523 desc.native_type = (char *) &native;
524 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
525 reg.interface_family = ifp->if_family;
526 reg.unit_number = ifp->if_unit;
527 reg.input = lo_input;
528 reg.pre_output = lo_pre_output;
529 reg.event = 0;
530 reg.offer = 0;
531 reg.ioctl = loioctl;
532 reg.default_proto = 0;
533 reg.protocol_family = PF_INET;
534
535 stat = dlil_attach_protocol(&reg, dl_tag);
536
537 if (stat)
538 printf("lo_attach_inet: dlil_attach_protocol returned=%d\n", stat);
539
540 return stat;
541 }
542
543 int lo_attach_inet6(struct ifnet *ifp, u_long *dl_tag)
544 {
545 struct dlil_proto_reg_str reg;
546 struct dlil_demux_desc desc;
547 short native=0;
548 int stat;
549 int i;
550
551 for (i=0; i < lo_count; i++) {
552 if ((lo_array[i]) && (lo_array[i]->ifp == ifp)) {
553 if (lo_array[i]->protocol_family == PF_INET6) {
554 *dl_tag = lo_array[i]->dl_tag;
555 return (0);
556 }
557 }
558 }
559
560 TAILQ_INIT(&reg.demux_desc_head);
561 desc.type = DLIL_DESC_RAW;
562 desc.variants.bitmask.proto_id_length = 0;
563 desc.variants.bitmask.proto_id = 0;
564 desc.variants.bitmask.proto_id_mask = 0;
565 desc.native_type = (char *) &native;
566 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
567 reg.interface_family = ifp->if_family;
568 reg.unit_number = ifp->if_unit;
569 reg.input = lo_input;
570 reg.pre_output = lo_pre_output;
571 reg.event = 0;
572 reg.offer = 0;
573 reg.ioctl = loioctl;
574 reg.default_proto = 0;
575 reg.protocol_family = PF_INET6;
576
577 stat = dlil_attach_protocol(&reg, dl_tag);
578
579 if (stat)
580 printf("lo_attach_inet6: dlil_attach_protocol returned=%d\n", stat);
581
582 return stat;
583 }
584
585 void lo_reg_if_mods()
586 {
587 struct dlil_ifmod_reg_str lo_ifmod;
588 struct dlil_protomod_reg_str lo_protoreg;
589 int error;
590
591 bzero(&lo_ifmod, sizeof(lo_ifmod));
592 lo_ifmod.add_if = lo_add_if;
593 lo_ifmod.del_if = lo_del_if;
594 lo_ifmod.add_proto = lo_add_proto;
595 lo_ifmod.del_proto = lo_del_proto;
596 lo_ifmod.ifmod_ioctl = 0;
597 lo_ifmod.shutdown = lo_shutdown;
598
599 if (dlil_reg_if_modules(APPLE_IF_FAM_LOOPBACK, &lo_ifmod))
600 panic("Couldn't register lo modules\n");
601
602 /* Register protocol registration functions */
603
604 bzero(&lo_protoreg, sizeof(lo_protoreg));
605 lo_protoreg.attach_proto = lo_attach_inet;
606 lo_protoreg.detach_proto = NULL; /* no detach function for loopback */
607
608 if ( error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_LOOPBACK, &lo_protoreg) != 0)
609 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
610
611 lo_protoreg.attach_proto = lo_attach_inet6;
612 lo_protoreg.detach_proto = NULL;
613
614 if ( error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_LOOPBACK, &lo_protoreg) != 0)
615 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
616
617 }
618
619 int lo_set_bpf_tap(struct ifnet *ifp, int mode, int (*bpf_callback)(struct ifnet *, struct mbuf *))
620 {
621
622 /*
623 * NEED MUTEX HERE XXX
624 */
625 if (mode == BPF_TAP_DISABLE) {
626 lo_statics[ifp->if_unit].bpf_mode = mode;
627 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
628 }
629 else {
630 lo_statics[ifp->if_unit].bpf_callback = bpf_callback;
631 lo_statics[ifp->if_unit].bpf_mode = mode;
632 }
633
634 return 0;
635 }
636
637
638 /* ARGSUSED */
639 void
640 loopattach(dummy)
641 void *dummy;
642 {
643 register struct ifnet *ifp;
644 register int i = 0;
645
646 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
647 lo_reg_if_mods();
648
649 for (ifp = loif; i < NLOOP; ifp++) {
650 lo_statics[i].bpf_callback = 0;
651 lo_statics[i].bpf_mode = BPF_TAP_DISABLE;
652 ifp->if_name = "lo";
653 ifp->if_family = APPLE_IF_FAM_LOOPBACK;
654 ifp->if_unit = i++;
655 ifp->if_mtu = LOMTU;
656 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
657 ifp->if_ioctl = lo_if_ioctl;
658 ifp->if_set_bpf_tap = lo_set_bpf_tap;
659 ifp->if_output = lo_output;
660 ifp->if_type = IFT_LOOP;
661 ifp->if_hwassist = 0; /* HW cksum on send side breaks Classic loopback */
662 dlil_if_attach(ifp);
663 #if NBPFILTER > 0
664 bpfattach(ifp, DLT_NULL, sizeof(u_int));
665 #endif
666 }
667 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
668 }