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