Upgrade ldns and drill(1). 1/2
[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.21 2008/05/14 11:59:23 sephe 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/bus.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 <sys/thread2.h>
52
53 #include <machine/cpu.h>
54
55 #include <net/if.h>
56 #include <net/if_types.h>
57 #include <net/ifq_var.h>
58 #include <net/netisr2.h>
59 #include <net/route.h>
60 #include <net/bpf.h>
61 #include <net/if_clone.h>
62
63 #include <netinet/in.h>
64 #include <netinet/in_systm.h>
65 #include <netinet/ip.h>
66 #ifdef  INET
67 #include <netinet/in_var.h>
68 #include <netinet/in_gif.h>
69 #include <netinet/ip_var.h>
70 #endif  /* INET */
71
72 #ifdef INET6
73 #ifndef INET
74 #include <netinet/in.h>
75 #endif
76 #include <netinet6/in6_var.h>
77 #include <netinet/ip6.h>
78 #include <netinet6/ip6_var.h>
79 #include <netinet6/in6_gif.h>
80 #include <netinet6/ip6protosw.h>
81 #endif /* INET6 */
82
83 #include <netinet/ip_encap.h>
84 #include "if_gif.h"
85
86 #include <net/net_osdep.h>
87
88 #define GIFNAME         "gif"
89
90 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
91 LIST_HEAD(, gif_softc) gif_softc_list;
92
93 int     gif_clone_create(struct if_clone *, int, caddr_t, caddr_t);
94 int     gif_clone_destroy(struct ifnet *);
95
96 struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif", gif_clone_create,
97     gif_clone_destroy, 0, IF_MAXUNIT);
98
99 static int gifmodevent(module_t, int, void *);
100 static void gif_clear_cache(struct gif_softc *sc);
101
102 SYSCTL_DECL(_net_link);
103 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
104     "Generic Tunnel Interface");
105
106 #ifndef MAX_GIF_NEST
107 /*
108  * This macro controls the default upper limitation on nesting of gif tunnels.
109  * Since, setting a large value to this macro with a careless configuration
110  * may introduce system crash, we don't allow any nestings by default.
111  * If you need to configure nested gif tunnels, you can define this macro
112  * in your kernel configuration file.  However, if you do so, please be
113  * careful to configure the tunnels so that it won't make a loop.
114  */
115 #define MAX_GIF_NEST 1
116 #endif
117 static int max_gif_nesting = MAX_GIF_NEST;
118 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
119     &max_gif_nesting, 0, "Max nested tunnels");
120
121 /*
122  * By default, we disallow creation of multiple tunnels between the same
123  * pair of addresses.  Some applications require this functionality so
124  * we allow control over this check here.
125  */
126 #ifdef XBONEHACK
127 static int parallel_tunnels = 1;
128 #else
129 static int parallel_tunnels = 0;
130 #endif
131 SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
132     &parallel_tunnels, 0, "Allow parallel tunnels?");
133
134
135 int
136 gif_clone_create(struct if_clone *ifc, int unit,
137                  caddr_t params __unused, caddr_t data __unused)
138 {
139         struct gif_softc *sc;
140         
141         sc = kmalloc (sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO);
142
143         sc->gif_if.if_softc = sc;
144         if_initname(&(sc->gif_if), GIFNAME, unit);
145
146         gifattach0(sc);
147
148         LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
149         return (0);
150 }
151
152 void
153 gifattach0(struct gif_softc *sc)
154 {
155
156         sc->encap_cookie4 = sc->encap_cookie6 = NULL;
157
158         sc->gif_if.if_addrlen = 0;
159         sc->gif_if.if_mtu    = GIF_MTU;
160         sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
161 #if 0
162         /* turn off ingress filter */
163         sc->gif_if.if_flags  |= IFF_LINK2;
164 #endif
165         sc->gif_if.if_ioctl  = gif_ioctl;
166         sc->gif_if.if_output = gif_output;
167         sc->gif_if.if_type   = IFT_GIF;
168         ifq_set_maxlen(&sc->gif_if.if_snd, IFQ_MAXLEN);
169         if_attach(&sc->gif_if, NULL);
170         bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int));
171 }
172
173 int
174 gif_clone_destroy(struct ifnet *ifp)
175 {
176         struct gif_softc *sc = ifp->if_softc;
177         int err;
178
179         gif_delete_tunnel(&sc->gif_if);
180         LIST_REMOVE(sc, gif_list);
181 #ifdef INET6
182         if (sc->encap_cookie6 != NULL) {
183                 err = encap_detach(sc->encap_cookie6);
184                 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
185         }
186 #endif
187 #ifdef INET
188         if (sc->encap_cookie4 != NULL) {
189                 err = encap_detach(sc->encap_cookie4);
190                 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
191         }
192 #endif
193         gif_clear_cache(sc);
194
195         bpfdetach(ifp);
196         if_detach(ifp);
197
198         kfree(sc, M_GIF);
199
200         return 0;
201 }
202
203 static void
204 gif_clear_cache(struct gif_softc *sc)
205 {
206         struct rtentry *rt;
207         int n;
208
209         for (n = 0; n < netisr_ncpus; ++n) {
210                 rt = sc->gif_ro[n].ro_rt;
211                 if (rt != NULL) {
212                         KASSERT(rt->rt_cpuid == n,
213                             ("inet rt for cpu%d installed on cpu%d slot",
214                              rt->rt_cpuid, n));
215                         rtfree_async(rt);
216                         sc->gif_ro[n].ro_rt = NULL;
217                 }
218 #ifdef INET6
219                 rt = sc->gif_ro6[n].ro_rt;
220                 if (rt != NULL) {
221                         KASSERT(rt->rt_cpuid == n,
222                             ("inet6 rt for cpu%d installed on cpu%d slot",
223                              rt->rt_cpuid, n));
224                         rtfree_async(rt);
225                         sc->gif_ro6[n].ro_rt = NULL;
226                 }
227 #endif
228         }
229 }
230
231 static int
232 gifmodevent(module_t mod, int type, void *data)
233 {
234
235         switch (type) {
236         case MOD_LOAD:
237                 LIST_INIT(&gif_softc_list);
238                 if_clone_attach(&gif_cloner);
239
240 #ifdef INET6
241                 ip6_gif_hlim = GIF_HLIM;
242 #endif
243
244                 break;
245         case MOD_UNLOAD:
246                 if_clone_detach(&gif_cloner);
247
248                 while (!LIST_EMPTY(&gif_softc_list))
249                         gif_clone_destroy(&LIST_FIRST(&gif_softc_list)->gif_if);
250
251 #ifdef INET6
252                 ip6_gif_hlim = 0;
253 #endif
254                 break;
255         }
256         return 0;
257 }
258
259 static moduledata_t gif_mod = {
260         "if_gif",
261         gifmodevent,
262         0
263 };
264
265 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
266
267 int
268 gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
269 {
270         struct ip ip;
271         struct gif_softc *sc;
272
273         sc = (struct gif_softc *)arg;
274         if (sc == NULL)
275                 return 0;
276
277         if ((sc->gif_if.if_flags & IFF_UP) == 0)
278                 return 0;
279
280         /* no physical address */
281         if (!sc->gif_psrc || !sc->gif_pdst)
282                 return 0;
283
284         switch (proto) {
285 #ifdef INET
286         case IPPROTO_IPV4:
287                 break;
288 #endif
289 #ifdef INET6
290         case IPPROTO_IPV6:
291                 break;
292 #endif
293         default:
294                 return 0;
295         }
296
297         /* Bail on short packets */
298         if (m->m_pkthdr.len < sizeof(ip))
299                 return 0;
300
301         m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
302
303         switch (ip.ip_v) {
304 #ifdef INET
305         case 4:
306                 if (sc->gif_psrc->sa_family != AF_INET ||
307                     sc->gif_pdst->sa_family != AF_INET)
308                         return 0;
309                 return gif_encapcheck4(m, off, proto, arg);
310 #endif
311 #ifdef INET6
312         case 6:
313                 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
314                         return 0;
315                 if (sc->gif_psrc->sa_family != AF_INET6 ||
316                     sc->gif_pdst->sa_family != AF_INET6)
317                         return 0;
318                 return gif_encapcheck6(m, off, proto, arg);
319 #endif
320         default:
321                 return 0;
322         }
323 }
324
325 /*
326  * Parameters:
327  *      rt:     added in net2
328  */
329 static int
330 gif_output_serialized(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
331                       struct rtentry *rt)
332 {
333         struct gif_softc *sc = (struct gif_softc*)ifp;
334         int error = 0;
335         static int called = 0;  /* XXX: MUTEX */
336
337         /*
338          * gif may cause infinite recursion calls when misconfigured.
339          * We'll prevent this by introducing upper limit.
340          * XXX: this mechanism may introduce another problem about
341          *      mutual exclusion of the variable CALLED, especially if we
342          *      use kernel thread.
343          */
344         if (++called > max_gif_nesting) {
345                 log(LOG_NOTICE,
346                     "gif_output: recursively called too many times(%d)\n",
347                     called);
348                 m_freem(m);
349                 error = EIO;    /* is there better errno? */
350                 goto end;
351         }
352
353         m->m_flags &= ~(M_BCAST|M_MCAST);
354         if (!(ifp->if_flags & IFF_UP) ||
355             sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
356                 m_freem(m);
357                 error = ENETDOWN;
358                 goto end;
359         }
360
361         if (ifp->if_bpf) {
362                 bpf_gettoken();
363                 if (ifp->if_bpf) {
364                         /*
365                          * We need to prepend the address family as
366                          * a four byte field.
367                          */
368                         uint32_t af = dst->sa_family;
369
370                         bpf_ptap(ifp->if_bpf, m, &af, sizeof(af));
371                 }
372                 bpf_reltoken();
373         }
374         IFNET_STAT_INC(ifp, opackets, 1);       
375         IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
376
377         /* inner AF-specific encapsulation */
378
379         /* XXX should we check if our outer source is legal? */
380
381         /* dispatch to output logic based on outer AF */
382         switch (sc->gif_psrc->sa_family) {
383 #ifdef INET
384         case AF_INET:
385                 error = in_gif_output(ifp, dst->sa_family, m);
386                 break;
387 #endif
388 #ifdef INET6
389         case AF_INET6:
390                 error = in6_gif_output(ifp, dst->sa_family, m);
391                 break;
392 #endif
393         default:
394                 m_freem(m);             
395                 error = ENETDOWN;
396                 goto end;
397         }
398
399   end:
400         called = 0;             /* reset recursion counter */
401         if (error)
402                 IFNET_STAT_INC(ifp, oerrors, 1);
403         return error;
404 }
405
406 int
407 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
408            struct rtentry *rt)
409 {
410         struct ifaltq_subque *ifsq = ifq_get_subq_default(&ifp->if_snd);
411         int error;
412
413         ASSERT_NETISR_NCPUS(mycpuid);
414
415         ifsq_serialize_hw(ifsq);
416         error = gif_output_serialized(ifp, m, dst, rt);
417         ifsq_deserialize_hw(ifsq);
418         return error;
419 }
420
421 void
422 gif_input(struct mbuf *m, int af, struct ifnet *ifp)
423 {
424         int isr;
425
426         if (ifp == NULL) {
427                 /* just in case */
428                 m_freem(m);
429                 return;
430         }
431
432         m->m_pkthdr.rcvif = ifp;
433         
434         if (ifp->if_bpf) {
435                 bpf_gettoken();
436                 if (ifp->if_bpf) {
437                         /*
438                          * We need to prepend the address family as
439                          * a four byte field.
440                          */
441                         uint32_t af1 = af;
442
443                         bpf_ptap(ifp->if_bpf, m, &af1, sizeof(af1));
444                 }
445                 bpf_reltoken();
446         }
447
448         /*
449          * Put the packet to the network layer input queue according to the
450          * specified address family.
451          * Note: older versions of gif_input directly called network layer
452          * input functions, e.g. ip6_input, here.  We changed the policy to
453          * prevent too many recursive calls of such input functions, which
454          * might cause kernel panic.  But the change may introduce another
455          * problem; if the input queue is full, packets are discarded.
456          * The kernel stack overflow really happened, and we believed
457          * queue-full rarely occurs, so we changed the policy.
458          */
459         switch (af) {
460 #ifdef INET
461         case AF_INET:
462                 isr = NETISR_IP;
463                 break;
464 #endif
465 #ifdef INET6
466         case AF_INET6:
467                 isr = NETISR_IPV6;
468                 break;
469 #endif
470         default:
471                 m_freem(m);
472                 return;
473         }
474
475         IFNET_STAT_INC(ifp, ipackets, 1);
476         IFNET_STAT_INC(ifp, ibytes, m->m_pkthdr.len);
477         m->m_flags &= ~M_HASH;
478         netisr_queue(isr, m);
479
480         return;
481 }
482
483 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
484 int
485 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
486 {
487         struct gif_softc *sc  = (struct gif_softc*)ifp;
488         struct ifreq     *ifr = (struct ifreq*)data;
489         int error = 0, size;
490         struct sockaddr *dst, *src;
491 #ifdef  SIOCSIFMTU /* xxx */
492         u_long mtu;
493 #endif
494
495         switch (cmd) {
496         case SIOCSIFADDR:
497                 ifp->if_flags |= IFF_UP;
498                 break;
499                 
500         case SIOCSIFDSTADDR:
501                 break;
502
503         case SIOCADDMULTI:
504         case SIOCDELMULTI:
505                 break;
506
507 #ifdef  SIOCSIFMTU /* xxx */
508         case SIOCGIFMTU:
509                 break;
510
511         case SIOCSIFMTU:
512                 mtu = ifr->ifr_mtu;
513                 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
514                         return (EINVAL);
515                 ifp->if_mtu = mtu;
516                 break;
517 #endif /* SIOCSIFMTU */
518
519 #ifdef INET
520         case SIOCSIFPHYADDR:
521 #endif
522 #ifdef INET6
523         case SIOCSIFPHYADDR_IN6:
524 #endif /* INET6 */
525         case SIOCSLIFPHYADDR:
526                 switch (cmd) {
527 #ifdef INET
528                 case SIOCSIFPHYADDR:
529                         src = (struct sockaddr *)
530                                 &(((struct in_aliasreq *)data)->ifra_addr);
531                         dst = (struct sockaddr *)
532                                 &(((struct in_aliasreq *)data)->ifra_dstaddr);
533                         break;
534 #endif
535 #ifdef INET6
536                 case SIOCSIFPHYADDR_IN6:
537                         src = (struct sockaddr *)
538                                 &(((struct in6_aliasreq *)data)->ifra_addr);
539                         dst = (struct sockaddr *)
540                                 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
541                         break;
542 #endif
543                 case SIOCSLIFPHYADDR:
544                         src = (struct sockaddr *)
545                                 &(((struct if_laddrreq *)data)->addr);
546                         dst = (struct sockaddr *)
547                                 &(((struct if_laddrreq *)data)->dstaddr);
548                         break;
549                 default:
550                         return EINVAL;
551                 }
552
553                 /* sa_family must be equal */
554                 if (src->sa_family != dst->sa_family)
555                         return EINVAL;
556
557                 /* validate sa_len */
558                 switch (src->sa_family) {
559 #ifdef INET
560                 case AF_INET:
561                         if (src->sa_len != sizeof(struct sockaddr_in))
562                                 return EINVAL;
563                         break;
564 #endif
565 #ifdef INET6
566                 case AF_INET6:
567                         if (src->sa_len != sizeof(struct sockaddr_in6))
568                                 return EINVAL;
569                         break;
570 #endif
571                 default:
572                         return EAFNOSUPPORT;
573                 }
574                 switch (dst->sa_family) {
575 #ifdef INET
576                 case AF_INET:
577                         if (dst->sa_len != sizeof(struct sockaddr_in))
578                                 return EINVAL;
579                         break;
580 #endif
581 #ifdef INET6
582                 case AF_INET6:
583                         if (dst->sa_len != sizeof(struct sockaddr_in6))
584                                 return EINVAL;
585                         break;
586 #endif
587                 default:
588                         return EAFNOSUPPORT;
589                 }
590
591                 /* check sa_family looks sane for the cmd */
592                 switch (cmd) {
593                 case SIOCSIFPHYADDR:
594                         if (src->sa_family == AF_INET)
595                                 break;
596                         return EAFNOSUPPORT;
597 #ifdef INET6
598                 case SIOCSIFPHYADDR_IN6:
599                         if (src->sa_family == AF_INET6)
600                                 break;
601                         return EAFNOSUPPORT;
602 #endif /* INET6 */
603                 case SIOCSLIFPHYADDR:
604                         /* checks done in the above */
605                         break;
606                 }
607
608                 error = gif_set_tunnel(&sc->gif_if, src, dst);
609                 break;
610
611 #ifdef SIOCDIFPHYADDR
612         case SIOCDIFPHYADDR:
613                 gif_delete_tunnel(&sc->gif_if);
614                 break;
615 #endif
616                         
617         case SIOCGIFPSRCADDR:
618 #ifdef INET6
619         case SIOCGIFPSRCADDR_IN6:
620 #endif /* INET6 */
621                 if (sc->gif_psrc == NULL) {
622                         error = EADDRNOTAVAIL;
623                         goto bad;
624                 }
625                 src = sc->gif_psrc;
626                 switch (cmd) {
627 #ifdef INET
628                 case SIOCGIFPSRCADDR:
629                         dst = &ifr->ifr_addr;
630                         size = sizeof(ifr->ifr_addr);
631                         break;
632 #endif /* INET */
633 #ifdef INET6
634                 case SIOCGIFPSRCADDR_IN6:
635                         dst = (struct sockaddr *)
636                                 &(((struct in6_ifreq *)data)->ifr_addr);
637                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
638                         break;
639 #endif /* INET6 */
640                 default:
641                         error = EADDRNOTAVAIL;
642                         goto bad;
643                 }
644                 if (src->sa_len > size)
645                         return EINVAL;
646                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
647                 break;
648                         
649         case SIOCGIFPDSTADDR:
650 #ifdef INET6
651         case SIOCGIFPDSTADDR_IN6:
652 #endif /* INET6 */
653                 if (sc->gif_pdst == NULL) {
654                         error = EADDRNOTAVAIL;
655                         goto bad;
656                 }
657                 src = sc->gif_pdst;
658                 switch (cmd) {
659 #ifdef INET
660                 case SIOCGIFPDSTADDR:
661                         dst = &ifr->ifr_addr;
662                         size = sizeof(ifr->ifr_addr);
663                         break;
664 #endif /* INET */
665 #ifdef INET6
666                 case SIOCGIFPDSTADDR_IN6:
667                         dst = (struct sockaddr *)
668                                 &(((struct in6_ifreq *)data)->ifr_addr);
669                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
670                         break;
671 #endif /* INET6 */
672                 default:
673                         error = EADDRNOTAVAIL;
674                         goto bad;
675                 }
676                 if (src->sa_len > size)
677                         return EINVAL;
678                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
679                 break;
680
681         case SIOCGLIFPHYADDR:
682                 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
683                         error = EADDRNOTAVAIL;
684                         goto bad;
685                 }
686
687                 /* copy src */
688                 src = sc->gif_psrc;
689                 dst = (struct sockaddr *)
690                         &(((struct if_laddrreq *)data)->addr);
691                 size = sizeof(((struct if_laddrreq *)data)->addr);
692                 if (src->sa_len > size)
693                         return EINVAL;
694                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
695
696                 /* copy dst */
697                 src = sc->gif_pdst;
698                 dst = (struct sockaddr *)
699                         &(((struct if_laddrreq *)data)->dstaddr);
700                 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
701                 if (src->sa_len > size)
702                         return EINVAL;
703                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
704                 break;
705
706         case SIOCSIFFLAGS:
707                 /* if_ioctl() takes care of it */
708                 break;
709
710         default:
711                 error = EINVAL;
712                 break;
713         }
714  bad:
715         return error;
716 }
717
718 int
719 gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
720 {
721         struct gif_softc *sc = (struct gif_softc *)ifp;
722         struct gif_softc *sc2;
723         struct sockaddr *osrc, *odst, *sa;
724         int error = 0; 
725
726         crit_enter();
727
728         LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
729                 if (sc2 == sc)
730                         continue;
731                 if (!sc2->gif_pdst || !sc2->gif_psrc)
732                         continue;
733                 if (sc2->gif_pdst->sa_family != dst->sa_family ||
734                     sc2->gif_pdst->sa_len != dst->sa_len ||
735                     sc2->gif_psrc->sa_family != src->sa_family ||
736                     sc2->gif_psrc->sa_len != src->sa_len)
737                         continue;
738
739                 /*
740                  * Disallow parallel tunnels unless instructed
741                  * otherwise.
742                  */
743                 if (!parallel_tunnels &&
744                     bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
745                     bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
746                         error = EADDRNOTAVAIL;
747                         goto bad;
748                 }
749
750                 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
751         }
752
753         /* XXX we can detach from both, but be polite just in case */
754         if (sc->gif_psrc) {
755                 switch (sc->gif_psrc->sa_family) {
756 #ifdef INET
757                 case AF_INET:
758                         in_gif_detach(sc);
759                         break;
760 #endif
761 #ifdef INET6
762                 case AF_INET6:
763                         in6_gif_detach(sc);
764                         break;
765 #endif
766                 }
767                 gif_clear_cache(sc);
768         }
769
770         osrc = sc->gif_psrc;
771         sa = (struct sockaddr *)kmalloc(src->sa_len, M_IFADDR, M_WAITOK);
772         bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
773         sc->gif_psrc = sa;
774
775         odst = sc->gif_pdst;
776         sa = (struct sockaddr *)kmalloc(dst->sa_len, M_IFADDR, M_WAITOK);
777         bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
778         sc->gif_pdst = sa;
779
780         switch (sc->gif_psrc->sa_family) {
781 #ifdef INET
782         case AF_INET:
783                 error = in_gif_attach(sc);
784                 break;
785 #endif
786 #ifdef INET6
787         case AF_INET6:
788                 error = in6_gif_attach(sc);
789                 break;
790 #endif
791         }
792         if (error) {
793                 /* rollback */
794                 kfree((caddr_t)sc->gif_psrc, M_IFADDR);
795                 kfree((caddr_t)sc->gif_pdst, M_IFADDR);
796                 sc->gif_psrc = osrc;
797                 sc->gif_pdst = odst;
798                 goto bad;
799         }
800
801         if (osrc)
802                 kfree((caddr_t)osrc, M_IFADDR);
803         if (odst)
804                 kfree((caddr_t)odst, M_IFADDR);
805
806         if (sc->gif_psrc && sc->gif_pdst)
807                 ifp->if_flags |= IFF_RUNNING;
808         else
809                 ifp->if_flags &= ~IFF_RUNNING;
810         crit_exit();
811
812         return 0;
813
814  bad:
815         if (sc->gif_psrc && sc->gif_pdst)
816                 ifp->if_flags |= IFF_RUNNING;
817         else
818                 ifp->if_flags &= ~IFF_RUNNING;
819         crit_exit();
820
821         return error;
822 }
823
824 void
825 gif_delete_tunnel(struct ifnet *ifp)
826 {
827         struct gif_softc *sc = (struct gif_softc *)ifp;
828
829         crit_enter();
830
831         if (sc->gif_psrc) {
832                 kfree((caddr_t)sc->gif_psrc, M_IFADDR);
833                 sc->gif_psrc = NULL;
834         }
835         if (sc->gif_pdst) {
836                 kfree((caddr_t)sc->gif_pdst, M_IFADDR);
837                 sc->gif_pdst = NULL;
838         }
839         /* it is safe to detach from both */
840 #ifdef INET
841         in_gif_detach(sc);
842 #endif
843 #ifdef INET6
844         in6_gif_detach(sc);
845 #endif
846         gif_clear_cache(sc);
847
848         if (sc->gif_psrc && sc->gif_pdst)
849                 ifp->if_flags |= IFF_RUNNING;
850         else
851                 ifp->if_flags &= ~IFF_RUNNING;
852         crit_exit();
853 }