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