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