]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/net/if_faith.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / net / if_faith.c
... / ...
CommitLineData
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/* $KAME: if_faith.c,v 1.21 2001/02/20 07:59:26 itojun Exp $ */
26
27/*
28 * Copyright (c) 1982, 1986, 1993
29 * The Regents of the University of California. All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * $FreeBSD: src/sys/net/if_faith.c,v 1.3.2.2 2001/07/05 14:46:25 ume Exp $
60 */
61/*
62 * derived from
63 * @(#)if_loop.c 8.1 (Berkeley) 6/10/93
64 * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp
65 */
66
67/*
68 * Loopback interface driver for protocol testing and timing.
69 */
70
71#include "faith.h"
72#if NFAITH > 0
73
74#include <sys/param.h>
75#include <sys/systm.h>
76#include <sys/kernel.h>
77#include <sys/mbuf.h>
78#include <sys/socket.h>
79#include <sys/errno.h>
80#include <sys/sockio.h>
81#include <sys/time.h>
82#include <sys/queue.h>
83
84#include <net/if.h>
85#include <net/if_types.h>
86#include <net/netisr.h>
87#include <net/route.h>
88#include <net/bpf.h>
89#include <net/if_faith.h>
90
91#if INET
92#include <netinet/in.h>
93#include <netinet/in_systm.h>
94#include <netinet/in_var.h>
95#include <netinet/ip.h>
96#endif
97
98#if INET6
99#ifndef INET
100#include <netinet/in.h>
101#endif
102#include <netinet6/in6_var.h>
103#include <netinet/ip6.h>
104#include <netinet6/ip6_var.h>
105#endif
106
107#include <net/dlil.h>
108#include "bpf.h"
109
110#include <net/net_osdep.h>
111
112static int faithioctl __P((struct ifnet *, u_long, void*));
113int faith_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *,
114 caddr_t, char *, char *, u_long));
115static void faithrtrequest __P((int, struct rtentry *, struct sockaddr *));
116
117void faithattach __P((void));
118#ifndef __APPLE__
119PSEUDO_SET(faithattach, if_faith);
120#endif
121
122static struct ifnet faithif[NFAITH];
123static struct if_proto *faith_array[NFAITH];
124static int faith_count = 0;
125
126#define FAITHMTU 1500
127
128static
129int faith_add_if(struct ifnet *ifp)
130{
131 ifp->if_demux = 0;
132 ifp->if_framer = 0;
133 return 0;
134}
135
136static
137int faith_del_if(struct ifnet *ifp)
138{
139 return 0;
140}
141
142static
143int faith_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
144{
145 int i;
146
147 for (i=0; i < faith_count; i++)
148 if (faith_array[i] == 0) {
149 faith_array[faith_count] = proto;
150 return 0;
151 }
152
153 if ((i == faith_count) && (faith_count == NFAITH))
154 panic("faith_add_proto -- Too many attachments\n");
155
156 faith_array[faith_count++] = proto;
157
158 return (0);
159}
160
161static
162int faith_del_proto(struct if_proto *proto, u_long dl_tag)
163{
164 int i;
165
166
167 for (i=0; i < faith_count; i++)
168 if (faith_array[i] == proto) {
169 faith_array[i] = 0;
170 return 0;
171 }
172
173 return ENOENT;
174}
175
176int faith_shutdown()
177{
178 return 0;
179}
180
181int faith_attach_inet(struct ifnet *ifp, u_long *dl_tag)
182{
183 struct dlil_proto_reg_str reg;
184 struct dlil_demux_desc desc;
185 short native=0;
186 int stat;
187 int i;
188
189 for (i=0; i < faith_count; i++) {
190 if (faith_array[i] && (faith_array[i]->ifp == ifp) &&
191 (faith_array[i]->protocol_family == PF_INET)) {
192#if 0
193 kprintf("faith_array for %s%d found dl_tag=%d\n",
194 ifp->if_name, ifp->if_unit, faith_array[i]->dl_tag);
195#endif
196 *dl_tag = faith_array[i]->dl_tag;
197 return 0;
198
199 }
200 }
201
202 TAILQ_INIT(&reg.demux_desc_head);
203 desc.type = DLIL_DESC_RAW;
204 desc.variants.bitmask.proto_id_length = 0;
205 desc.variants.bitmask.proto_id = 0;
206 desc.variants.bitmask.proto_id_mask = 0;
207 desc.native_type = (char *) &native;
208 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
209 reg.interface_family = ifp->if_family;
210 reg.unit_number = ifp->if_unit;
211 reg.input = 0;
212 reg.pre_output = faith_pre_output;
213 reg.event = 0;
214 reg.offer = 0;
215 reg.ioctl = 0;
216 reg.default_proto = 0;
217 reg.protocol_family = PF_INET;
218
219 stat = dlil_attach_protocol(&reg, dl_tag);
220 if (stat) {
221 panic("faith_attach_inet can't attach interface\n");
222 }
223
224 return stat;
225}
226
227void faith_reg_if_mods()
228{
229 struct dlil_ifmod_reg_str faith_ifmod;
230 struct dlil_protomod_reg_str faith_protoreg;
231 int error;
232
233 bzero(&faith_ifmod, sizeof(faith_ifmod));
234 faith_ifmod.add_if = faith_add_if;
235 faith_ifmod.del_if = faith_del_if;
236 faith_ifmod.add_proto = faith_add_proto;
237 faith_ifmod.del_proto = faith_del_proto;
238 faith_ifmod.ifmod_ioctl = 0;
239 faith_ifmod.shutdown = faith_shutdown;
240
241
242 if (dlil_reg_if_modules(APPLE_IF_FAM_FAITH, &faith_ifmod))
243 panic("Couldn't register faith modules\n");
244
245 /* Register protocol registration functions */
246
247 bzero(&faith_protoreg, sizeof(faith_protoreg));
248 faith_protoreg.attach_proto = faith_attach_inet;
249 faith_protoreg.detach_proto = 0;
250
251 if ( error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_FAITH, &faith_protoreg) != 0)
252 kprintf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
253
254
255}
256
257void
258faithattach(void)
259{
260 struct ifnet *ifp;
261 int i;
262
263 faith_reg_if_mods(); /* DLIL modules */
264
265 for (i = 0; i < NFAITH; i++) {
266 ifp = &faithif[i];
267 bzero(ifp, sizeof(faithif[i]));
268 ifp->if_name = "faith";
269 ifp->if_unit = i;
270 ifp->if_family = APPLE_IF_FAM_FAITH;
271 ifp->if_mtu = FAITHMTU;
272 /* LOOPBACK commented out to announce IPv6 routes to faith */
273 ifp->if_flags = /* IFF_LOOPBACK | */ IFF_MULTICAST;
274 ifp->if_ioctl = faithioctl;
275 ifp->if_output = NULL;
276 ifp->if_type = IFT_FAITH;
277 ifp->if_hdrlen = 0;
278 ifp->if_addrlen = 0;
279 dlil_if_attach(ifp);
280#if NBPFILTER > 0
281#ifdef HAVE_OLD_BPF
282 bpfattach(ifp, DLT_NULL, sizeof(u_int));
283#else
284 bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
285#endif
286#endif
287 }
288}
289
290int
291faith_pre_output(ifp, m0, dst, route_entry, frame_type, dst_addr, dl_tag)
292 struct ifnet *ifp;
293 register struct mbuf **m0;
294 struct sockaddr *dst;
295 caddr_t route_entry;
296 char *frame_type;
297 char *dst_addr;
298 u_long dl_tag;
299{
300 int s, isr;
301 register struct ifqueue *ifq = 0;
302 register struct mbuf *m = *m0;
303 struct rtentry *rt = (struct rtentry*)route_entry;
304
305 if ((m->m_flags & M_PKTHDR) == 0)
306 panic("faithoutput no HDR");
307#if NBPFILTER > 0
308 /* BPF write needs to be handled specially */
309 if (dst && dst->sa_family == AF_UNSPEC) {
310 dst->sa_family = *(mtod(m, int *));
311 m->m_len -= sizeof(int);
312 m->m_pkthdr.len -= sizeof(int);
313 m->m_data += sizeof(int);
314 }
315
316 if (ifp->if_bpf) {
317 /*
318 * We need to prepend the address family as
319 * a four byte field. Cons up a faith header
320 * to pacify bpf. This is safe because bpf
321 * will only read from the mbuf (i.e., it won't
322 * try to free it or keep a pointer a to it).
323 */
324 struct mbuf m0;
325 u_int32_t af = dst->sa_family;
326
327 m0.m_next = m;
328 m0.m_len = 4;
329 m0.m_data = (char *)&af;
330
331#ifdef HAVE_OLD_BPF
332 bpf_mtap(ifp, &m0);
333#else
334 bpf_mtap(ifp->if_bpf, &m0);
335#endif
336 }
337#endif
338
339 if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
340 return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
341 rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
342 }
343 ifp->if_opackets++;
344 ifp->if_obytes += m->m_pkthdr.len;
345 switch (dst->sa_family) {
346#if INET
347 case AF_INET:
348 ifq = &ipintrq;
349 isr = NETISR_IP;
350 break;
351#endif
352#if INET6
353 case AF_INET6:
354 ifq = &ip6intrq;
355 isr = NETISR_IPV6;
356 break;
357#endif
358 default:
359 return EAFNOSUPPORT;
360 }
361
362 /* XXX do we need more sanity checks? */
363
364 m->m_pkthdr.rcvif = ifp;
365 s = splimp();
366 if (IF_QFULL(ifq)) {
367 IF_DROP(ifq);
368 splx(s);
369 return (ENOBUFS);
370 }
371 IF_ENQUEUE(ifq, m);
372 schednetisr(isr);
373 ifp->if_ipackets++;
374 ifp->if_ibytes += m->m_pkthdr.len;
375 splx(s);
376 return (EJUSTRETURN);
377}
378
379/* ARGSUSED */
380static void
381faithrtrequest(cmd, rt, sa)
382 int cmd;
383 struct rtentry *rt;
384 struct sockaddr *sa;
385{
386 if (rt) {
387 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
388 /*
389 * For optimal performance, the send and receive buffers
390 * should be at least twice the MTU plus a little more for
391 * overhead.
392 */
393 rt->rt_rmx.rmx_recvpipe =
394 rt->rt_rmx.rmx_sendpipe = 3 * FAITHMTU;
395 }
396}
397
398/*
399 * Process an ioctl request.
400 */
401/* ARGSUSED */
402static int
403faithioctl(ifp, cmd, data)
404 struct ifnet *ifp;
405 u_long cmd;
406 void* data;
407{
408 struct ifaddr *ifa;
409 struct ifreq *ifr = (struct ifreq *)data;
410 int error = 0;
411
412 switch (cmd) {
413
414 case SIOCSIFADDR:
415 ifp->if_flags |= IFF_UP | IFF_RUNNING;
416 ifa = (struct ifaddr *)data;
417 ifa->ifa_rtrequest = faithrtrequest;
418 /*
419 * Everything else is done at a higher level.
420 */
421 break;
422
423 case SIOCADDMULTI:
424 case SIOCDELMULTI:
425 if (ifr == 0) {
426 error = EAFNOSUPPORT; /* XXX */
427 break;
428 }
429 switch (ifr->ifr_addr.sa_family) {
430#if INET
431 case AF_INET:
432 break;
433#endif
434#if INET6
435 case AF_INET6:
436 break;
437#endif
438
439 default:
440 error = EAFNOSUPPORT;
441 break;
442 }
443 break;
444
445#ifdef SIOCSIFMTU
446 case SIOCSIFMTU:
447 ifp->if_mtu = ifr->ifr_mtu;
448 break;
449#endif
450
451 case SIOCSIFFLAGS:
452 break;
453
454 default:
455 error = EINVAL;
456 }
457 return (error);
458}
459
460#if INET6
461/*
462 * XXX could be slow
463 * XXX could be layer violation to call sys/net from sys/netinet6
464 */
465int
466faithprefix(in6)
467 struct in6_addr *in6;
468{
469 struct rtentry *rt;
470 struct sockaddr_in6 sin6;
471 int ret;
472
473 if (ip6_keepfaith == 0)
474 return 0;
475
476 bzero(&sin6, sizeof(sin6));
477 sin6.sin6_family = AF_INET6;
478 sin6.sin6_len = sizeof(struct sockaddr_in6);
479 sin6.sin6_addr = *in6;
480 rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
481 if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
482 (rt->rt_ifp->if_flags & IFF_UP) != 0)
483 ret = 1;
484 else
485 ret = 0;
486 if (rt)
487 rtfree(rt);
488 return ret;
489}
490#endif
491#endif /* NFAITH > 0 */