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_loop.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1982, 1986, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the University nor the names of its contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      @(#)if_loop.c   8.1 (Berkeley) 6/10/93
   30  * $FreeBSD: src/sys/net/if_loop.c,v 1.47.2.9 2004/02/08 08:40:24 silby Exp $
   31  */
   32 
   33 /*
   34  * Loopback interface driver for protocol testing and timing.
   35  */
   36 #include "use_loop.h"
   37 
   38 #include "opt_inet.h"
   39 #include "opt_inet6.h"
   40 #include "opt_ipx.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/kernel.h>
   45 #include <sys/lock.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/socket.h>
   48 #include <sys/sockio.h>
   49 
   50 #include <sys/mplock2.h>
   51 
   52 #include <net/if.h>
   53 #include <net/if_types.h>
   54 #include <net/ifq_var.h>
   55 #include <net/netisr.h>
   56 #include <net/route.h>
   57 #include <net/bpf.h>
   58 #include <net/bpfdesc.h>
   59 
   60 #ifdef  INET
   61 #include <netinet/in.h>
   62 #include <netinet/in_var.h>
   63 #endif
   64 
   65 #ifdef IPX
   66 #include <netproto/ipx/ipx.h>
   67 #include <netproto/ipx/ipx_if.h>
   68 #endif
   69 
   70 #ifdef INET6
   71 #ifndef INET
   72 #include <netinet/in.h>
   73 #endif
   74 #include <netinet6/in6_var.h>
   75 #include <netinet/ip6.h>
   76 #endif
   77 
   78 static void     loopattach(void *);
   79 static int      looutput(struct ifnet *, struct mbuf *, struct sockaddr *,
   80                          struct rtentry *);
   81 static int      loioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
   82 static void     lortrequest(int, struct rtentry *);
   83 #ifdef ALTQ
   84 static void     lo_altqstart(struct ifnet *, struct ifaltq_subque *);
   85 #endif
   86 PSEUDO_SET(loopattach, if_loop);
   87 
   88 #ifdef TINY_LOMTU
   89 #define LOMTU   (1024+512)
   90 #elif defined(LARGE_LOMTU)
   91 #define LOMTU   131072
   92 #else
   93 #define LOMTU   16384
   94 #endif
   95 
   96 #define LO_CSUM_FEATURES        (CSUM_IP | CSUM_UDP | CSUM_TCP)
   97 
   98 struct  ifnet loif[NLOOP];
   99 
  100 /* ARGSUSED */
  101 static void
  102 loopattach(void *dummy)
  103 {
  104         struct ifnet *ifp;
  105         int i;
  106 
  107         for (i = 0, ifp = loif; i < NLOOP; i++, ifp++) {
  108                 if_initname(ifp, "lo", i);
  109                 ifp->if_mtu = LOMTU;
  110                 ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
  111                 ifp->if_capabilities = IFCAP_HWCSUM;
  112                 ifp->if_hwassist = LO_CSUM_FEATURES;
  113                 ifp->if_capenable = ifp->if_capabilities;
  114                 ifp->if_ioctl = loioctl;
  115                 ifp->if_output = looutput;
  116                 ifp->if_type = IFT_LOOP;
  117                 ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
  118                 ifq_set_ready(&ifp->if_snd);
  119 #ifdef ALTQ
  120                 ifp->if_start = lo_altqstart;
  121 #endif
  122                 if_attach(ifp, NULL);
  123                 bpfattach(ifp, DLT_NULL, sizeof(u_int));
  124         }
  125 }
  126 
  127 static int
  128 looutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  129          struct rtentry *rt)
  130 {
  131         M_ASSERTPKTHDR(m);
  132 
  133         if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
  134                 m_freem(m);
  135                 return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
  136                         rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
  137         }
  138 
  139         IFNET_STAT_INC(ifp, opackets, 1);
  140         IFNET_STAT_INC(ifp, obytes, m->m_pkthdr.len);
  141 #if 1   /* XXX */
  142         switch (dst->sa_family) {
  143         case AF_INET:
  144         case AF_INET6:
  145         case AF_IPX:
  146         case AF_NS:
  147                 break;
  148         default:
  149                 kprintf("looutput: af=%d unexpected\n", dst->sa_family);
  150                 m_freem(m);
  151                 return (EAFNOSUPPORT);
  152         }
  153 #endif
  154 
  155         if (ifp->if_capenable & IFCAP_RXCSUM) {
  156                 int csum_flags = 0;
  157 
  158                 if (m->m_pkthdr.csum_flags & CSUM_IP)
  159                         csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
  160                 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
  161                         csum_flags |= (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
  162 
  163                 m->m_pkthdr.csum_flags |= csum_flags;
  164                 if (csum_flags & CSUM_DATA_VALID)
  165                         m->m_pkthdr.csum_data = 0xffff;
  166         }
  167         return (if_simloop(ifp, m, dst->sa_family, 0));
  168 }
  169 
  170 /*
  171  * if_simloop()
  172  *
  173  * This function is to support software emulation of hardware loopback,
  174  * i.e., for interfaces with the IFF_SIMPLEX attribute. Since they can't
  175  * hear their own broadcasts, we create a copy of the packet that we
  176  * would normally receive via a hardware loopback.
  177  *
  178  * This function expects the packet to include the media header of length hlen.
  179  */
  180 int
  181 if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen)
  182 {
  183         int isr;
  184 
  185         KASSERT((m->m_flags & M_PKTHDR) != 0, ("if_simloop: no HDR"));
  186         m->m_pkthdr.rcvif = ifp;
  187 
  188         /* BPF write needs to be handled specially */
  189         if (af == AF_UNSPEC) {
  190                 KASSERT(m->m_len >= sizeof(int), ("if_simloop: m_len"));
  191                 af = *(mtod(m, int *));
  192                 m->m_len -= sizeof(int);
  193                 m->m_pkthdr.len -= sizeof(int);
  194                 m->m_data += sizeof(int);
  195         }
  196 
  197         if (ifp->if_bpf) {
  198                 bpf_gettoken();
  199 
  200                 /* Re-check */
  201                 if (ifp->if_bpf == NULL)
  202                         goto rel;
  203 
  204                 if (ifp->if_bpf->bif_dlt == DLT_NULL) {
  205                         uint32_t bpf_af = (uint32_t)af;
  206                         bpf_ptap(ifp->if_bpf, m, &bpf_af, 4);
  207                 } else {
  208                         bpf_mtap(ifp->if_bpf, m);
  209                 }
  210 rel:
  211                 bpf_reltoken();
  212         }
  213 
  214         /* Strip away media header */
  215         if (hlen > 0)
  216                 m_adj(m, hlen);
  217  
  218 #ifdef ALTQ
  219         /*
  220          * altq for loop is just for debugging.
  221          * only used when called for loop interface (not for
  222          * a simplex interface).
  223          */
  224         if (ifq_is_enabled(&ifp->if_snd) && ifp->if_start == lo_altqstart) {
  225                 struct altq_pktattr pktattr;
  226                 int32_t *afp;
  227 
  228                 /*
  229                  * if the queueing discipline needs packet classification,
  230                  * do it before prepending link headers.
  231                  */
  232                 ifq_classify(&ifp->if_snd, m, af, &pktattr);
  233 
  234                 M_PREPEND(m, sizeof(int32_t), MB_DONTWAIT);
  235                 if (m == NULL)
  236                         return(ENOBUFS);
  237                 afp = mtod(m, int32_t *);
  238                 *afp = (int32_t)af;
  239 
  240                 return ifq_dispatch(ifp, m, &pktattr);
  241         }
  242 #endif /* ALTQ */
  243 
  244         /* Deliver to upper layer protocol */
  245         switch (af) {
  246 #ifdef INET
  247         case AF_INET:
  248                 isr = NETISR_IP;
  249                 break;
  250 #endif
  251 #ifdef INET6
  252         case AF_INET6:
  253                 m->m_flags |= M_LOOP;
  254                 isr = NETISR_IPV6;
  255                 break;
  256 #endif
  257 #ifdef IPX
  258         case AF_IPX:
  259                 isr = NETISR_IPX;
  260                 break;
  261 #endif
  262         default:
  263                 kprintf("if_simloop: can't handle af=%d\n", af);
  264                 m_freem(m);
  265                 return (EAFNOSUPPORT);
  266         }
  267 
  268         IFNET_STAT_INC(ifp, ipackets, 1);
  269         IFNET_STAT_INC(ifp, ibytes, m->m_pkthdr.len);
  270         netisr_queue(isr, m);
  271         return (0);
  272 }
  273 
  274 #ifdef ALTQ
  275 static void
  276 lo_altqstart(struct ifnet *ifp, struct ifaltq_subque *ifsq)
  277 {
  278         struct mbuf *m;
  279         int32_t af, *afp;
  280         int isr;
  281         
  282         while (1) {
  283                 crit_enter();
  284                 m = ifsq_dequeue(ifsq);
  285                 crit_exit();
  286                 if (m == NULL)
  287                         return;
  288 
  289                 afp = mtod(m, int32_t *);
  290                 af = *afp;
  291                 m_adj(m, sizeof(int32_t));
  292 
  293                 switch (af) {
  294 #ifdef INET
  295                 case AF_INET:
  296                         isr = NETISR_IP;
  297                         break;
  298 #endif
  299 #ifdef INET6
  300                 case AF_INET6:
  301                         m->m_flags |= M_LOOP;
  302                         isr = NETISR_IPV6;
  303                         break;
  304 #endif
  305 #ifdef IPX
  306                 case AF_IPX:
  307                         isr = NETISR_IPX;
  308                         break;
  309 #endif
  310 #ifdef ISO
  311                 case AF_ISO:
  312                         isr = NETISR_ISO;
  313                         break;
  314 #endif
  315                 default:
  316                         kprintf("lo_altqstart: can't handle af%d\n", af);
  317                         m_freem(m);
  318                         return;
  319                 }
  320 
  321                 IFNET_STAT_INC(ifp, ipackets, 1);
  322                 IFNET_STAT_INC(ifp, ibytes, m->m_pkthdr.len);
  323                 netisr_queue(isr, m);
  324         }
  325 }
  326 #endif /* ALTQ */
  327 
  328 /* ARGSUSED */
  329 static void
  330 lortrequest(int cmd, struct rtentry *rt)
  331 {
  332         if (rt) {
  333                 rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; /* for ISO */
  334                 /*
  335                  * For optimal performance, the send and receive buffers
  336                  * should be at least twice the MTU plus a little more for
  337                  * overhead.
  338                  */
  339                 rt->rt_rmx.rmx_recvpipe = rt->rt_rmx.rmx_sendpipe = 3 * LOMTU;
  340         }
  341 }
  342 
  343 /*
  344  * Process an ioctl request.
  345  */
  346 /* ARGSUSED */
  347 static int
  348 loioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
  349 {
  350         struct ifaddr *ifa;
  351         struct ifreq *ifr = (struct ifreq *)data;
  352         int error = 0, mask;
  353 
  354         switch (cmd) {
  355         case SIOCSIFADDR:
  356                 ifp->if_flags |= IFF_UP | IFF_RUNNING;
  357                 ifa = (struct ifaddr *)data;
  358                 ifa->ifa_rtrequest = lortrequest;
  359                 /*
  360                  * Everything else is done at a higher level.
  361                  */
  362                 break;
  363 
  364         case SIOCADDMULTI:
  365         case SIOCDELMULTI:
  366                 if (ifr == NULL) {
  367                         error = EAFNOSUPPORT;           /* XXX */
  368                         break;
  369                 }
  370                 switch (ifr->ifr_addr.sa_family) {
  371 
  372 #ifdef INET
  373                 case AF_INET:
  374                         break;
  375 #endif
  376 #ifdef INET6
  377                 case AF_INET6:
  378                         break;
  379 #endif
  380 
  381                 default:
  382                         error = EAFNOSUPPORT;
  383                         break;
  384                 }
  385                 break;
  386 
  387         case SIOCSIFMTU:
  388                 ifp->if_mtu = ifr->ifr_mtu;
  389                 break;
  390 
  391         case SIOCSIFFLAGS:
  392                 break;
  393 
  394         case SIOCSIFCAP:
  395                 mask = (ifr->ifr_reqcap ^ ifp->if_capenable) & IFCAP_HWCSUM;
  396                 if (mask) {
  397                         ifp->if_capenable ^= mask;
  398                         if (IFCAP_TXCSUM & ifp->if_capenable)
  399                                 ifp->if_hwassist = LO_CSUM_FEATURES;
  400                         else
  401                                 ifp->if_hwassist = 0;
  402                 }
  403                 break;
  404 
  405         default:
  406                 error = EINVAL;
  407         }
  408         return (error);
  409 }

Cache object: 9d9afc58d3741863221b825304e79a07


[ 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.