]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_gif.c
This commit was generated by cvs2svn to compensate for changes in r161351,
[FreeBSD/FreeBSD.git] / sys / net / if_gif.c
1 /*      $FreeBSD$       */
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/module.h>
44 #include <sys/socket.h>
45 #include <sys/sockio.h>
46 #include <sys/errno.h>
47 #include <sys/time.h>
48 #include <sys/sysctl.h>
49 #include <sys/syslog.h>
50 #include <sys/protosw.h>
51 #include <sys/conf.h>
52 #include <machine/cpu.h>
53
54 #include <net/if.h>
55 #include <net/if_clone.h>
56 #include <net/if_types.h>
57 #include <net/netisr.h>
58 #include <net/route.h>
59 #include <net/bpf.h>
60
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #ifdef  INET
65 #include <netinet/in_var.h>
66 #include <netinet/in_gif.h>
67 #include <netinet/ip_var.h>
68 #endif  /* INET */
69
70 #ifdef INET6
71 #ifndef INET
72 #include <netinet/in.h>
73 #endif
74 #include <netinet6/in6_var.h>
75 #include <netinet/ip6.h>
76 #include <netinet6/ip6_var.h>
77 #include <netinet6/scope6_var.h>
78 #include <netinet6/in6_gif.h>
79 #include <netinet6/ip6protosw.h>
80 #endif /* INET6 */
81
82 #include <netinet/ip_encap.h>
83 #include <net/ethernet.h>
84 #include <net/if_bridgevar.h>
85 #include <net/if_gif.h>
86
87 #define GIFNAME         "gif"
88
89 /*
90  * gif_mtx protects the global gif_softc_list.
91  */
92 static struct mtx gif_mtx;
93 static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
94 static LIST_HEAD(, gif_softc) gif_softc_list;
95
96 void    (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
97 void    (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
98 void    (*ng_gif_attach_p)(struct ifnet *ifp);
99 void    (*ng_gif_detach_p)(struct ifnet *ifp);
100
101 static void     gif_start(struct ifnet *);
102 static int      gif_clone_create(struct if_clone *, int, caddr_t);
103 static void     gif_clone_destroy(struct ifnet *);
104
105 IFC_SIMPLE_DECLARE(gif, 0);
106
107 static int gifmodevent(module_t, int, void *);
108
109 SYSCTL_DECL(_net_link);
110 SYSCTL_NODE(_net_link, IFT_GIF, gif, CTLFLAG_RW, 0,
111     "Generic Tunnel Interface");
112 #ifndef MAX_GIF_NEST
113 /*
114  * This macro controls the default upper limitation on nesting of gif tunnels.
115  * Since, setting a large value to this macro with a careless configuration
116  * may introduce system crash, we don't allow any nestings by default.
117  * If you need to configure nested gif tunnels, you can define this macro
118  * in your kernel configuration file.  However, if you do so, please be
119  * careful to configure the tunnels so that it won't make a loop.
120  */
121 #define MAX_GIF_NEST 1
122 #endif
123 static int max_gif_nesting = MAX_GIF_NEST;
124 SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW,
125     &max_gif_nesting, 0, "Max nested tunnels");
126
127 /*
128  * By default, we disallow creation of multiple tunnels between the same
129  * pair of addresses.  Some applications require this functionality so
130  * we allow control over this check here.
131  */
132 #ifdef XBONEHACK
133 static int parallel_tunnels = 1;
134 #else
135 static int parallel_tunnels = 0;
136 #endif
137 SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW,
138     &parallel_tunnels, 0, "Allow parallel tunnels?");
139
140 static int
141 gif_clone_create(ifc, unit, params)
142         struct if_clone *ifc;
143         int unit;
144         caddr_t params;
145 {
146         struct gif_softc *sc;
147
148         sc = malloc(sizeof(struct gif_softc), M_GIF, M_WAITOK | M_ZERO);
149         GIF2IFP(sc) = if_alloc(IFT_GIF);
150         if (GIF2IFP(sc) == NULL) {
151                 free(sc, M_GIF);
152                 return (ENOSPC);
153         }
154
155         GIF_LOCK_INIT(sc);
156
157         GIF2IFP(sc)->if_softc = sc;
158         if_initname(GIF2IFP(sc), ifc->ifc_name, unit);
159
160         sc->encap_cookie4 = sc->encap_cookie6 = NULL;
161
162         GIF2IFP(sc)->if_addrlen = 0;
163         GIF2IFP(sc)->if_mtu    = GIF_MTU;
164         GIF2IFP(sc)->if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
165 #if 0
166         /* turn off ingress filter */
167         GIF2IFP(sc)->if_flags  |= IFF_LINK2;
168 #endif
169         GIF2IFP(sc)->if_ioctl  = gif_ioctl;
170         GIF2IFP(sc)->if_start  = gif_start;
171         GIF2IFP(sc)->if_output = gif_output;
172         GIF2IFP(sc)->if_snd.ifq_maxlen = IFQ_MAXLEN;
173         if_attach(GIF2IFP(sc));
174         bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
175         if (ng_gif_attach_p != NULL)
176                 (*ng_gif_attach_p)(GIF2IFP(sc));
177
178         mtx_lock(&gif_mtx);
179         LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
180         mtx_unlock(&gif_mtx);
181
182         return (0);
183 }
184
185 static void
186 gif_clone_destroy(ifp)
187         struct ifnet *ifp;
188 {
189         int err;
190         struct gif_softc *sc = ifp->if_softc;
191
192         mtx_lock(&gif_mtx);
193         LIST_REMOVE(sc, gif_list);
194         mtx_unlock(&gif_mtx);
195
196         gif_delete_tunnel(ifp);
197 #ifdef INET6
198         if (sc->encap_cookie6 != NULL) {
199                 err = encap_detach(sc->encap_cookie6);
200                 KASSERT(err == 0, ("Unexpected error detaching encap_cookie6"));
201         }
202 #endif
203 #ifdef INET
204         if (sc->encap_cookie4 != NULL) {
205                 err = encap_detach(sc->encap_cookie4);
206                 KASSERT(err == 0, ("Unexpected error detaching encap_cookie4"));
207         }
208 #endif
209
210         if (ng_gif_detach_p != NULL)
211                 (*ng_gif_detach_p)(ifp);
212         bpfdetach(ifp);
213         if_detach(ifp);
214         if_free(ifp);
215
216         GIF_LOCK_DESTROY(sc);
217
218         free(sc, M_GIF);
219 }
220
221 static int
222 gifmodevent(mod, type, data)
223         module_t mod;
224         int type;
225         void *data;
226 {
227
228         switch (type) {
229         case MOD_LOAD:
230                 mtx_init(&gif_mtx, "gif_mtx", NULL, MTX_DEF);
231                 LIST_INIT(&gif_softc_list);
232                 if_clone_attach(&gif_cloner);
233
234 #ifdef INET6
235                 ip6_gif_hlim = GIF_HLIM;
236 #endif
237
238                 break;
239         case MOD_UNLOAD:
240                 if_clone_detach(&gif_cloner);
241                 mtx_destroy(&gif_mtx);
242 #ifdef INET6
243                 ip6_gif_hlim = 0;
244 #endif
245                 break;
246         default:
247                 return EOPNOTSUPP;
248         }
249         return 0;
250 }
251
252 static moduledata_t gif_mod = {
253         "if_gif",
254         gifmodevent,
255         0
256 };
257
258 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
259 MODULE_VERSION(if_gif, 1);
260
261 int
262 gif_encapcheck(m, off, proto, arg)
263         const struct mbuf *m;
264         int off;
265         int proto;
266         void *arg;
267 {
268         struct ip ip;
269         struct gif_softc *sc;
270
271         sc = (struct gif_softc *)arg;
272         if (sc == NULL)
273                 return 0;
274
275         if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0)
276                 return 0;
277
278         /* no physical address */
279         if (!sc->gif_psrc || !sc->gif_pdst)
280                 return 0;
281
282         switch (proto) {
283 #ifdef INET
284         case IPPROTO_IPV4:
285                 break;
286 #endif
287 #ifdef INET6
288         case IPPROTO_IPV6:
289                 break;
290 #endif
291         case IPPROTO_ETHERIP:
292                 break;
293
294         default:
295                 return 0;
296         }
297
298         /* Bail on short packets */
299         if (m->m_pkthdr.len < sizeof(ip))
300                 return 0;
301
302         m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
303
304         switch (ip.ip_v) {
305 #ifdef INET
306         case 4:
307                 if (sc->gif_psrc->sa_family != AF_INET ||
308                     sc->gif_pdst->sa_family != AF_INET)
309                         return 0;
310                 return gif_encapcheck4(m, off, proto, arg);
311 #endif
312 #ifdef INET6
313         case 6:
314                 if (m->m_pkthdr.len < sizeof(struct ip6_hdr))
315                         return 0;
316                 if (sc->gif_psrc->sa_family != AF_INET6 ||
317                     sc->gif_pdst->sa_family != AF_INET6)
318                         return 0;
319                 return gif_encapcheck6(m, off, proto, arg);
320 #endif
321         default:
322                 return 0;
323         }
324 }
325
326 static void
327 gif_start(struct ifnet *ifp)
328 {
329         struct gif_softc *sc;
330         struct mbuf *m;
331
332         sc = ifp->if_softc;
333
334         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
335         for (;;) {
336                 IFQ_DEQUEUE(&ifp->if_snd, m);
337                 if (m == 0)
338                         break;
339
340                 gif_output(ifp, m, sc->gif_pdst, NULL);
341
342         }
343         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
344
345         return;
346 }
347
348 int
349 gif_output(ifp, m, dst, rt)
350         struct ifnet *ifp;
351         struct mbuf *m;
352         struct sockaddr *dst;
353         struct rtentry *rt;     /* added in net2 */
354 {
355         struct gif_softc *sc = ifp->if_softc;
356         struct m_tag *mtag;
357         int error = 0;
358         int gif_called;
359         u_int32_t af;
360
361 #ifdef MAC
362         error = mac_check_ifnet_transmit(ifp, m);
363         if (error) {
364                 m_freem(m);
365                 goto end;
366         }
367 #endif
368
369         /*
370          * gif may cause infinite recursion calls when misconfigured.
371          * We'll prevent this by detecting loops.
372          *
373          * High nesting level may cause stack exhaustion.
374          * We'll prevent this by introducing upper limit.
375          */
376         gif_called = 1;
377         mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, NULL);
378         while (mtag != NULL) {
379                 if (*(struct ifnet **)(mtag + 1) == ifp) {
380                         log(LOG_NOTICE,
381                             "gif_output: loop detected on %s\n",
382                             (*(struct ifnet **)(mtag + 1))->if_xname);
383                         m_freem(m);
384                         error = EIO;    /* is there better errno? */
385                         goto end;
386                 }
387                 mtag = m_tag_locate(m, MTAG_GIF, MTAG_GIF_CALLED, mtag);
388                 gif_called++;
389         }
390         if (gif_called > max_gif_nesting) {
391                 log(LOG_NOTICE,
392                     "gif_output: recursively called too many times(%d)\n",
393                     gif_called);
394                 m_freem(m);
395                 error = EIO;    /* is there better errno? */
396                 goto end;
397         }
398         mtag = m_tag_alloc(MTAG_GIF, MTAG_GIF_CALLED, sizeof(struct ifnet *),
399             M_NOWAIT);
400         if (mtag == NULL) {
401                 m_freem(m);
402                 error = ENOMEM;
403                 goto end;
404         }
405         *(struct ifnet **)(mtag + 1) = ifp;
406         m_tag_prepend(m, mtag);
407
408         m->m_flags &= ~(M_BCAST|M_MCAST);
409
410         GIF_LOCK(sc);
411
412         if (!(ifp->if_flags & IFF_UP) ||
413             sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
414                 GIF_UNLOCK(sc);
415                 m_freem(m);
416                 error = ENETDOWN;
417                 goto end;
418         }
419
420         /* BPF writes need to be handled specially. */
421         if (dst->sa_family == AF_UNSPEC) {
422                 bcopy(dst->sa_data, &af, sizeof(af));
423                 dst->sa_family = af;
424         }
425
426         af = dst->sa_family;
427         BPF_MTAP2(ifp, &af, sizeof(af), m);
428         ifp->if_opackets++;     
429         ifp->if_obytes += m->m_pkthdr.len;
430
431         /* override to IPPROTO_ETHERIP for bridged traffic */
432         if (ifp->if_bridge)
433                 af = AF_LINK;
434
435         /* inner AF-specific encapsulation */
436
437         /* XXX should we check if our outer source is legal? */
438
439         /* dispatch to output logic based on outer AF */
440         switch (sc->gif_psrc->sa_family) {
441 #ifdef INET
442         case AF_INET:
443                 error = in_gif_output(ifp, af, m);
444                 break;
445 #endif
446 #ifdef INET6
447         case AF_INET6:
448                 error = in6_gif_output(ifp, af, m);
449                 break;
450 #endif
451         default:
452                 m_freem(m);             
453                 error = ENETDOWN;
454         }
455
456         GIF_UNLOCK(sc);
457   end:
458         if (error)
459                 ifp->if_oerrors++;
460         return (error);
461 }
462
463 void
464 gif_input(m, af, ifp)
465         struct mbuf *m;
466         int af;
467         struct ifnet *ifp;
468 {
469         int isr, n;
470         struct etherip_header *eip;
471
472         if (ifp == NULL) {
473                 /* just in case */
474                 m_freem(m);
475                 return;
476         }
477
478         m->m_pkthdr.rcvif = ifp;
479
480 #ifdef MAC
481         mac_create_mbuf_from_ifnet(ifp, m);
482 #endif
483
484         if (bpf_peers_present(ifp->if_bpf)) {
485                 u_int32_t af1 = af;
486                 bpf_mtap2(ifp->if_bpf, &af1, sizeof(af1), m);
487         }
488
489         if (ng_gif_input_p != NULL) {
490                 (*ng_gif_input_p)(ifp, &m, af);
491                 if (m == NULL)
492                         return;
493         }
494
495         /*
496          * Put the packet to the network layer input queue according to the
497          * specified address family.
498          * Note: older versions of gif_input directly called network layer
499          * input functions, e.g. ip6_input, here.  We changed the policy to
500          * prevent too many recursive calls of such input functions, which
501          * might cause kernel panic.  But the change may introduce another
502          * problem; if the input queue is full, packets are discarded.
503          * The kernel stack overflow really happened, and we believed
504          * queue-full rarely occurs, so we changed the policy.
505          */
506         switch (af) {
507 #ifdef INET
508         case AF_INET:
509                 isr = NETISR_IP;
510                 break;
511 #endif
512 #ifdef INET6
513         case AF_INET6:
514                 isr = NETISR_IPV6;
515                 break;
516 #endif
517         case AF_LINK:
518                 n = sizeof(struct etherip_header) + sizeof(struct ether_header);
519                 if (n > m->m_len) {
520                         m = m_pullup(m, n);
521                         if (m == NULL) {
522                                 ifp->if_ierrors++;
523                                 return;
524                         }
525                 }
526
527                 eip = mtod(m, struct etherip_header *);
528                 if (eip->eip_ver !=
529                     (ETHERIP_VERSION & ETHERIP_VER_VERS_MASK)) {
530                         /* discard unknown versions */
531                         m_freem(m);
532                         return;
533                 }
534                 m_adj(m, sizeof(struct etherip_header));
535
536                 m->m_flags &= ~(M_BCAST|M_MCAST);
537                 m->m_pkthdr.rcvif = ifp;
538
539                 if (ifp->if_bridge)
540                         BRIDGE_INPUT(ifp, m);
541                 
542                 if (m != NULL)
543                         m_freem(m);
544                 return;
545
546         default:
547                 if (ng_gif_input_orphan_p != NULL)
548                         (*ng_gif_input_orphan_p)(ifp, m, af);
549                 else
550                         m_freem(m);
551                 return;
552         }
553
554         ifp->if_ipackets++;
555         ifp->if_ibytes += m->m_pkthdr.len;
556         netisr_dispatch(isr, m);
557 }
558
559 /* XXX how should we handle IPv6 scope on SIOC[GS]IFPHYADDR? */
560 int
561 gif_ioctl(ifp, cmd, data)
562         struct ifnet *ifp;
563         u_long cmd;
564         caddr_t data;
565 {
566         struct gif_softc *sc  = ifp->if_softc;
567         struct ifreq     *ifr = (struct ifreq*)data;
568         int error = 0, size;
569         struct sockaddr *dst, *src;
570 #ifdef  SIOCSIFMTU /* xxx */
571         u_long mtu;
572 #endif
573
574         switch (cmd) {
575         case SIOCSIFADDR:
576                 ifp->if_flags |= IFF_UP;
577                 break;
578                 
579         case SIOCSIFDSTADDR:
580                 break;
581
582         case SIOCADDMULTI:
583         case SIOCDELMULTI:
584                 break;
585
586 #ifdef  SIOCSIFMTU /* xxx */
587         case SIOCGIFMTU:
588                 break;
589
590         case SIOCSIFMTU:
591                 mtu = ifr->ifr_mtu;
592                 if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX)
593                         return (EINVAL);
594                 ifp->if_mtu = mtu;
595                 break;
596 #endif /* SIOCSIFMTU */
597
598 #ifdef INET
599         case SIOCSIFPHYADDR:
600 #endif
601 #ifdef INET6
602         case SIOCSIFPHYADDR_IN6:
603 #endif /* INET6 */
604         case SIOCSLIFPHYADDR:
605                 switch (cmd) {
606 #ifdef INET
607                 case SIOCSIFPHYADDR:
608                         src = (struct sockaddr *)
609                                 &(((struct in_aliasreq *)data)->ifra_addr);
610                         dst = (struct sockaddr *)
611                                 &(((struct in_aliasreq *)data)->ifra_dstaddr);
612                         break;
613 #endif
614 #ifdef INET6
615                 case SIOCSIFPHYADDR_IN6:
616                         src = (struct sockaddr *)
617                                 &(((struct in6_aliasreq *)data)->ifra_addr);
618                         dst = (struct sockaddr *)
619                                 &(((struct in6_aliasreq *)data)->ifra_dstaddr);
620                         break;
621 #endif
622                 case SIOCSLIFPHYADDR:
623                         src = (struct sockaddr *)
624                                 &(((struct if_laddrreq *)data)->addr);
625                         dst = (struct sockaddr *)
626                                 &(((struct if_laddrreq *)data)->dstaddr);
627                         break;
628                 default:
629                         return EINVAL;
630                 }
631
632                 /* sa_family must be equal */
633                 if (src->sa_family != dst->sa_family)
634                         return EINVAL;
635
636                 /* validate sa_len */
637                 switch (src->sa_family) {
638 #ifdef INET
639                 case AF_INET:
640                         if (src->sa_len != sizeof(struct sockaddr_in))
641                                 return EINVAL;
642                         break;
643 #endif
644 #ifdef INET6
645                 case AF_INET6:
646                         if (src->sa_len != sizeof(struct sockaddr_in6))
647                                 return EINVAL;
648                         break;
649 #endif
650                 default:
651                         return EAFNOSUPPORT;
652                 }
653                 switch (dst->sa_family) {
654 #ifdef INET
655                 case AF_INET:
656                         if (dst->sa_len != sizeof(struct sockaddr_in))
657                                 return EINVAL;
658                         break;
659 #endif
660 #ifdef INET6
661                 case AF_INET6:
662                         if (dst->sa_len != sizeof(struct sockaddr_in6))
663                                 return EINVAL;
664                         break;
665 #endif
666                 default:
667                         return EAFNOSUPPORT;
668                 }
669
670                 /* check sa_family looks sane for the cmd */
671                 switch (cmd) {
672                 case SIOCSIFPHYADDR:
673                         if (src->sa_family == AF_INET)
674                                 break;
675                         return EAFNOSUPPORT;
676 #ifdef INET6
677                 case SIOCSIFPHYADDR_IN6:
678                         if (src->sa_family == AF_INET6)
679                                 break;
680                         return EAFNOSUPPORT;
681 #endif /* INET6 */
682                 case SIOCSLIFPHYADDR:
683                         /* checks done in the above */
684                         break;
685                 }
686
687                 error = gif_set_tunnel(GIF2IFP(sc), src, dst);
688                 break;
689
690 #ifdef SIOCDIFPHYADDR
691         case SIOCDIFPHYADDR:
692                 gif_delete_tunnel(GIF2IFP(sc));
693                 break;
694 #endif
695                         
696         case SIOCGIFPSRCADDR:
697 #ifdef INET6
698         case SIOCGIFPSRCADDR_IN6:
699 #endif /* INET6 */
700                 if (sc->gif_psrc == NULL) {
701                         error = EADDRNOTAVAIL;
702                         goto bad;
703                 }
704                 src = sc->gif_psrc;
705                 switch (cmd) {
706 #ifdef INET
707                 case SIOCGIFPSRCADDR:
708                         dst = &ifr->ifr_addr;
709                         size = sizeof(ifr->ifr_addr);
710                         break;
711 #endif /* INET */
712 #ifdef INET6
713                 case SIOCGIFPSRCADDR_IN6:
714                         dst = (struct sockaddr *)
715                                 &(((struct in6_ifreq *)data)->ifr_addr);
716                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
717                         break;
718 #endif /* INET6 */
719                 default:
720                         error = EADDRNOTAVAIL;
721                         goto bad;
722                 }
723                 if (src->sa_len > size)
724                         return EINVAL;
725                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
726 #ifdef INET6
727                 if (dst->sa_family == AF_INET6) {
728                         error = sa6_recoverscope((struct sockaddr_in6 *)dst);
729                         if (error != 0)
730                                 return (error);
731                 }
732 #endif
733                 break;
734                         
735         case SIOCGIFPDSTADDR:
736 #ifdef INET6
737         case SIOCGIFPDSTADDR_IN6:
738 #endif /* INET6 */
739                 if (sc->gif_pdst == NULL) {
740                         error = EADDRNOTAVAIL;
741                         goto bad;
742                 }
743                 src = sc->gif_pdst;
744                 switch (cmd) {
745 #ifdef INET
746                 case SIOCGIFPDSTADDR:
747                         dst = &ifr->ifr_addr;
748                         size = sizeof(ifr->ifr_addr);
749                         break;
750 #endif /* INET */
751 #ifdef INET6
752                 case SIOCGIFPDSTADDR_IN6:
753                         dst = (struct sockaddr *)
754                                 &(((struct in6_ifreq *)data)->ifr_addr);
755                         size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
756                         break;
757 #endif /* INET6 */
758                 default:
759                         error = EADDRNOTAVAIL;
760                         goto bad;
761                 }
762                 if (src->sa_len > size)
763                         return EINVAL;
764                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
765 #ifdef INET6
766                 if (dst->sa_family == AF_INET6) {
767                         error = sa6_recoverscope((struct sockaddr_in6 *)dst);
768                         if (error != 0)
769                                 return (error);
770                 }
771 #endif
772                 break;
773
774         case SIOCGLIFPHYADDR:
775                 if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
776                         error = EADDRNOTAVAIL;
777                         goto bad;
778                 }
779
780                 /* copy src */
781                 src = sc->gif_psrc;
782                 dst = (struct sockaddr *)
783                         &(((struct if_laddrreq *)data)->addr);
784                 size = sizeof(((struct if_laddrreq *)data)->addr);
785                 if (src->sa_len > size)
786                         return EINVAL;
787                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
788
789                 /* copy dst */
790                 src = sc->gif_pdst;
791                 dst = (struct sockaddr *)
792                         &(((struct if_laddrreq *)data)->dstaddr);
793                 size = sizeof(((struct if_laddrreq *)data)->dstaddr);
794                 if (src->sa_len > size)
795                         return EINVAL;
796                 bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
797                 break;
798
799         case SIOCSIFFLAGS:
800                 /* if_ioctl() takes care of it */
801                 break;
802
803         default:
804                 error = EINVAL;
805                 break;
806         }
807  bad:
808         return error;
809 }
810
811 /*
812  * XXXRW: There's a general event-ordering issue here: the code to check
813  * if a given tunnel is already present happens before we perform a
814  * potentially blocking setup of the tunnel.  This code needs to be
815  * re-ordered so that the check and replacement can be atomic using
816  * a mutex.
817  */
818 int
819 gif_set_tunnel(ifp, src, dst)
820         struct ifnet *ifp;
821         struct sockaddr *src;
822         struct sockaddr *dst;
823 {
824         struct gif_softc *sc = ifp->if_softc;
825         struct gif_softc *sc2;
826         struct sockaddr *osrc, *odst, *sa;
827         int error = 0; 
828
829         mtx_lock(&gif_mtx);
830         LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
831                 if (sc2 == sc)
832                         continue;
833                 if (!sc2->gif_pdst || !sc2->gif_psrc)
834                         continue;
835                 if (sc2->gif_pdst->sa_family != dst->sa_family ||
836                     sc2->gif_pdst->sa_len != dst->sa_len ||
837                     sc2->gif_psrc->sa_family != src->sa_family ||
838                     sc2->gif_psrc->sa_len != src->sa_len)
839                         continue;
840
841                 /*
842                  * Disallow parallel tunnels unless instructed
843                  * otherwise.
844                  */
845                 if (!parallel_tunnels &&
846                     bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
847                     bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
848                         error = EADDRNOTAVAIL;
849                         mtx_unlock(&gif_mtx);
850                         goto bad;
851                 }
852
853                 /* XXX both end must be valid? (I mean, not 0.0.0.0) */
854         }
855         mtx_unlock(&gif_mtx);
856
857         /* XXX we can detach from both, but be polite just in case */
858         if (sc->gif_psrc)
859                 switch (sc->gif_psrc->sa_family) {
860 #ifdef INET
861                 case AF_INET:
862                         (void)in_gif_detach(sc);
863                         break;
864 #endif
865 #ifdef INET6
866                 case AF_INET6:
867                         (void)in6_gif_detach(sc);
868                         break;
869 #endif
870                 }
871
872         osrc = sc->gif_psrc;
873         sa = (struct sockaddr *)malloc(src->sa_len, M_IFADDR, M_WAITOK);
874         bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
875         sc->gif_psrc = sa;
876
877         odst = sc->gif_pdst;
878         sa = (struct sockaddr *)malloc(dst->sa_len, M_IFADDR, M_WAITOK);
879         bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
880         sc->gif_pdst = sa;
881
882         switch (sc->gif_psrc->sa_family) {
883 #ifdef INET
884         case AF_INET:
885                 error = in_gif_attach(sc);
886                 break;
887 #endif
888 #ifdef INET6
889         case AF_INET6:
890                 /*
891                  * Check validity of the scope zone ID of the addresses, and
892                  * convert it into the kernel internal form if necessary.
893                  */
894                 error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_psrc, 0);
895                 if (error != 0)
896                         break;
897                 error = sa6_embedscope((struct sockaddr_in6 *)sc->gif_pdst, 0);
898                 if (error != 0)
899                         break;
900                 error = in6_gif_attach(sc);
901                 break;
902 #endif
903         }
904         if (error) {
905                 /* rollback */
906                 free((caddr_t)sc->gif_psrc, M_IFADDR);
907                 free((caddr_t)sc->gif_pdst, M_IFADDR);
908                 sc->gif_psrc = osrc;
909                 sc->gif_pdst = odst;
910                 goto bad;
911         }
912
913         if (osrc)
914                 free((caddr_t)osrc, M_IFADDR);
915         if (odst)
916                 free((caddr_t)odst, M_IFADDR);
917
918  bad:
919         if (sc->gif_psrc && sc->gif_pdst)
920                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
921         else
922                 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
923
924         return error;
925 }
926
927 void
928 gif_delete_tunnel(ifp)
929         struct ifnet *ifp;
930 {
931         struct gif_softc *sc = ifp->if_softc;
932
933         if (sc->gif_psrc) {
934                 free((caddr_t)sc->gif_psrc, M_IFADDR);
935                 sc->gif_psrc = NULL;
936         }
937         if (sc->gif_pdst) {
938                 free((caddr_t)sc->gif_pdst, M_IFADDR);
939                 sc->gif_pdst = NULL;
940         }
941         /* it is safe to detach from both */
942 #ifdef INET
943         (void)in_gif_detach(sc);
944 #endif
945 #ifdef INET6
946         (void)in6_gif_detach(sc);
947 #endif
948         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
949 }