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