Deleted Added
sdiff udiff text old ( 121816 ) new ( 123922 )
full compact
1/* $FreeBSD: head/sys/net/if_gif.c 121816 2003-10-31 18:32:15Z brooks $ */
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;
360 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);
367 }
368 ifp->if_opackets++;
369 ifp->if_obytes += m->m_pkthdr.len;
370
371 /* inner AF-specific encapsulation */
372
373 /* XXX should we check if our outer source is legal? */
374
375 /* dispatch to output logic based on outer AF */
376 switch (sc->gif_psrc->sa_family) {
377#ifdef INET
378 case AF_INET:
379 error = in_gif_output(ifp, dst->sa_family, m);
380 break;
381#endif
382#ifdef INET6
383 case AF_INET6:
384 error = in6_gif_output(ifp, dst->sa_family, m);
385 break;
386#endif
387 default:
388 m_freem(m);
389 error = ENETDOWN;
390 goto end;
391 }
392
393 end:
394 called = 0; /* reset recursion counter */
395 if (error)
396 ifp->if_oerrors++;
397 return error;
398}
399
400void
401gif_input(m, af, ifp)
402 struct mbuf *m;
403 int af;
404 struct ifnet *ifp;
405{
406 int isr;
407
408 if (ifp == NULL) {
409 /* just in case */
410 m_freem(m);
411 return;
412 }
413
414 m->m_pkthdr.rcvif = ifp;
415
416#ifdef MAC
417 mac_create_mbuf_from_ifnet(ifp, m);
418#endif
419
420 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;
429 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);
436 }
437
438 if (ng_gif_input_p != NULL) {
439 (*ng_gif_input_p)(ifp, &m, af);
440 if (m == NULL)
441 return;
442 }
443
444 /*
445 * Put the packet to the network layer input queue according to the
446 * specified address family.
447 * Note: older versions of gif_input directly called network layer
448 * input functions, e.g. ip6_input, here. We changed the policy to
449 * prevent too many recursive calls of such input functions, which
450 * might cause kernel panic. But the change may introduce another
451 * problem; if the input queue is full, packets are discarded.
452 * The kernel stack overflow really happened, and we believed
453 * queue-full rarely occurs, so we changed the policy.
454 */
455 switch (af) {
456#ifdef INET
457 case AF_INET:
458 isr = NETISR_IP;
459 break;
460#endif
461#ifdef INET6
462 case AF_INET6:
463 isr = NETISR_IPV6;
464 break;
465#endif
466 default:
467 if (ng_gif_input_orphan_p != NULL)
468 (*ng_gif_input_orphan_p)(ifp, m, af);
469 else
470 m_freem(m);
471 return;
472 }
473
474 ifp->if_ipackets++;
475 ifp->if_ibytes += m->m_pkthdr.len;
476 netisr_dispatch(isr, m);
477}
478
479/* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
480int
481gif_ioctl(ifp, cmd, data)
482 struct ifnet *ifp;
483 u_long cmd;
484 caddr_t data;
485{
486 struct gif_softc *sc = (struct gif_softc*)ifp;
487 struct ifreq *ifr = (struct ifreq*)data;
488 int error = 0, size;
489 struct sockaddr *dst, *src;
490#ifdef SIOCSIFMTU /* xxx */
491 u_long mtu;
492#endif
493
494 switch (cmd) {
495 case SIOCSIFADDR:
496 ifp->if_flags |= IFF_UP;
497 break;
498
499 case SIOCSIFDSTADDR:
500 break;
501
502 case SIOCADDMULTI:
503 case SIOCDELMULTI:
504 break;
505
506#ifdef SIOCSIFMTU /* xxx */
507 case SIOCGIFMTU:
508 break;
509
510 case SIOCSIFMTU:
511 mtu = ifr->ifr_mtu;
512 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
513 return (EINVAL);
514 ifp->if_mtu = mtu;
515 break;
516#endif /* SIOCSIFMTU */
517
518#ifdef INET
519 case SIOCSIFPHYADDR:
520#endif
521#ifdef INET6
522 case SIOCSIFPHYADDR_IN6:
523#endif /* INET6 */
524 case SIOCSLIFPHYADDR:
525 switch (cmd) {
526#ifdef INET
527 case SIOCSIFPHYADDR:
528 src = (struct sockaddr *)
529 &(((struct in_aliasreq *)data)->ifra_addr);
530 dst = (struct sockaddr *)
531 &(((struct in_aliasreq *)data)->ifra_dstaddr);
532 break;
533#endif
534#ifdef INET6
535 case SIOCSIFPHYADDR_IN6:
536 src = (struct sockaddr *)
537 &(((struct in6_aliasreq *)data)->ifra_addr);
538 dst = (struct sockaddr *)
539 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
540 break;
541#endif
542 case SIOCSLIFPHYADDR:
543 src = (struct sockaddr *)
544 &(((struct if_laddrreq *)data)->addr);
545 dst = (struct sockaddr *)
546 &(((struct if_laddrreq *)data)->dstaddr);
547 break;
548 default:
549 return EINVAL;
550 }
551
552 /* sa_family must be equal */
553 if (src->sa_family != dst->sa_family)
554 return EINVAL;
555
556 /* validate sa_len */
557 switch (src->sa_family) {
558#ifdef INET
559 case AF_INET:
560 if (src->sa_len != sizeof(struct sockaddr_in))
561 return EINVAL;
562 break;
563#endif
564#ifdef INET6
565 case AF_INET6:
566 if (src->sa_len != sizeof(struct sockaddr_in6))
567 return EINVAL;
568 break;
569#endif
570 default:
571 return EAFNOSUPPORT;
572 }
573 switch (dst->sa_family) {
574#ifdef INET
575 case AF_INET:
576 if (dst->sa_len != sizeof(struct sockaddr_in))
577 return EINVAL;
578 break;
579#endif
580#ifdef INET6
581 case AF_INET6:
582 if (dst->sa_len != sizeof(struct sockaddr_in6))
583 return EINVAL;
584 break;
585#endif
586 default:
587 return EAFNOSUPPORT;
588 }
589
590 /* check sa_family looks sane for the cmd */
591 switch (cmd) {
592 case SIOCSIFPHYADDR:
593 if (src->sa_family == AF_INET)
594 break;
595 return EAFNOSUPPORT;
596#ifdef INET6
597 case SIOCSIFPHYADDR_IN6:
598 if (src->sa_family == AF_INET6)
599 break;
600 return EAFNOSUPPORT;
601#endif /* INET6 */
602 case SIOCSLIFPHYADDR:
603 /* checks done in the above */
604 break;
605 }
606
607 error = gif_set_tunnel(&sc->gif_if, src, dst);
608 break;
609
610#ifdef SIOCDIFPHYADDR
611 case SIOCDIFPHYADDR:
612 gif_delete_tunnel(&sc->gif_if);
613 break;
614#endif
615
616 case SIOCGIFPSRCADDR:
617#ifdef INET6
618 case SIOCGIFPSRCADDR_IN6:
619#endif /* INET6 */
620 if (sc->gif_psrc == NULL) {
621 error = EADDRNOTAVAIL;
622 goto bad;
623 }
624 src = sc->gif_psrc;
625 switch (cmd) {
626#ifdef INET
627 case SIOCGIFPSRCADDR:
628 dst = &ifr->ifr_addr;
629 size = sizeof(ifr->ifr_addr);
630 break;
631#endif /* INET */
632#ifdef INET6
633 case SIOCGIFPSRCADDR_IN6:
634 dst = (struct sockaddr *)
635 &(((struct in6_ifreq *)data)->ifr_addr);
636 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
637 break;
638#endif /* INET6 */
639 default:
640 error = EADDRNOTAVAIL;
641 goto bad;
642 }
643 if (src->sa_len > size)
644 return EINVAL;
645 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
646 break;
647
648 case SIOCGIFPDSTADDR:
649#ifdef INET6
650 case SIOCGIFPDSTADDR_IN6:
651#endif /* INET6 */
652 if (sc->gif_pdst == NULL) {
653 error = EADDRNOTAVAIL;
654 goto bad;
655 }
656 src = sc->gif_pdst;
657 switch (cmd) {
658#ifdef INET
659 case SIOCGIFPDSTADDR:
660 dst = &ifr->ifr_addr;
661 size = sizeof(ifr->ifr_addr);
662 break;
663#endif /* INET */
664#ifdef INET6
665 case SIOCGIFPDSTADDR_IN6:
666 dst = (struct sockaddr *)
667 &(((struct in6_ifreq *)data)->ifr_addr);
668 size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
669 break;
670#endif /* INET6 */
671 default:
672 error = EADDRNOTAVAIL;
673 goto bad;
674 }
675 if (src->sa_len > size)
676 return EINVAL;
677 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
678 break;
679
680 case SIOCGLIFPHYADDR:
681 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
682 error = EADDRNOTAVAIL;
683 goto bad;
684 }
685
686 /* copy src */
687 src = sc->gif_psrc;
688 dst = (struct sockaddr *)
689 &(((struct if_laddrreq *)data)->addr);
690 size = sizeof(((struct if_laddrreq *)data)->addr);
691 if (src->sa_len > size)
692 return EINVAL;
693 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
694
695 /* copy dst */
696 src = sc->gif_pdst;
697 dst = (struct sockaddr *)
698 &(((struct if_laddrreq *)data)->dstaddr);
699 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
700 if (src->sa_len > size)
701 return EINVAL;
702 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
703 break;
704
705 case SIOCSIFFLAGS:
706 /* if_ioctl() takes care of it */
707 break;
708
709 default:
710 error = EINVAL;
711 break;
712 }
713 bad:
714 return error;
715}
716
717int
718gif_set_tunnel(ifp, src, dst)
719 struct ifnet *ifp;
720 struct sockaddr *src;
721 struct sockaddr *dst;
722{
723 struct gif_softc *sc = (struct gif_softc *)ifp;
724 struct gif_softc *sc2;
725 struct sockaddr *osrc, *odst, *sa;
726 int s;
727 int error = 0;
728
729 s = splnet();
730
731 LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
732 if (sc2 == sc)
733 continue;
734 if (!sc2->gif_pdst || !sc2->gif_psrc)
735 continue;
736 if (sc2->gif_pdst->sa_family != dst->sa_family ||
737 sc2->gif_pdst->sa_len != dst->sa_len ||
738 sc2->gif_psrc->sa_family != src->sa_family ||
739 sc2->gif_psrc->sa_len != src->sa_len)
740 continue;
741
742 /*
743 * Disallow parallel tunnels unless instructed
744 * otherwise.
745 */
746 if (!parallel_tunnels &&
747 bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
748 bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
749 error = EADDRNOTAVAIL;
750 goto bad;
751 }
752
753 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
754 }
755
756 /* XXX we can detach from both, but be polite just in case */
757 if (sc->gif_psrc)
758 switch (sc->gif_psrc->sa_family) {
759#ifdef INET
760 case AF_INET:
761 (void)in_gif_detach(sc);
762 break;
763#endif
764#ifdef INET6
765 case AF_INET6:
766 (void)in6_gif_detach(sc);
767 break;
768#endif
769 }
770
771 osrc = sc->gif_psrc;
772 sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
773 bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
774 sc->gif_psrc = sa;
775
776 odst = sc->gif_pdst;
777 sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
778 bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
779 sc->gif_pdst = sa;
780
781 switch (sc->gif_psrc->sa_family) {
782#ifdef INET
783 case AF_INET:
784 error = in_gif_attach(sc);
785 break;
786#endif
787#ifdef INET6
788 case AF_INET6:
789 error = in6_gif_attach(sc);
790 break;
791#endif
792 }
793 if (error) {
794 /* rollback */
795 free((caddr_t)sc->gif_psrc, M_IFADDR);
796 free((caddr_t)sc->gif_pdst, M_IFADDR);
797 sc->gif_psrc = osrc;
798 sc->gif_pdst = odst;
799 goto bad;
800 }
801
802 if (osrc)
803 free((caddr_t)osrc, M_IFADDR);
804 if (odst)
805 free((caddr_t)odst, M_IFADDR);
806
807 if (sc->gif_psrc && sc->gif_pdst)
808 ifp->if_flags |= IFF_RUNNING;
809 else
810 ifp->if_flags &= ~IFF_RUNNING;
811 splx(s);
812
813 return 0;
814
815 bad:
816 if (sc->gif_psrc && sc->gif_pdst)
817 ifp->if_flags |= IFF_RUNNING;
818 else
819 ifp->if_flags &= ~IFF_RUNNING;
820 splx(s);
821
822 return error;
823}
824
825void
826gif_delete_tunnel(ifp)
827 struct ifnet *ifp;
828{
829 struct gif_softc *sc = (struct gif_softc *)ifp;
830 int s;
831
832 s = splnet();
833
834 if (sc->gif_psrc) {
835 free((caddr_t)sc->gif_psrc, M_IFADDR);
836 sc->gif_psrc = NULL;
837 }
838 if (sc->gif_pdst) {
839 free((caddr_t)sc->gif_pdst, M_IFADDR);
840 sc->gif_pdst = NULL;
841 }
842 /* it is safe to detach from both */
843#ifdef INET
844 (void)in_gif_detach(sc);
845#endif
846#ifdef INET6
847 (void)in6_gif_detach(sc);
848#endif
849
850 if (sc->gif_psrc && sc->gif_pdst)
851 ifp->if_flags |= IFF_RUNNING;
852 else
853 ifp->if_flags &= ~IFF_RUNNING;
854 splx(s);
855}