The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_mpe.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /* $OpenBSD: if_mpe.c,v 1.14 2008/11/06 20:53:10 michele Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 #include "mpe.h"
   19 
   20 #include <sys/param.h>
   21 #include <sys/systm.h>
   22 #include <sys/mbuf.h>
   23 #include <sys/proc.h>
   24 #include <sys/socket.h>
   25 #include <sys/sockio.h>
   26 #include <sys/ioctl.h>
   27 
   28 #include <net/if.h>
   29 #include <net/if_types.h>
   30 #include <net/netisr.h>
   31 #include <net/route.h>
   32 
   33 #ifdef  INET
   34 #include <netinet/in.h>
   35 #include <netinet/in_var.h>
   36 #include <netinet/in_systm.h>
   37 #include <netinet/ip.h>
   38 #endif
   39 
   40 #ifdef INET6
   41 #include <netinet/ip6.h>
   42 #ifndef INET
   43 #include <netinet/in.h>
   44 #endif
   45 #endif /* INET6 */
   46 
   47 #include "bpfilter.h"
   48 #if NBPFILTER > 0
   49 #include <net/bpf.h>
   50 #endif
   51 
   52 #include <netmpls/mpls.h>
   53 
   54 #ifdef MPLS_DEBUG
   55 #define DPRINTF(x)    do { if (mpedebug) printf x ; } while (0)
   56 #else
   57 #define DPRINTF(x)
   58 #endif
   59 
   60 void    mpeattach(int);
   61 int     mpeoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
   62                        struct rtentry *);
   63 int     mpeioctl(struct ifnet *, u_long, caddr_t);
   64 void    mpestart(struct ifnet *);
   65 int     mpe_clone_create(struct if_clone *, int);
   66 int     mpe_clone_destroy(struct ifnet *);
   67 
   68 LIST_HEAD(, mpe_softc)  mpeif_list;
   69 struct if_clone mpe_cloner =
   70     IF_CLONE_INITIALIZER("mpe", mpe_clone_create, mpe_clone_destroy);
   71 
   72 extern int      mpls_mapttl_ip;
   73 extern int      mpls_mapttl_ip6;
   74 
   75 void
   76 mpeattach(int nmpe)
   77 {
   78         LIST_INIT(&mpeif_list);
   79         if_clone_attach(&mpe_cloner);
   80 }
   81 
   82 int
   83 mpe_clone_create(struct if_clone *ifc, int unit)
   84 {
   85         struct ifnet            *ifp;
   86         struct mpe_softc        *mpeif;
   87         int                      s;
   88 
   89         if ((mpeif = malloc(sizeof(*mpeif),
   90             M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
   91                 return (ENOMEM);
   92 
   93         mpeif->sc_shim.shim_label = MPLS_BOS_MASK | htonl(mpls_defttl);
   94         mpeif->sc_unit = unit;
   95         ifp = &mpeif->sc_if;
   96         snprintf(ifp->if_xname, sizeof ifp->if_xname, "mpe%d", unit);
   97         ifp->if_flags = IFF_POINTOPOINT;
   98         ifp->if_softc = mpeif;
   99         ifp->if_mtu = MPE_MTU;
  100         ifp->if_ioctl = mpeioctl;
  101         ifp->if_output = mpeoutput;
  102         ifp->if_start = mpestart;
  103         ifp->if_type = IFT_MPLS;
  104         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  105         ifp->if_hdrlen = MPE_HDRLEN;
  106         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
  107         IFQ_SET_READY(&ifp->if_snd);
  108         if_attach(ifp);
  109         if_alloc_sadl(ifp);
  110 #if NBPFILTER > 0
  111         bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, MPE_HDRLEN);
  112 #endif
  113 
  114         s = splnet();
  115         LIST_INSERT_HEAD(&mpeif_list, mpeif, sc_list);
  116         splx(s);
  117 
  118         return (0);
  119 }
  120 
  121 int
  122 mpe_clone_destroy(struct ifnet *ifp)
  123 {
  124         struct mpe_softc        *mpeif = ifp->if_softc;
  125         int                      s;
  126 
  127         s = splnet();
  128         LIST_REMOVE(mpeif, sc_list);
  129         splx(s);
  130 
  131 #if NBPFILTER > 0
  132         bpfdetach(ifp);
  133 #endif
  134         if_detach(ifp);
  135         free(mpeif, M_DEVBUF);
  136         return (0);
  137 }
  138 
  139 /*
  140  * Start output on the mpe interface.
  141  */
  142 void
  143 mpestart(struct ifnet *ifp)
  144 {
  145         struct mbuf             *m;
  146         struct mpe_softc        *ifm;
  147         struct shim_hdr          shim;
  148         int                      s;
  149 
  150         for (;;) {
  151                 s = splnet();
  152                 IFQ_DEQUEUE(&ifp->if_snd, m);
  153                 splx(s);
  154 
  155                 if (m == NULL)
  156                         return;
  157 
  158 #if NBPFILTER > 0
  159                 if (ifp->if_bpf)
  160                         bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_OUT);
  161 #endif
  162                 ifm = ifp->if_softc;
  163                 shim.shim_label = ifm->sc_shim.shim_label;
  164                 M_PREPEND(m, sizeof(shim), M_DONTWAIT);
  165                 m_copyback(m, 0, sizeof(shim), (caddr_t)&shim);
  166                 if (m == NULL) {
  167                         ifp->if_ierrors++;
  168                         continue;
  169                 }
  170                 m->m_pkthdr.rcvif = ifp;
  171                 mpls_output(m);
  172         }
  173 }
  174 
  175 int
  176 mpeoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  177         struct rtentry *rt)
  178 {
  179         int     s;
  180         int     error;
  181 
  182         error = 0;
  183         switch (dst->sa_family) {
  184         case AF_INET:
  185                 break;
  186         case AF_MPLS:
  187                 /*
  188                  * drop MPLS packets entering here. This is a hack to prevent
  189                  * loops because of misconfiguration.
  190                  */
  191                 m_freem(m);
  192                 error = ENETUNREACH;
  193                 return (error);
  194         default:
  195                 error = ENETDOWN;
  196                 goto out;
  197         }
  198         s = splnet();
  199         IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
  200         if (error) {
  201                 /* mbuf is already freed */
  202                 splx(s);
  203                 return (error);
  204         }
  205         if_start(ifp);
  206         splx(s);
  207 out:
  208         if (error)
  209                 ifp->if_oerrors++;
  210         return (error);
  211 }
  212 
  213 /* ARGSUSED */
  214 int
  215 mpeioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  216 {
  217         int                      error;
  218         struct mpe_softc        *ifm;
  219         struct ifreq            *ifr;
  220         struct shim_hdr          shim;
  221         u_int32_t                ttl = htonl(mpls_defttl);
  222 
  223         ifr = (struct ifreq *)data;
  224         error = 0;
  225         switch (cmd) {
  226         case SIOCSIFADDR:
  227                 ifp->if_flags |= IFF_UP;
  228                 break;
  229         case SIOCSIFFLAGS:
  230                 if (ifp->if_flags & IFF_UP)
  231                         ifp->if_flags |= IFF_RUNNING;
  232                 else
  233                         ifp->if_flags &= ~IFF_RUNNING;
  234                 break;
  235         case SIOCSIFMTU:
  236                 if (ifr->ifr_mtu < MPE_MTU_MIN ||
  237                     ifr->ifr_mtu > MPE_MTU_MAX)
  238                         error = EINVAL;
  239                 else
  240                         ifp->if_mtu = ifr->ifr_mtu;
  241                 break;
  242         case SIOCGETLABEL:
  243                 ifm = ifp->if_softc;
  244                 shim.shim_label =
  245                     ((ntohl(ifm->sc_shim.shim_label & MPLS_LABEL_MASK)) >>
  246                     MPLS_LABEL_OFFSET);
  247                 error = copyout(&shim, ifr->ifr_data, sizeof(shim));
  248                 break;
  249         case SIOCSETLABEL:
  250                 ifm = ifp->if_softc;
  251                 if ((error = copyin(ifr->ifr_data, &shim, sizeof(shim))))
  252                         break;
  253                 if (shim.shim_label > MPLS_LABEL_MAX ||
  254                     shim.shim_label <= MPLS_LABEL_RESERVED_MAX) {
  255                         error = EINVAL;
  256                         break;
  257                 }
  258                 shim.shim_label = (htonl(shim.shim_label << MPLS_LABEL_OFFSET))
  259                     | MPLS_BOS_MASK | ttl;
  260                 if (ifm->sc_shim.shim_label == shim.shim_label)
  261                         break;
  262                 LIST_FOREACH(ifm, &mpeif_list, sc_list) {
  263                         if (ifm != ifp->if_softc &&
  264                             ifm->sc_shim.shim_label == shim.shim_label) {
  265                                 error = EEXIST;
  266                                 break;
  267                         }
  268                 }
  269                 if (error)
  270                         break;
  271                 ifm = ifp->if_softc;
  272                 ifm->sc_shim.shim_label = shim.shim_label;
  273                 break;
  274         default:
  275                 return (ENOTTY);
  276         }
  277 
  278         return (error);
  279 }
  280 
  281 void
  282 mpe_input(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls,
  283     u_int8_t ttl)
  284 {
  285         struct ip       *ip;
  286         int              s, hlen;
  287 
  288         /* label -> AF lookup */
  289 
  290         if (mpls_mapttl_ip) {
  291                 if (m->m_len < sizeof (struct ip) &&
  292                     (m = m_pullup(m, sizeof(struct ip))) == NULL)
  293                         return;
  294                 ip = mtod(m, struct ip *);
  295                 hlen = ip->ip_hl << 2;
  296                 if (m->m_len < hlen) {
  297                         if ((m = m_pullup(m, hlen)) == NULL)
  298                                 return;
  299                         ip = mtod(m, struct ip *);
  300                 }
  301 
  302                 if (in_cksum(m, hlen) != 0) {
  303                         m_free(m);
  304                         return;
  305                 }
  306 
  307                 /* set IP ttl from MPLS ttl */
  308                 ip->ip_ttl = ttl;
  309 
  310                 /* recalculate checksum */
  311                 ip->ip_sum = 0;
  312                 ip->ip_sum = in_cksum(m, hlen);
  313         }
  314         
  315 #if NBPFILTER > 0
  316         if (ifp && ifp->if_bpf)
  317                 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
  318 #endif
  319         s = splnet();
  320         IF_ENQUEUE(&ipintrq, m);
  321         schednetisr(NETISR_IP);
  322         splx(s);
  323 }
  324 
  325 void
  326 mpe_input6(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls,
  327     u_int8_t ttl)
  328 {
  329         struct ip6_hdr *ip6hdr;
  330         int s;
  331 
  332         /* label -> AF lookup */
  333 
  334         if (mpls_mapttl_ip6) {
  335                 if (m->m_len < sizeof (struct ip6_hdr) &&
  336                     (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
  337                         return;
  338 
  339                 ip6hdr = mtod(m, struct ip6_hdr *);
  340 
  341                 /* set IPv6 ttl from MPLS ttl */
  342                 ip6hdr->ip6_hlim = ttl;
  343         }
  344 
  345 #if NBPFILTER > 0
  346         if (ifp && ifp->if_bpf)
  347                 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
  348 #endif
  349         s = splnet();
  350         IF_ENQUEUE(&ip6intrq, m);
  351         schednetisr(NETISR_IPV6);
  352         splx(s);
  353 }

Cache object: 63a298f422eb19494030f44843a0313c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.