source: rtems-libbsd/freebsd/sys/net/if_gif.c @ 549488b

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 549488b was 549488b, checked in by Sebastian Huber <sebastian.huber@…>, on 10/10/13 at 12:45:09

Disable alternative routing tables

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