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