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