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