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