]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_gif.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / net / if_gif.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
9bccf70c
A
25/* $FreeBSD: src/sys/net/if_gif.c,v 1.4.2.6 2001/07/24 19:10:18 brooks Exp $ */
26/* $KAME: if_gif.c,v 1.47 2001/05/01 05:28:42 itojun Exp $ */
1c79356b
A
27
28/*
29 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
55 */
56
1c79356b
A
57#include <sys/param.h>
58#include <sys/systm.h>
59#include <sys/kernel.h>
60#include <sys/malloc.h>
61#include <sys/mbuf.h>
62#include <sys/socket.h>
63#include <sys/sockio.h>
64#include <sys/errno.h>
65#include <sys/time.h>
66#include <sys/syslog.h>
9bccf70c 67#include <sys/protosw.h>
1c79356b
A
68#include <kern/cpu_number.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
1c79356b
A
76#include <netinet/in.h>
77#include <netinet/in_systm.h>
1c79356b 78#include <netinet/ip.h>
9bccf70c
A
79#if INET
80#include <netinet/in_var.h>
1c79356b 81#include <netinet/in_gif.h>
9bccf70c 82#include <netinet/ip_var.h>
1c79356b
A
83#endif /* INET */
84
85#if INET6
1c79356b
A
86#include <netinet6/in6_var.h>
87#include <netinet/ip6.h>
88#include <netinet6/ip6_var.h>
89#include <netinet6/in6_gif.h>
90#include <netinet6/ip6protosw.h>
91#endif /* INET6 */
92
93#include <netinet/ip_encap.h>
94#include <net/dlil.h>
95#include <net/if_gif.h>
96
1c79356b
A
97#include <net/net_osdep.h>
98
9bccf70c
A
99#define GIFNAME "gif"
100#define GIFDEV "if_gif"
101#define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */
1c79356b 102
9bccf70c
A
103#ifndef __APPLE__
104static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
105#endif
106
107TAILQ_HEAD(gifhead, gif_softc) gifs = TAILQ_HEAD_INITIALIZER(gifs);
108
109#ifdef __APPLE__
110void gifattach __P((void));
1c79356b 111int gif_pre_output __P((struct ifnet *, register struct mbuf **, struct sockaddr *,
9bccf70c
A
112 caddr_t, char *, char *, u_long));
113static void gif_create_dev(void);
114static int gif_encapcheck(const struct mbuf*, int, int, void*);
115
116
117int ngif = 0; /* number of interfaces */
118#endif
119
120#if INET
121struct protosw in_gif_protosw =
122{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
123 in_gif_input, 0, 0, 0,
124 0,
125 0, 0, 0, 0,
126 0,
127 &rip_usrreqs
128};
129#endif
130#if INET6
131struct ip6protosw in6_gif_protosw =
132{ SOCK_RAW, 0, 0/*IPPROTO_IPV[46]*/, PR_ATOMIC|PR_ADDR,
133 in6_gif_input,
134 0, 0, 0,
135 0,
136 0, 0, 0, 0,
137 0,
138 &rip6_usrreqs
139};
140#endif
1c79356b 141
1c79356b
A
142#ifndef MAX_GIF_NEST
143/*
144 * This macro controls the upper limitation on nesting of gif tunnels.
145 * Since, setting a large value to this macro with a careless configuration
146 * may introduce system crash, we don't allow any nestings by default.
147 * If you need to configure nested gif tunnels, you can define this macro
148 * in your kernel configuration file. However, if you do so, please be
149 * careful to configure the tunnels so that it won't make a loop.
150 */
151#define MAX_GIF_NEST 1
152#endif
153static int max_gif_nesting = MAX_GIF_NEST;
154
155
156
9bccf70c
A
157#ifdef __APPLE__
158/*
159 * Theory of operation: initially, one gif interface is created.
160 * Any time a gif interface is configured, if there are no other
161 * unconfigured gif interfaces, a new gif interface is created.
162 * BSD uses the clone mechanism to dynamically create more
163 * gif interfaces.
164 *
165 * We have some extra glue to support DLIL.
166 */
167
168/* GIF interface module support */
1c79356b
A
169int gif_demux(ifp, m, frame_header, proto)
170 struct ifnet *ifp;
171 struct mbuf *m;
172 char *frame_header;
173 struct if_proto **proto;
174{
9bccf70c
A
175 struct gif_softc* gif = (struct gif_softc*)ifp->if_softc;
176
177 /* Only one protocol may be attached to a gif interface. */
178 *proto = gif->gif_proto;
179
180 return 0;
1c79356b
A
181}
182
1c79356b
A
183static
184int gif_add_if(struct ifnet *ifp)
9bccf70c
A
185{
186 ifp->if_demux = gif_demux;
1c79356b
A
187 ifp->if_framer = 0;
188 return 0;
189}
9bccf70c 190
1c79356b
A
191static
192int gif_del_if(struct ifnet *ifp)
193{
194 return 0;
195}
196
197static
198int gif_add_proto(struct ddesc_head_str *desc_head, struct if_proto *proto, u_long dl_tag)
9bccf70c
A
199{
200 /* Only one protocol may be attached at a time */
201 struct gif_softc* gif = (struct gif_softc*)proto->ifp;
1c79356b 202
9bccf70c
A
203 if (gif->gif_proto != NULL)
204 printf("gif_add_proto: request add_proto for gif%d\n", gif->gif_if.if_unit);
1c79356b 205
9bccf70c 206 gif->gif_proto = proto;
1c79356b 207
9bccf70c 208 return 0;
1c79356b
A
209}
210
211static
212int gif_del_proto(struct if_proto *proto, u_long dl_tag)
9bccf70c
A
213{
214 if (((struct gif_softc*)proto->ifp)->gif_proto == proto)
215 ((struct gif_softc*)proto->ifp)->gif_proto = NULL;
216 else
217 return ENOENT;
1c79356b 218
9bccf70c 219 return 0;
1c79356b
A
220}
221
222int gif_shutdown()
223{
9bccf70c 224 return 0;
1c79356b
A
225}
226
227void gif_reg_if_mods()
228{
229 struct dlil_ifmod_reg_str gif_ifmod;
230
9bccf70c 231 bzero(&gif_ifmod, sizeof(gif_ifmod));
1c79356b
A
232 gif_ifmod.add_if = gif_add_if;
233 gif_ifmod.del_if = gif_del_if;
234 gif_ifmod.add_proto = gif_add_proto;
235 gif_ifmod.del_proto = gif_del_proto;
236 gif_ifmod.ifmod_ioctl = 0;
237 gif_ifmod.shutdown = gif_shutdown;
238
239 if (dlil_reg_if_modules(APPLE_IF_FAM_GIF, &gif_ifmod))
240 panic("Couldn't register gif modules\n");
241
9bccf70c 242}
1c79356b 243
9bccf70c
A
244/* Glue code to attach inet to a gif interface through DLIL */
245
246u_long gif_attach_proto_family(struct ifnet *ifp, int af)
1c79356b
A
247{
248 struct dlil_proto_reg_str reg;
249 struct dlil_demux_desc desc;
250 u_long dl_tag=0;
251 short native=0;
9bccf70c
A
252 int stat;
253
254 /* Check if we're already attached */
255 stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, af, &dl_tag);
256 if (stat == 0)
257 return dl_tag;
1c79356b
A
258
259 TAILQ_INIT(&reg.demux_desc_head);
260 desc.type = DLIL_DESC_RAW;
261 desc.variants.bitmask.proto_id_length = 0;
262 desc.variants.bitmask.proto_id = 0;
263 desc.variants.bitmask.proto_id_mask = 0;
264 desc.native_type = (char *) &native;
265 TAILQ_INSERT_TAIL(&reg.demux_desc_head, &desc, next);
266 reg.interface_family = ifp->if_family;
267 reg.unit_number = ifp->if_unit;
268 reg.input = gif_input;
269 reg.pre_output = gif_pre_output;
270 reg.event = 0;
271 reg.offer = 0;
9bccf70c 272 reg.ioctl = 0;
1c79356b 273 reg.default_proto = 0;
9bccf70c 274 reg.protocol_family = af;
1c79356b
A
275
276 stat = dlil_attach_protocol(&reg, &dl_tag);
277 if (stat) {
9bccf70c 278 panic("gif_attach_proto_family can't attach interface fam=%d\n", af);
1c79356b
A
279 }
280
281 return dl_tag;
282}
283
9bccf70c
A
284u_long gif_detach_proto_family(struct ifnet *ifp, int af)
285{
286 u_long ip_dl_tag = 0;
287 int stat;
288
289 stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, af, &ip_dl_tag);
290 if (stat == 0) {
291 stat = dlil_detach_protocol(ip_dl_tag);
292 if (stat) {
293 printf("WARNING: gif_detach can't detach IP fam=%d from interface\n", af);
294 }
295 }
296 return (stat);
297}
298
55e303ae
A
299int gif_attach_inet(struct ifnet *ifp, u_long *dl_tag) {
300 *dl_tag = gif_attach_proto_family(ifp, AF_INET);
301 return 0;
302}
303
304int gif_detach_inet(struct ifnet *ifp, u_long dl_tag) {
305 gif_detach_proto_family(ifp, AF_INET);
306 return 0;
307}
308
309int gif_attach_inet6(struct ifnet *ifp, u_long *dl_tag) {
310 *dl_tag = gif_attach_proto_family(ifp, AF_INET6);
311 return 0;
312}
313
314int gif_detach_inet6(struct ifnet *ifp, u_long dl_tag) {
315 gif_detach_proto_family(ifp, AF_INET6);
316 return 0;
317}
9bccf70c
A
318#endif
319
320/* Function to setup the first gif interface */
1c79356b 321void
9bccf70c 322gifattach(void)
1c79356b 323{
55e303ae
A
324 struct dlil_protomod_reg_str gif_protoreg;
325 int error;
326
9bccf70c
A
327 /* Init the list of interfaces */
328 TAILQ_INIT(&gifs);
1c79356b
A
329
330 gif_reg_if_mods(); /* DLIL modules */
331
55e303ae
A
332 /* Register protocol registration functions */
333
334 bzero(&gif_protoreg, sizeof(gif_protoreg));
335 gif_protoreg.attach_proto = gif_attach_inet;
336 gif_protoreg.detach_proto = gif_detach_inet;
337
338 if ( error = dlil_reg_proto_module(AF_INET, APPLE_IF_FAM_GIF, &gif_protoreg) != 0)
339 printf("dlil_reg_proto_module failed for AF_INET error=%d\n", error);
340
341 gif_protoreg.attach_proto = gif_attach_inet6;
342 gif_protoreg.detach_proto = gif_detach_inet6;
343
344 if ( error = dlil_reg_proto_module(AF_INET6, APPLE_IF_FAM_GIF, &gif_protoreg) != 0)
345 printf("dlil_reg_proto_module failed for AF_INET6 error=%d\n", error);
346
347
9bccf70c
A
348 /* Create first device */
349 gif_create_dev();
350}
351
352/* Creates another gif device if there are none free */
353static void
354gif_create_dev(void)
355{
356 struct gif_softc *sc;
357
358
359 /* Can't create more than GIF_MAXUNIT */
360 if (ngif >= GIF_MAXUNIT)
361 return;
362
363 /* Check for unused gif interface */
364 TAILQ_FOREACH(sc, &gifs, gif_link) {
365 /* If unused, return, no need to create a new interface */
366 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0)
367 return;
368 }
369
370 sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
371 if (sc == NULL) {
372 log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif);
373 return;
374 }
375
376 bzero(sc, sizeof(struct gif_softc));
377 sc->gif_if.if_softc = sc;
378 sc->gif_if.if_name = GIFNAME;
379 sc->gif_if.if_unit = ngif;
380
381 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
382#ifdef INET
383 sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
384 gif_encapcheck, &in_gif_protosw, sc);
385 if (sc->encap_cookie4 == NULL) {
386 printf("%s: unable to attach encap4\n", if_name(&sc->gif_if));
387 FREE(sc, M_DEVBUF);
388 return;
389 }
390#endif
391#ifdef INET6
392 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1,
393 gif_encapcheck, (struct protosw*)&in6_gif_protosw, sc);
394 if (sc->encap_cookie6 == NULL) {
395 if (sc->encap_cookie4) {
396 encap_detach(sc->encap_cookie4);
397 sc->encap_cookie4 = NULL;
398 }
399 printf("%s: unable to attach encap6\n", if_name(&sc->gif_if));
400 FREE(sc, M_DEVBUF);
401 return;
402 }
403#endif
404
405 sc->gif_if.if_family= APPLE_IF_FAM_GIF;
406 sc->gif_if.if_mtu = GIF_MTU;
407 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
1c79356b 408#if 0
9bccf70c
A
409 /* turn off ingress filter */
410 sc->gif_if.if_flags |= IFF_LINK2;
1c79356b 411#endif
9bccf70c
A
412 sc->gif_if.if_ioctl = gif_ioctl;
413 sc->gif_if.if_output = NULL; /* pre_output returns error or EJUSTRETURN */
414 sc->gif_if.if_type = IFT_GIF;
415 dlil_if_attach(&sc->gif_if);
416 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
417 TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
418 ngif++;
419}
420
421static int
422gif_encapcheck(m, off, proto, arg)
423 const struct mbuf *m;
424 int off;
425 int proto;
426 void *arg;
427{
428 struct ip ip;
429 struct gif_softc *sc;
430
431 sc = (struct gif_softc *)arg;
432 if (sc == NULL)
433 return 0;
434
435 if ((sc->gif_if.if_flags & IFF_UP) == 0)
436 return 0;
437
438 /* no physical address */
439 if (!sc->gif_psrc || !sc->gif_pdst)
440 return 0;
441
442 switch (proto) {
443#if INET
444 case IPPROTO_IPV4:
445 break;
1c79356b 446#endif
9bccf70c
A
447#if INET6
448 case IPPROTO_IPV6:
449 break;
1c79356b 450#endif
9bccf70c
A
451 default:
452 return 0;
1c79356b 453 }
1c79356b 454
9bccf70c
A
455 /* LINTED const cast */
456 m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
457
458 switch (ip.ip_v) {
459#if INET
460 case 4:
461 if (sc->gif_psrc->sa_family != AF_INET ||
462 sc->gif_pdst->sa_family != AF_INET)
463 return 0;
464 return gif_encapcheck4(m, off, proto, arg);
465#endif
466#if INET6
467 case 6:
468 if (sc->gif_psrc->sa_family != AF_INET6 ||
469 sc->gif_pdst->sa_family != AF_INET6)
470 return 0;
471 return gif_encapcheck6(m, off, proto, arg);
1c79356b 472#endif
9bccf70c
A
473 default:
474 return 0;
475 }
476}
1c79356b
A
477
478int
479gif_pre_output(ifp, m0, dst, rt, frame, address, dl_tag)
480 struct ifnet *ifp;
481 struct mbuf **m0;
482 struct sockaddr *dst;
9bccf70c 483 caddr_t rt;
1c79356b
A
484 char *frame;
485 char *address;
486 u_long dl_tag;
487{
9bccf70c 488 struct gif_softc *sc = (struct gif_softc*)ifp;
1c79356b
A
489 register struct mbuf * m = *m0;
490 int error = 0;
491 static int called = 0; /* XXX: MUTEX */
492
493 /*
494 * gif may cause infinite recursion calls when misconfigured.
495 * We'll prevent this by introducing upper limit.
496 * XXX: this mechanism may introduce another problem about
497 * mutual exclusion of the variable CALLED, especially if we
498 * use kernel thread.
499 */
500 if (++called > max_gif_nesting) {
501 log(LOG_NOTICE,
502 "gif_output: recursively called too many times(%d)\n",
503 called);
55e303ae 504 m_freem(m); /* free it here not in dlil_output*/
1c79356b
A
505 error = EIO; /* is there better errno? */
506 goto end;
507 }
508
509 getmicrotime(&ifp->if_lastchange);
510 m->m_flags &= ~(M_BCAST|M_MCAST);
511 if (!(ifp->if_flags & IFF_UP) ||
1c79356b 512 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
55e303ae 513 m_freem(m); /* free it here not in dlil_output */
1c79356b 514 error = ENETDOWN;
1c79356b
A
515 goto end;
516 }
517
1c79356b
A
518 if (ifp->if_bpf) {
519 /*
520 * We need to prepend the address family as
521 * a four byte field. Cons up a dummy header
522 * to pacify bpf. This is safe because bpf
523 * will only read from the mbuf (i.e., it won't
524 * try to free it or keep a pointer a to it).
525 */
526 struct mbuf m0;
9bccf70c 527 u_int32_t af = dst->sa_family;
1c79356b
A
528
529 m0.m_next = m;
530 m0.m_len = 4;
531 m0.m_data = (char *)&af;
532
1c79356b 533 bpf_mtap(ifp, &m0);
1c79356b 534 }
1c79356b
A
535 ifp->if_opackets++;
536 ifp->if_obytes += m->m_pkthdr.len;
1c79356b 537
9bccf70c
A
538 /* inner AF-specific encapsulation */
539
540 /* XXX should we check if our outer source is legal? */
541
542 /* dispatch to output logic based on outer AF */
1c79356b
A
543 switch (sc->gif_psrc->sa_family) {
544#if INET
545 case AF_INET:
9bccf70c 546 error = in_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
1c79356b
A
547 break;
548#endif
549#if INET6
550 case AF_INET6:
9bccf70c 551 error = in6_gif_output(ifp, dst->sa_family, m, (struct rtentry*)rt);
1c79356b
A
552 break;
553#endif
554 default:
1c79356b 555 error = ENETDOWN;
9bccf70c 556 goto end;
1c79356b 557 }
1c79356b
A
558
559 end:
560 called = 0; /* reset recursion counter */
55e303ae
A
561 if (error) {
562 /* the mbuf was freed either by in_gif_output or in here */
563 *m0 = NULL; /* avoid getting dlil_output freeing it */
9bccf70c 564 ifp->if_oerrors++;
55e303ae 565 }
9bccf70c
A
566 if (error == 0)
567 error = EJUSTRETURN; /* if no error, packet got sent already */
568 return error;
1c79356b
A
569}
570
9bccf70c
A
571int
572gif_input(m, frame_header, gifp, dl_tag, sync_ok)
1c79356b 573 struct mbuf *m;
9bccf70c
A
574 char* frame_header;
575 struct ifnet* gifp;
576 u_long dl_tag;
577 int sync_ok;
1c79356b
A
578{
579 int s, isr;
9bccf70c
A
580 struct ifqueue *ifq = 0;
581 int af;
1c79356b
A
582
583 if (gifp == NULL) {
584 /* just in case */
585 m_freem(m);
586 return;
587 }
588
9bccf70c
A
589 /* Assume packet is of type of protocol attached to this interface */
590 af = ((struct gif_softc*)(gifp->if_softc))->gif_proto->protocol_family;
591
1c79356b
A
592 if (m->m_pkthdr.rcvif)
593 m->m_pkthdr.rcvif = gifp;
594
1c79356b
A
595 if (gifp->if_bpf) {
596 /*
597 * We need to prepend the address family as
598 * a four byte field. Cons up a dummy header
599 * to pacify bpf. This is safe because bpf
600 * will only read from the mbuf (i.e., it won't
601 * try to free it or keep a pointer a to it).
602 */
603 struct mbuf m0;
9bccf70c 604 u_int32_t af1 = af;
1c79356b
A
605
606 m0.m_next = m;
607 m0.m_len = 4;
9bccf70c 608 m0.m_data = (char *)&af1;
1c79356b 609
1c79356b 610 bpf_mtap(gifp, &m0);
1c79356b 611 }
1c79356b
A
612
613 /*
614 * Put the packet to the network layer input queue according to the
615 * specified address family.
616 * Note: older versions of gif_input directly called network layer
617 * input functions, e.g. ip6_input, here. We changed the policy to
618 * prevent too many recursive calls of such input functions, which
619 * might cause kernel panic. But the change may introduce another
620 * problem; if the input queue is full, packets are discarded.
621 * We believed it rarely occurs and changed the policy. If we find
622 * it occurs more times than we thought, we may change the policy
623 * again.
624 */
625 switch (af) {
626#if INET
627 case AF_INET:
628 ifq = &ipintrq;
629 isr = NETISR_IP;
630 break;
631#endif
632#if INET6
633 case AF_INET6:
634 ifq = &ip6intrq;
635 isr = NETISR_IPV6;
636 break;
637#endif
638 default:
639 m_freem(m);
9bccf70c 640 return (EJUSTRETURN);
1c79356b
A
641 }
642
643 s = splimp();
644 if (IF_QFULL(ifq)) {
645 IF_DROP(ifq); /* update statistics */
646 m_freem(m);
647 splx(s);
9bccf70c 648 return (EJUSTRETURN);
1c79356b
A
649 }
650 IF_ENQUEUE(ifq, m);
651 /* we need schednetisr since the address family may change */
652 schednetisr(isr);
653 gifp->if_ipackets++;
654 gifp->if_ibytes += m->m_pkthdr.len;
655 splx(s);
656
9bccf70c 657 return (0);
1c79356b
A
658}
659
660/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
661int
662gif_ioctl(ifp, cmd, data)
663 struct ifnet *ifp;
664 u_long cmd;
9bccf70c 665 void* data;
1c79356b
A
666{
667 struct gif_softc *sc = (struct gif_softc*)ifp;
668 struct ifreq *ifr = (struct ifreq*)data;
669 int error = 0, size;
670 struct sockaddr *dst, *src;
9bccf70c
A
671 struct sockaddr *sa;
672 int s;
673 struct ifnet *ifp2;
1c79356b
A
674 struct gif_softc *sc2;
675
676 switch (cmd) {
677 case SIOCSIFADDR:
678 break;
679
680 case SIOCSIFDSTADDR:
681 break;
682
683 case SIOCADDMULTI:
684 case SIOCDELMULTI:
1c79356b
A
685 break;
686
687#ifdef SIOCSIFMTU /* xxx */
1c79356b
A
688 case SIOCGIFMTU:
689 break;
9bccf70c 690
1c79356b
A
691 case SIOCSIFMTU:
692 {
1c79356b
A
693 u_long mtu;
694 mtu = ifr->ifr_mtu;
1c79356b
A
695 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
696 return (EINVAL);
697 }
698 ifp->if_mtu = mtu;
699 }
700 break;
1c79356b
A
701#endif /* SIOCSIFMTU */
702
703 case SIOCSIFPHYADDR:
704#if INET6
705 case SIOCSIFPHYADDR_IN6:
706#endif /* INET6 */
9bccf70c
A
707 case SIOCSLIFPHYADDR:
708 switch (cmd) {
709#if INET
710 case SIOCSIFPHYADDR:
711 src = (struct sockaddr *)
712 &(((struct in_aliasreq *)data)->ifra_addr);
713 dst = (struct sockaddr *)
714 &(((struct in_aliasreq *)data)->ifra_dstaddr);
715 break;
716#endif
717#if INET6
718 case SIOCSIFPHYADDR_IN6:
719 src = (struct sockaddr *)
720 &(((struct in6_aliasreq *)data)->ifra_addr);
721 dst = (struct sockaddr *)
722 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
723 break;
724#endif
725 case SIOCSLIFPHYADDR:
726 src = (struct sockaddr *)
727 &(((struct if_laddrreq *)data)->addr);
728 dst = (struct sockaddr *)
729 &(((struct if_laddrreq *)data)->dstaddr);
730 }
731
732 /* sa_family must be equal */
733 if (src->sa_family != dst->sa_family)
734 return EINVAL;
735
736 /* validate sa_len */
737 switch (src->sa_family) {
738#if INET
739 case AF_INET:
740 if (src->sa_len != sizeof(struct sockaddr_in))
741 return EINVAL;
742 break;
743#endif
744#if INET6
745 case AF_INET6:
746 if (src->sa_len != sizeof(struct sockaddr_in6))
747 return EINVAL;
748 break;
749#endif
750 default:
751 return EAFNOSUPPORT;
752 }
753 switch (dst->sa_family) {
754#if INET
755 case AF_INET:
756 if (dst->sa_len != sizeof(struct sockaddr_in))
757 return EINVAL;
758 break;
759#endif
760#if INET6
761 case AF_INET6:
762 if (dst->sa_len != sizeof(struct sockaddr_in6))
763 return EINVAL;
764 break;
765#endif
766 default:
767 return EAFNOSUPPORT;
768 }
769
770 /* check sa_family looks sane for the cmd */
771 switch (cmd) {
772 case SIOCSIFPHYADDR:
773 if (src->sa_family == AF_INET)
774 break;
775 return EAFNOSUPPORT;
776#if INET6
777 case SIOCSIFPHYADDR_IN6:
778 if (src->sa_family == AF_INET6)
779 break;
780 return EAFNOSUPPORT;
781#endif /* INET6 */
782 case SIOCSLIFPHYADDR:
783 /* checks done in the above */
784 break;
785 }
786
787 TAILQ_FOREACH(ifp2, &ifnet, if_link) {
788 if (strcmp(ifp2->if_name, GIFNAME) != 0)
789 continue;
790 sc2 = ifp2->if_softc;
1c79356b
A
791 if (sc2 == sc)
792 continue;
793 if (!sc2->gif_pdst || !sc2->gif_psrc)
794 continue;
9bccf70c
A
795 if (sc2->gif_pdst->sa_family != dst->sa_family ||
796 sc2->gif_pdst->sa_len != dst->sa_len ||
797 sc2->gif_psrc->sa_family != src->sa_family ||
798 sc2->gif_psrc->sa_len != src->sa_len)
799 continue;
800#ifndef XBONEHACK
801 /* can't configure same pair of address onto two gifs */
802 if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
1c79356b
A
803 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
804 error = EADDRNOTAVAIL;
805 goto bad;
806 }
9bccf70c 807#endif
1c79356b 808
9bccf70c
A
809 /* can't configure multiple multi-dest interfaces */
810#define multidest(x) \
811 (((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
1c79356b 812#if INET6
9bccf70c
A
813#define multidest6(x) \
814 (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
815#endif
816 if (dst->sa_family == AF_INET &&
817 multidest(dst) && multidest(sc2->gif_pdst)) {
818 error = EADDRNOTAVAIL;
819 goto bad;
820 }
821#if INET6
822 if (dst->sa_family == AF_INET6 &&
823 multidest6(dst) && multidest6(sc2->gif_pdst)) {
824 error = EADDRNOTAVAIL;
825 goto bad;
826 }
827#endif
1c79356b 828 }
9bccf70c
A
829
830 if (sc->gif_psrc)
831 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
832 sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK);
833 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
834 sc->gif_psrc = sa;
835
836 if (sc->gif_pdst)
837 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
838 sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK);
839 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
840 sc->gif_pdst = sa;
841
842 ifp->if_flags |= IFF_RUNNING;
843
844 gif_attach_proto_family(ifp, src->sa_family);
845
846 s = splimp();
847 if_up(ifp); /* mark interface UP and send up RTM_IFINFO */
848#ifdef __APPLE__
849 /* Make sure at least one unused device is still available */
850 gif_create_dev();
851#endif
852 splx(s);
853
854 error = 0;
1c79356b 855 break;
9bccf70c
A
856
857#ifdef SIOCDIFPHYADDR
858 case SIOCDIFPHYADDR:
859 if (sc->gif_psrc) {
860 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
861 sc->gif_psrc = NULL;
862 }
863 if (sc->gif_pdst) {
864 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
865 sc->gif_pdst = NULL;
866 }
867 /* change the IFF_{UP, RUNNING} flag as well? */
868 break;
869#endif
1c79356b
A
870
871 case SIOCGIFPSRCADDR:
872#if INET6
873 case SIOCGIFPSRCADDR_IN6:
874#endif /* INET6 */
875 if (sc->gif_psrc == NULL) {
876 error = EADDRNOTAVAIL;
877 goto bad;
878 }
879 src = sc->gif_psrc;
9bccf70c 880 switch (cmd) {
1c79356b 881#if INET
9bccf70c 882 case SIOCGIFPSRCADDR:
1c79356b 883 dst = &ifr->ifr_addr;
9bccf70c 884 size = sizeof(ifr->ifr_addr);
1c79356b
A
885 break;
886#endif /* INET */
887#if INET6
9bccf70c 888 case SIOCGIFPSRCADDR_IN6:
1c79356b
A
889 dst = (struct sockaddr *)
890 &(((struct in6_ifreq *)data)->ifr_addr);
9bccf70c 891 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
1c79356b
A
892 break;
893#endif /* INET6 */
894 default:
895 error = EADDRNOTAVAIL;
896 goto bad;
897 }
9bccf70c
A
898 if (src->sa_len > size)
899 return EINVAL;
900 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
1c79356b
A
901 break;
902
903 case SIOCGIFPDSTADDR:
904#if INET6
905 case SIOCGIFPDSTADDR_IN6:
906#endif /* INET6 */
907 if (sc->gif_pdst == NULL) {
908 error = EADDRNOTAVAIL;
909 goto bad;
910 }
911 src = sc->gif_pdst;
9bccf70c 912 switch (cmd) {
1c79356b 913#if INET
9bccf70c 914 case SIOCGIFPDSTADDR:
1c79356b 915 dst = &ifr->ifr_addr;
9bccf70c 916 size = sizeof(ifr->ifr_addr);
1c79356b
A
917 break;
918#endif /* INET */
919#if INET6
9bccf70c 920 case SIOCGIFPDSTADDR_IN6:
1c79356b
A
921 dst = (struct sockaddr *)
922 &(((struct in6_ifreq *)data)->ifr_addr);
9bccf70c 923 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
1c79356b
A
924 break;
925#endif /* INET6 */
926 default:
927 error = EADDRNOTAVAIL;
928 goto bad;
929 }
9bccf70c
A
930 if (src->sa_len > size)
931 return EINVAL;
932 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
1c79356b
A
933 break;
934
9bccf70c
A
935 case SIOCGLIFPHYADDR:
936 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
937 error = EADDRNOTAVAIL;
1c79356b 938 goto bad;
1c79356b 939 }
9bccf70c
A
940
941 /* copy src */
942 src = sc->gif_psrc;
943 dst = (struct sockaddr *)
944 &(((struct if_laddrreq *)data)->addr);
945 size = sizeof(((struct if_laddrreq *)data)->addr);
946 if (src->sa_len > size)
947 return EINVAL;
948 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
949
950 /* copy dst */
951 src = sc->gif_pdst;
952 dst = (struct sockaddr *)
953 &(((struct if_laddrreq *)data)->dstaddr);
954 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
955 if (src->sa_len > size)
956 return EINVAL;
957 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
958 break;
959
960 case SIOCSIFFLAGS:
961 /* if_ioctl() takes care of it */
1c79356b
A
962 break;
963
964 default:
9bccf70c 965 error = EOPNOTSUPP;
1c79356b
A
966 break;
967 }
968 bad:
969 return error;
970}
9bccf70c
A
971
972void
973gif_delete_tunnel(sc)
974 struct gif_softc *sc;
975{
976 /* XXX: NetBSD protects this function with splsoftnet() */
977
978 if (sc->gif_psrc) {
979 FREE((caddr_t)sc->gif_psrc, M_IFADDR);
980 sc->gif_psrc = NULL;
981 }
982 if (sc->gif_pdst) {
983 FREE((caddr_t)sc->gif_pdst, M_IFADDR);
984 sc->gif_pdst = NULL;
985 }
986 /* change the IFF_UP flag as well? */
987}