Deleted Added
full compact
1/* $FreeBSD: head/sys/net/if_gif.c 121816 2003-10-31 18:32:15Z brooks $ */
1/* $FreeBSD: head/sys/net/if_gif.c 123922 2003-12-28 03:56:00Z sam $ */
2/* $KAME: if_gif.c,v 1.87 2001/10/19 08:50:27 itojun Exp $ */
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include "opt_inet.h"
34#include "opt_inet6.h"
35#include "opt_mac.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/mac.h>
41#include <sys/malloc.h>
42#include <sys/mbuf.h>
43#include <sys/socket.h>
44#include <sys/sockio.h>
45#include <sys/errno.h>
46#include <sys/time.h>
47#include <sys/sysctl.h>
48#include <sys/syslog.h>
49#include <sys/protosw.h>
50#include <sys/conf.h>
51#include <machine/cpu.h>
52
53#include <net/if.h>
54#include <net/if_types.h>
55#include <net/netisr.h>
56#include <net/route.h>
57#include <net/bpf.h>
58
59#include <netinet/in.h>
60#include <netinet/in_systm.h>
61#include <netinet/ip.h>
62#ifdef INET
63#include <netinet/in_var.h>
64#include <netinet/in_gif.h>
65#include <netinet/ip_var.h>
66#endif /* INET */
67
68#ifdef INET6
69#ifndef INET
70#include <netinet/in.h>
71#endif
72#include <netinet6/in6_var.h>
73#include <netinet/ip6.h>
74#include <netinet6/ip6_var.h>
75#include <netinet6/in6_gif.h>
76#include <netinet6/ip6protosw.h>
77#endif /* INET6 */
78
79#include <netinet/ip_encap.h>
80#include <net/if_gif.h>
81
82#include <net/net_osdep.h>
83
84#define GIFNAME "gif"
85
86static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
87static LIST_HEAD(, gif_softc) gif_softc_list;
88
89void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
90void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
91void (*ng_gif_attach_p)(struct ifnet *ifp);
92void (*ng_gif_detach_p)(struct ifnet *ifp);
93
94int gif_clone_create(struct if_clone *, int);
95void gif_clone_destroy(struct ifnet *);
96
97struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
98 gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
99
100static int gifmodevent(module_t, int, void *);
101
102SYSCTL_DECL(_net_link);
103SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
104 "Generic Tunnel Interface");
105#ifndef MAX_GIF_NEST
106/*
107 * This macro controls the default upper limitation on nesting of gif tunnels.
108 * Since, setting a large value to this macro with a careless configuration
109 * may introduce system crash, we don't allow any nestings by default.
110 * If you need to configure nested gif tunnels, you can define this macro
111 * in your kernel configuration file. However, if you do so, please be
112 * careful to configure the tunnels so that it won't make a loop.
113 */
114#define MAX_GIF_NEST 1
115#endif
116static int max_gif_nesting = MAX_GIF_NEST;
117SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
118 &max_gif_nesting, 0, "Max nested tunnels");
119
120/*
121 * By default, we disallow creation of multiple tunnels between the same
122 * pair of addresses. Some applications require this functionality so
123 * we allow control over this check here.
124 */
125#ifdef XBONEHACK
126static int parallel_tunnels = 1;
127#else
128static int parallel_tunnels = 0;
129#endif
130SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
131 &parallel_tunnels, 0, "Allow parallel tunnels?");
132
133int
134gif_clone_create(ifc, unit)
135 struct if_clone *ifc;
136 int unit;
137{
138 struct gif_softc *sc;
139
140 sc = malloc (sizeof(struct gif_softc), M_GIF, M_WAITOK);
141 bzero(sc, sizeof(struct gif_softc));
142
143 sc->gif_if.if_softc = sc;
144 if_initname(&sc->gif_if, ifc->ifc_name, unit);
145
146 gifattach0(sc);
147
148 LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
149 return (0);
150}
151
152void
153gifattach0(sc)
154 struct gif_softc *sc;
155{
156
157 sc->encap_cookie4 = sc->encap_cookie6 = NULL;
158
159 sc->gif_if.if_addrlen = 0;
160 sc->gif_if.if_mtu = GIF_MTU;
161 sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
162#if 0
163 /* turn off ingress filter */
164 sc->gif_if.if_flags |= IFF_LINK2;
165#endif
166 sc->gif_if.if_ioctl = gif_ioctl;
167 sc->gif_if.if_output = gif_output;
168 sc->gif_if.if_type = IFT_GIF;
169 sc->gif_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
170 if_attach(&sc->gif_if);
171 bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
172 if (ng_gif_attach_p != NULL)
173 (*ng_gif_attach_p)(&sc->gif_if);
174}
175
176void
177gif_clone_destroy(ifp)
178 struct ifnet *ifp;
179{
180 int err;
181 struct gif_softc *sc = ifp->if_softc;
182
183 gif_delete_tunnel(&sc->gif_if);
184 LIST_REMOVE(sc, gif_list);
185#ifdef INET6
186 if (sc->encap_cookie6 != NULL) {
187 err = encap_detach(sc->encap_cookie6);
188 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
189 }
190#endif
191#ifdef INET
192 if (sc->encap_cookie4 != NULL) {
193 err = encap_detach(sc->encap_cookie4);
194 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
195 }
196#endif
197
198 if (ng_gif_detach_p != NULL)
199 (*ng_gif_detach_p)(ifp);
200 bpfdetach(ifp);
201 if_detach(ifp);
202
203 free(sc, M_GIF);
204}
205
206static int
207gifmodevent(mod, type, data)
208 module_t mod;
209 int type;
210 void *data;
211{
212
213 switch (type) {
214 case MOD_LOAD:
215 LIST_INIT(&gif_softc_list);
216 if_clone_attach(&gif_cloner);
217
218#ifdef INET6
219 ip6_gif_hlim = GIF_HLIM;
220#endif
221
222 break;
223 case MOD_UNLOAD:
224 if_clone_detach(&gif_cloner);
225
226 while (!LIST_EMPTY(&gif_softc_list))
227 gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
228
229#ifdef INET6
230 ip6_gif_hlim = 0;
231#endif
232 break;
233 }
234 return 0;
235}
236
237static moduledata_t gif_mod = {
238 "if_gif",
239 gifmodevent,
240 0
241};
242
243DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
244MODULE_VERSION(if_gif, 1);
245
246int
247gif_encapcheck(m, off, proto, arg)
248 const struct mbuf *m;
249 int off;
250 int proto;
251 void *arg;
252{
253 struct ip ip;
254 struct gif_softc *sc;
255
256 sc = (struct gif_softc *)arg;
257 if (sc == NULL)
258 return 0;
259
260 if ((sc->gif_if.if_flags & IFF_UP) == 0)
261 return 0;
262
263 /* no physical address */
264 if (!sc->gif_psrc || !sc->gif_pdst)
265 return 0;
266
267 switch (proto) {
268#ifdef INET
269 case IPPROTO_IPV4:
270 break;
271#endif
272#ifdef INET6
273 case IPPROTO_IPV6:
274 break;
275#endif
276 default:
277 return 0;
278 }
279
280 /* Bail on short packets */
281 if (m->m_pkthdr.len < sizeof(ip))
282 return 0;
283
284 m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
285
286 switch (ip.ip_v) {
287#ifdef INET
288 case 4:
289 if (sc->gif_psrc->sa_family != AF_INET ||
290 sc->gif_pdst->sa_family != AF_INET)
291 return 0;
292 return gif_encapcheck4(m, off, proto, arg);
293#endif
294#ifdef INET6
295 case 6:
296 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
297 return 0;
298 if (sc->gif_psrc->sa_family != AF_INET6 ||
299 sc->gif_pdst->sa_family != AF_INET6)
300 return 0;
301 return gif_encapcheck6(m, off, proto, arg);
302#endif
303 default:
304 return 0;
305 }
306}
307
308int
309gif_output(ifp, m, dst, rt)
310 struct ifnet *ifp;
311 struct mbuf *m;
312 struct sockaddr *dst;
313 struct rtentry *rt; /* added in net2 */
314{
315 struct gif_softc *sc = (struct gif_softc*)ifp;
316 int error = 0;
317 static int called = 0; /* XXX: MUTEX */
318
319#ifdef MAC
320 error = mac_check_ifnet_transmit(ifp, m);
321 if (error) {
322 m_freem(m);
323 goto end;
324 }
325#endif
326
327 /*
328 * gif may cause infinite recursion calls when misconfigured.
329 * We'll prevent this by introducing upper limit.
330 * XXX: this mechanism may introduce another problem about
331 * mutual exclusion of the variable CALLED, especially if we
332 * use kernel thread.
333 */
334 if (++called > max_gif_nesting) {
335 log(LOG_NOTICE,
336 "gif_output: recursively called too many times(%d)\n",
337 called);
338 m_freem(m);
339 error = EIO; /* is there better errno? */
340 goto end;
341 }
342
343 m->m_flags &= ~(M_BCAST|M_MCAST);
344 if (!(ifp->if_flags & IFF_UP) ||
345 sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
346 m_freem(m);
347 error = ENETDOWN;
348 goto end;
349 }
350
351 if (ifp->if_bpf) {
352 /*
353 * We need to prepend the address family as
354 * a four byte field. Cons up a dummy header
355 * to pacify bpf. This is safe because bpf
356 * will only read from the mbuf (i.e., it won't
357 * try to free it or keep a pointer a to it).
358 */
359 struct mbuf m0;
352 u_int32_t af = dst->sa_family;
361
362 m0.m_next = m;
363 m0.m_len = 4;
364 m0.m_data = (char *)&af;
365
366 BPF_MTAP(ifp, &m0);
353 bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
354 }
355 ifp->if_opackets++;
356 ifp->if_obytes += m->m_pkthdr.len;
357
358 /* inner AF-specific encapsulation */
359
360 /* XXX should we check if our outer source is legal? */
361
362 /* dispatch to output logic based on outer AF */
363 switch (sc->gif_psrc->sa_family) {
364#ifdef INET
365 case AF_INET:
366 error = in_gif_output(ifp, dst->sa_family, m);
367 break;
368#endif
369#ifdef INET6
370 case AF_INET6:
371 error = in6_gif_output(ifp, dst->sa_family, m);
372 break;
373#endif
374 default:
375 m_freem(m);
376 error = ENETDOWN;
377 goto end;
378 }
379
380 end:
381 called = 0; /* reset recursion counter */
382 if (error)
383 ifp->if_oerrors++;
384 return error;
385}
386
387void
388gif_input(m, af, ifp)
389 struct mbuf *m;
390 int af;
391 struct ifnet *ifp;
392{
393 int isr;
394
395 if (ifp == NULL) {
396 /* just in case */
397 m_freem(m);
398 return;
399 }
400
401 m->m_pkthdr.rcvif = ifp;
402
403#ifdef MAC
404 mac_create_mbuf_from_ifnet(ifp, m);
405#endif
406
407 if (ifp->if_bpf) {
421 /*
422 * We need to prepend the address family as
423 * a four byte field. Cons up a dummy header
424 * to pacify bpf. This is safe because bpf
425 * will only read from the mbuf (i.e., it won't
426 * try to free it or keep a pointer a to it).
427 */
428 struct mbuf m0;
408 u_int32_t af1 = af;
430
431 m0.m_next = m;
432 m0.m_len = 4;
433 m0.m_data = (char *)&af1;
434
435 BPF_MTAP(ifp, &m0);
409 bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
410 }
411
412 if (ng_gif_input_p != NULL) {
413 (*ng_gif_input_p)(ifp, &m, af);
414 if (m == NULL)
415 return;
416 }
417
418 /*
419 * Put the packet to the network layer input queue according to the
420 * specified address family.
421 * Note: older versions of gif_input directly called network layer
422 * input functions, e.g. ip6_input, here. We changed the policy to
423 * prevent too many recursive calls of such input functions, which
424 * might cause kernel panic. But the change may introduce another
425 * problem; if the input queue is full, packets are discarded.
426 * The kernel stack overflow really happened, and we believed
427 * queue-full rarely occurs, so we changed the policy.
428 */
429 switch (af) {
430#ifdef INET
431 case AF_INET:
432 isr = NETISR_IP;
433 break;
434#endif
435#ifdef INET6
436 case AF_INET6:
437 isr = NETISR_IPV6;
438 break;
439#endif
440 default:
441 if (ng_gif_input_orphan_p != NULL)
442 (*ng_gif_input_orphan_p)(ifp, m, af);
443 else
444 m_freem(m);
445 return;
446 }
447
448 ifp->if_ipackets++;
449 ifp->if_ibytes += m->m_pkthdr.len;
450 netisr_dispatch(isr, m);
451}
452
453/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
454int
455gif_ioctl(ifp, cmd, data)
456 struct ifnet *ifp;
457 u_long cmd;
458 caddr_t data;
459{
460 struct gif_softc *sc = (struct gif_softc*)ifp;
461 struct ifreq *ifr = (struct ifreq*)data;
462 int error = 0, size;
463 struct sockaddr *dst, *src;
464#ifdef SIOCSIFMTU /* xxx */
465 u_long mtu;
466#endif
467
468 switch (cmd) {
469 case SIOCSIFADDR:
470 ifp->if_flags |= IFF_UP;
471 break;
472
473 case SIOCSIFDSTADDR:
474 break;
475
476 case SIOCADDMULTI:
477 case SIOCDELMULTI:
478 break;
479
480#ifdef SIOCSIFMTU /* xxx */
481 case SIOCGIFMTU:
482 break;
483
484 case SIOCSIFMTU:
485 mtu = ifr->ifr_mtu;
486 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
487 return (EINVAL);
488 ifp->if_mtu = mtu;
489 break;
490#endif /* SIOCSIFMTU */
491
492#ifdef INET
493 case SIOCSIFPHYADDR:
494#endif
495#ifdef INET6
496 case SIOCSIFPHYADDR_IN6:
497#endif /* INET6 */
498 case SIOCSLIFPHYADDR:
499 switch (cmd) {
500#ifdef INET
501 case SIOCSIFPHYADDR:
502 src = (struct sockaddr *)
503 &(((struct in_aliasreq *)data)->ifra_addr);
504 dst = (struct sockaddr *)
505 &(((struct in_aliasreq *)data)->ifra_dstaddr);
506 break;
507#endif
508#ifdef INET6
509 case SIOCSIFPHYADDR_IN6:
510 src = (struct sockaddr *)
511 &(((struct in6_aliasreq *)data)->ifra_addr);
512 dst = (struct sockaddr *)
513 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
514 break;
515#endif
516 case SIOCSLIFPHYADDR:
517 src = (struct sockaddr *)
518 &(((struct if_laddrreq *)data)->addr);
519 dst = (struct sockaddr *)
520 &(((struct if_laddrreq *)data)->dstaddr);
521 break;
522 default:
523 return EINVAL;
524 }
525
526 /* sa_family must be equal */
527 if (src->sa_family != dst->sa_family)
528 return EINVAL;
529
530 /* validate sa_len */
531 switch (src->sa_family) {
532#ifdef INET
533 case AF_INET:
534 if (src->sa_len != sizeof(struct sockaddr_in))
535 return EINVAL;
536 break;
537#endif
538#ifdef INET6
539 case AF_INET6:
540 if (src->sa_len != sizeof(struct sockaddr_in6))
541 return EINVAL;
542 break;
543#endif
544 default:
545 return EAFNOSUPPORT;
546 }
547 switch (dst->sa_family) {
548#ifdef INET
549 case AF_INET:
550 if (dst->sa_len != sizeof(struct sockaddr_in))
551 return EINVAL;
552 break;
553#endif
554#ifdef INET6
555 case AF_INET6:
556 if (dst->sa_len != sizeof(struct sockaddr_in6))
557 return EINVAL;
558 break;
559#endif
560 default:
561 return EAFNOSUPPORT;
562 }
563
564 /* check sa_family looks sane for the cmd */
565 switch (cmd) {
566 case SIOCSIFPHYADDR:
567 if (src->sa_family == AF_INET)
568 break;
569 return EAFNOSUPPORT;
570#ifdef INET6
571 case SIOCSIFPHYADDR_IN6:
572 if (src->sa_family == AF_INET6)
573 break;
574 return EAFNOSUPPORT;
575#endif /* INET6 */
576 case SIOCSLIFPHYADDR:
577 /* checks done in the above */
578 break;
579 }
580
581 error = gif_set_tunnel(&sc->gif_if, src, dst);
582 break;
583
584#ifdef SIOCDIFPHYADDR
585 case SIOCDIFPHYADDR:
586 gif_delete_tunnel(&sc->gif_if);
587 break;
588#endif
589
590 case SIOCGIFPSRCADDR:
591#ifdef INET6
592 case SIOCGIFPSRCADDR_IN6:
593#endif /* INET6 */
594 if (sc->gif_psrc == NULL) {
595 error = EADDRNOTAVAIL;
596 goto bad;
597 }
598 src = sc->gif_psrc;
599 switch (cmd) {
600#ifdef INET
601 case SIOCGIFPSRCADDR:
602 dst = &ifr->ifr_addr;
603 size = sizeof(ifr->ifr_addr);
604 break;
605#endif /* INET */
606#ifdef INET6
607 case SIOCGIFPSRCADDR_IN6:
608 dst = (struct sockaddr *)
609 &(((struct in6_ifreq *)data)->ifr_addr);
610 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
611 break;
612#endif /* INET6 */
613 default:
614 error = EADDRNOTAVAIL;
615 goto bad;
616 }
617 if (src->sa_len > size)
618 return EINVAL;
619 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
620 break;
621
622 case SIOCGIFPDSTADDR:
623#ifdef INET6
624 case SIOCGIFPDSTADDR_IN6:
625#endif /* INET6 */
626 if (sc->gif_pdst == NULL) {
627 error = EADDRNOTAVAIL;
628 goto bad;
629 }
630 src = sc->gif_pdst;
631 switch (cmd) {
632#ifdef INET
633 case SIOCGIFPDSTADDR:
634 dst = &ifr->ifr_addr;
635 size = sizeof(ifr->ifr_addr);
636 break;
637#endif /* INET */
638#ifdef INET6
639 case SIOCGIFPDSTADDR_IN6:
640 dst = (struct sockaddr *)
641 &(((struct in6_ifreq *)data)->ifr_addr);
642 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
643 break;
644#endif /* INET6 */
645 default:
646 error = EADDRNOTAVAIL;
647 goto bad;
648 }
649 if (src->sa_len > size)
650 return EINVAL;
651 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
652 break;
653
654 case SIOCGLIFPHYADDR:
655 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
656 error = EADDRNOTAVAIL;
657 goto bad;
658 }
659
660 /* copy src */
661 src = sc->gif_psrc;
662 dst = (struct sockaddr *)
663 &(((struct if_laddrreq *)data)->addr);
664 size = sizeof(((struct if_laddrreq *)data)->addr);
665 if (src->sa_len > size)
666 return EINVAL;
667 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
668
669 /* copy dst */
670 src = sc->gif_pdst;
671 dst = (struct sockaddr *)
672 &(((struct if_laddrreq *)data)->dstaddr);
673 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
674 if (src->sa_len > size)
675 return EINVAL;
676 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
677 break;
678
679 case SIOCSIFFLAGS:
680 /* if_ioctl() takes care of it */
681 break;
682
683 default:
684 error = EINVAL;
685 break;
686 }
687 bad:
688 return error;
689}
690
691int
692gif_set_tunnel(ifp, src, dst)
693 struct ifnet *ifp;
694 struct sockaddr *src;
695 struct sockaddr *dst;
696{
697 struct gif_softc *sc = (struct gif_softc *)ifp;
698 struct gif_softc *sc2;
699 struct sockaddr *osrc, *odst, *sa;
700 int s;
701 int error = 0;
702
703 s = splnet();
704
705 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
706 if (sc2 == sc)
707 continue;
708 if (!sc2->gif_pdst || !sc2->gif_psrc)
709 continue;
710 if (sc2->gif_pdst->sa_family != dst->sa_family ||
711 sc2->gif_pdst->sa_len != dst->sa_len ||
712 sc2->gif_psrc->sa_family != src->sa_family ||
713 sc2->gif_psrc->sa_len != src->sa_len)
714 continue;
715
716 /*
717 * Disallow parallel tunnels unless instructed
718 * otherwise.
719 */
720 if (!parallel_tunnels &&
721 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
722 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
723 error = EADDRNOTAVAIL;
724 goto bad;
725 }
726
727 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
728 }
729
730 /* XXX we can detach from both, but be polite just in case */
731 if (sc->gif_psrc)
732 switch (sc->gif_psrc->sa_family) {
733#ifdef INET
734 case AF_INET:
735 (void)in_gif_detach(sc);
736 break;
737#endif
738#ifdef INET6
739 case AF_INET6:
740 (void)in6_gif_detach(sc);
741 break;
742#endif
743 }
744
745 osrc = sc->gif_psrc;
746 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
747 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
748 sc->gif_psrc = sa;
749
750 odst = sc->gif_pdst;
751 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
752 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
753 sc->gif_pdst = sa;
754
755 switch (sc->gif_psrc->sa_family) {
756#ifdef INET
757 case AF_INET:
758 error = in_gif_attach(sc);
759 break;
760#endif
761#ifdef INET6
762 case AF_INET6:
763 error = in6_gif_attach(sc);
764 break;
765#endif
766 }
767 if (error) {
768 /* rollback */
769 free((caddr_t)sc->gif_psrc, M_IFADDR);
770 free((caddr_t)sc->gif_pdst, M_IFADDR);
771 sc->gif_psrc = osrc;
772 sc->gif_pdst = odst;
773 goto bad;
774 }
775
776 if (osrc)
777 free((caddr_t)osrc, M_IFADDR);
778 if (odst)
779 free((caddr_t)odst, M_IFADDR);
780
781 if (sc->gif_psrc && sc->gif_pdst)
782 ifp->if_flags |= IFF_RUNNING;
783 else
784 ifp->if_flags &= ~IFF_RUNNING;
785 splx(s);
786
787 return 0;
788
789 bad:
790 if (sc->gif_psrc && sc->gif_pdst)
791 ifp->if_flags |= IFF_RUNNING;
792 else
793 ifp->if_flags &= ~IFF_RUNNING;
794 splx(s);
795
796 return error;
797}
798
799void
800gif_delete_tunnel(ifp)
801 struct ifnet *ifp;
802{
803 struct gif_softc *sc = (struct gif_softc *)ifp;
804 int s;
805
806 s = splnet();
807
808 if (sc->gif_psrc) {
809 free((caddr_t)sc->gif_psrc, M_IFADDR);
810 sc->gif_psrc = NULL;
811 }
812 if (sc->gif_pdst) {
813 free((caddr_t)sc->gif_pdst, M_IFADDR);
814 sc->gif_pdst = NULL;
815 }
816 /* it is safe to detach from both */
817#ifdef INET
818 (void)in_gif_detach(sc);
819#endif
820#ifdef INET6
821 (void)in6_gif_detach(sc);
822#endif
823
824 if (sc->gif_psrc && sc->gif_pdst)
825 ifp->if_flags |= IFF_RUNNING;
826 else
827 ifp->if_flags &= ~IFF_RUNNING;
828 splx(s);
829}