if_loop.c revision 195837
1139823Simp/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 2985051Sru * @(#)if_loop.c 8.2 (Berkeley) 1/9/95 3050477Speter * $FreeBSD: head/sys/net/if_loop.c 195837 2009-07-23 20:46:49Z rwatson $ 311541Srgrimes */ 321541Srgrimes 331541Srgrimes/* 341541Srgrimes * Loopback interface driver for protocol testing and timing. 351541Srgrimes */ 361541Srgrimes 3732356Seivind#include "opt_atalk.h" 3832350Seivind#include "opt_inet.h" 3954263Sshin#include "opt_inet6.h" 4031742Seivind#include "opt_ipx.h" 4131742Seivind 421541Srgrimes#include <sys/param.h> 431541Srgrimes#include <sys/systm.h> 441541Srgrimes#include <sys/kernel.h> 451541Srgrimes#include <sys/mbuf.h> 4671862Speter#include <sys/module.h> 4791648Sbrooks#include <machine/bus.h> 4891648Sbrooks#include <sys/rman.h> 491541Srgrimes#include <sys/socket.h> 5024204Sbde#include <sys/sockio.h> 5171791Speter#include <sys/sysctl.h> 52181803Sbz#include <sys/vimage.h> 531541Srgrimes 541541Srgrimes#include <net/if.h> 55130933Sbrooks#include <net/if_clone.h> 561541Srgrimes#include <net/if_types.h> 571541Srgrimes#include <net/netisr.h> 581541Srgrimes#include <net/route.h> 591541Srgrimes#include <net/bpf.h> 60185571Sbz#include <net/vnet.h> 611541Srgrimes 621541Srgrimes#ifdef INET 631541Srgrimes#include <netinet/in.h> 641541Srgrimes#include <netinet/in_var.h> 651541Srgrimes#endif 661541Srgrimes 6711819Sjulian#ifdef IPX 6811819Sjulian#include <netipx/ipx.h> 6911819Sjulian#include <netipx/ipx_if.h> 7011819Sjulian#endif 7111819Sjulian 7253541Sshin#ifdef INET6 7353541Sshin#ifndef INET 7453541Sshin#include <netinet/in.h> 7553541Sshin#endif 7653541Sshin#include <netinet6/in6_var.h> 7762587Sitojun#include <netinet/ip6.h> 7853541Sshin#endif 7953541Sshin 8015885Sjulian#ifdef NETATALK 8115885Sjulian#include <netatalk/at.h> 8215885Sjulian#include <netatalk/at_var.h> 8383268Speter#endif 8415885Sjulian 85187039Srwatson#include <security/mac/mac_framework.h> 86187039Srwatson 871622Sdg#ifdef TINY_LOMTU 881541Srgrimes#define LOMTU (1024+512) 8953541Sshin#elif defined(LARGE_LOMTU) 9053541Sshin#define LOMTU 131072 911622Sdg#else 926876Sdg#define LOMTU 16384 931622Sdg#endif 941541Srgrimes 95189873Srwatson#define LO_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP) 96189873Srwatson#define LO_CSUM_SET (CSUM_DATA_VALID | CSUM_PSEUDO_HDR | \ 97189873Srwatson CSUM_IP_CHECKED | CSUM_IP_VALID | \ 98189873Srwatson CSUM_SCTP_VALID) 99189873Srwatson 10091648Sbrooksint loioctl(struct ifnet *, u_long, caddr_t); 10191648Sbrooksstatic void lortrequest(int, struct rtentry *, struct rt_addrinfo *); 10291648Sbrooksint looutput(struct ifnet *ifp, struct mbuf *m, 103191148Skmacy struct sockaddr *dst, struct route *ro); 104160195Ssamstatic int lo_clone_create(struct if_clone *, int, caddr_t); 105128209Sbrooksstatic void lo_clone_destroy(struct ifnet *); 10691648Sbrooks 107195699SrwatsonVNET_DEFINE(struct ifnet *, loif); /* Used externally */ 10891648Sbrooks 109192669Szec#ifdef VIMAGE 110195837Srwatsonstatic VNET_DEFINE(struct ifc_simple_data, lo_cloner_data); 111195837Srwatsonstatic VNET_DEFINE(struct if_clone, lo_cloner); 112195727Srwatson#define V_lo_cloner_data VNET(lo_cloner_data) 113195727Srwatson#define V_lo_cloner VNET(lo_cloner) 114192669Szec#endif 115192669Szec 116130933SbrooksIFC_SIMPLE_DECLARE(lo, 1); 11791648Sbrooks 118128209Sbrooksstatic void 119177965Srwatsonlo_clone_destroy(struct ifnet *ifp) 12091648Sbrooks{ 12191648Sbrooks 122193731Szec#ifndef VIMAGE 12397289Sbrooks /* XXX: destroying lo0 will lead to panics. */ 124181803Sbz KASSERT(V_loif != ifp, ("%s: destroying lo0", __func__)); 125193731Szec#endif 12691648Sbrooks 12791648Sbrooks bpfdetach(ifp); 12891648Sbrooks if_detach(ifp); 129147256Sbrooks if_free(ifp); 13091648Sbrooks} 13191648Sbrooks 132128209Sbrooksstatic int 133177965Srwatsonlo_clone_create(struct if_clone *ifc, int unit, caddr_t params) 13471791Speter{ 135147256Sbrooks struct ifnet *ifp; 13671791Speter 137180094Sed ifp = if_alloc(IFT_LOOP); 138180094Sed if (ifp == NULL) 139147256Sbrooks return (ENOSPC); 14071791Speter 141147256Sbrooks if_initname(ifp, ifc->ifc_name, unit); 142147256Sbrooks ifp->if_mtu = LOMTU; 143147256Sbrooks ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 144147256Sbrooks ifp->if_ioctl = loioctl; 145147256Sbrooks ifp->if_output = looutput; 146147256Sbrooks ifp->if_snd.ifq_maxlen = ifqmaxlen; 147189871Srwatson ifp->if_capabilities = ifp->if_capenable = IFCAP_HWCSUM; 148189873Srwatson ifp->if_hwassist = LO_CSUM_FEATURES; 149147256Sbrooks if_attach(ifp); 150147611Sdwmalone bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 151181803Sbz if (V_loif == NULL) 152181803Sbz V_loif = ifp; 15392081Smux 15492081Smux return (0); 15571791Speter} 15671791Speter 157195837Srwatsonstatic void 158195837Srwatsonvnet_loif_init(const void *unused __unused) 159190787Szec{ 160190787Szec 161192669Szec#ifdef VIMAGE 162195837Srwatson V_lo_cloner = lo_cloner; 163195837Srwatson V_lo_cloner_data = lo_cloner_data; 164195837Srwatson V_lo_cloner.ifc_data = &V_lo_cloner_data; 165195837Srwatson if_clone_attach(&V_lo_cloner); 166192669Szec#else 167190787Szec if_clone_attach(&lo_cloner); 168192669Szec#endif 169190787Szec} 170195837SrwatsonVNET_SYSINIT(vnet_loif_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 171195837Srwatson vnet_loif_init, NULL); 172190787Szec 173193731Szec#ifdef VIMAGE 174195837Srwatsonstatic void 175195837Srwatsonvnet_loif_uninit(const void *unused __unused) 176193731Szec{ 177193731Szec 178195837Srwatson if_clone_detach(&V_lo_cloner); 179193731Szec V_loif = NULL; 180193731Szec} 181195837SrwatsonVNET_SYSUNINIT(vnet_loif_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 182195837Srwatson vnet_loif_uninit, NULL); 183193731Szec#endif 184193731Szec 185193731Szecstatic int 186178883Srwatsonloop_modevent(module_t mod, int type, void *data) 187178883Srwatson{ 188177965Srwatson 189178883Srwatson switch (type) { 190178883Srwatson case MOD_LOAD: 191178883Srwatson break; 192177965Srwatson 193178883Srwatson case MOD_UNLOAD: 194178883Srwatson printf("loop module unload - not possible for this module type\n"); 195177965Srwatson return (EINVAL); 196177965Srwatson 197132199Sphk default: 198177965Srwatson return (EOPNOTSUPP); 199178883Srwatson } 200177965Srwatson return (0); 201178883Srwatson} 2021541Srgrimes 203178883Srwatsonstatic moduledata_t loop_mod = { 204178883Srwatson "loop", 205178883Srwatson loop_modevent, 20671862Speter 0 207178883Srwatson}; 20871862Speter 209121596SkanDECLARE_MODULE(loop, loop_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 21071862Speter 21154263Sshinint 212177965Srwatsonlooutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 213191148Skmacy struct route *ro) 2141541Srgrimes{ 215147611Sdwmalone u_int32_t af; 216191148Skmacy struct rtentry *rt = NULL; 217187039Srwatson#ifdef MAC 218187039Srwatson int error; 219187039Srwatson#endif 220147611Sdwmalone 221113255Sdes M_ASSERTPKTHDR(m); /* check if we have the packet header */ 222113255Sdes 223191148Skmacy if (ro != NULL) 224191148Skmacy rt = ro->ro_rt; 225187039Srwatson#ifdef MAC 226187039Srwatson error = mac_ifnet_check_transmit(ifp, m); 227187039Srwatson if (error) { 228187039Srwatson m_freem(m); 229187039Srwatson return (error); 230187039Srwatson } 231187039Srwatson#endif 232187039Srwatson 23336908Sjulian if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) { 23436908Sjulian m_freem(m); 23536908Sjulian return (rt->rt_flags & RTF_BLACKHOLE ? 0 : 23636908Sjulian rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 23736908Sjulian } 23853541Sshin 23936908Sjulian ifp->if_opackets++; 24036908Sjulian ifp->if_obytes += m->m_pkthdr.len; 241147611Sdwmalone 242147611Sdwmalone /* BPF writes need to be handled specially. */ 243147611Sdwmalone if (dst->sa_family == AF_UNSPEC) { 244147611Sdwmalone bcopy(dst->sa_data, &af, sizeof(af)); 245147611Sdwmalone dst->sa_family = af; 246147611Sdwmalone } 247147611Sdwmalone 24836992Sjulian#if 1 /* XXX */ 24936992Sjulian switch (dst->sa_family) { 25036992Sjulian case AF_INET: 251189863Srwatson if (ifp->if_capenable & IFCAP_RXCSUM) { 252189863Srwatson m->m_pkthdr.csum_data = 0xffff; 253189873Srwatson m->m_pkthdr.csum_flags = LO_CSUM_SET; 254189863Srwatson } 255189873Srwatson m->m_pkthdr.csum_flags &= ~LO_CSUM_FEATURES; 25653541Sshin case AF_INET6: 25736992Sjulian case AF_IPX: 25836992Sjulian case AF_APPLETALK: 25936994Sjulian break; 26036992Sjulian default: 26165454Srwatson printf("looutput: af=%d unexpected\n", dst->sa_family); 26236992Sjulian m_freem(m); 26336992Sjulian return (EAFNOSUPPORT); 26436992Sjulian } 26536992Sjulian#endif 266177965Srwatson return (if_simloop(ifp, m, dst->sa_family, 0)); 26736908Sjulian} 26836908Sjulian 26936908Sjulian/* 27036908Sjulian * if_simloop() 27136908Sjulian * 27236908Sjulian * This function is to support software emulation of hardware loopback, 27336908Sjulian * i.e., for interfaces with the IFF_SIMPLEX attribute. Since they can't 27436908Sjulian * hear their own broadcasts, we create a copy of the packet that we 27536908Sjulian * would normally receive via a hardware loopback. 27636908Sjulian * 27736908Sjulian * This function expects the packet to include the media header of length hlen. 27836908Sjulian */ 27936908Sjulianint 280177965Srwatsonif_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen) 28136908Sjulian{ 28269152Sjlemon int isr; 2831541Srgrimes 284113255Sdes M_ASSERTPKTHDR(m); 285121645Ssam m_tag_delete_nonpersistent(m); 28636908Sjulian m->m_pkthdr.rcvif = ifp; 28760889Sarchie 288187039Srwatson#ifdef MAC 289187039Srwatson mac_ifnet_create_mbuf(ifp, m); 290187039Srwatson#endif 291187039Srwatson 292162539Ssuz /* 293162539Ssuz * Let BPF see incoming packet in the following manner: 294178883Srwatson * - Emulated packet loopback for a simplex interface 295162539Ssuz * (net/if_ethersubr.c) 296162539Ssuz * -> passes it to ifp's BPF 297162539Ssuz * - IPv4/v6 multicast packet loopback (netinet(6)/ip(6)_output.c) 298162539Ssuz * -> not passes it to any BPF 299162539Ssuz * - Normal packet loopback from myself to myself (net/if_loop.c) 300162539Ssuz * -> passes to lo0's BPF (even in case of IPv6, where ifp!=lo0) 301162539Ssuz */ 302162539Ssuz if (hlen > 0) { 303162539Ssuz if (bpf_peers_present(ifp->if_bpf)) { 304123922Ssam bpf_mtap(ifp->if_bpf, m); 305162539Ssuz } 306162539Ssuz } else { 307181803Sbz if (bpf_peers_present(V_loif->if_bpf)) { 308181803Sbz if ((m->m_flags & M_MCAST) == 0 || V_loif == ifp) { 309162539Ssuz /* XXX beware sizeof(af) != 4 */ 310181118Srwatson u_int32_t af1 = af; 311162539Ssuz 312162539Ssuz /* 313162539Ssuz * We need to prepend the address family. 314162539Ssuz */ 315181803Sbz bpf_mtap2(V_loif->if_bpf, &af1, sizeof(af1), m); 316162539Ssuz } 317162539Ssuz } 3181541Srgrimes } 3191541Srgrimes 32036908Sjulian /* Strip away media header */ 32137600Sdfr if (hlen > 0) { 32260952Sgallatin m_adj(m, hlen); 323166577Scognet#ifndef __NO_STRICT_ALIGNMENT 324158471Sjhb /* 325158471Sjhb * Some archs do not like unaligned data, so 326158471Sjhb * we move data down in the first mbuf. 327158471Sjhb */ 32860952Sgallatin if (mtod(m, vm_offset_t) & 3) { 32961181Smjacob KASSERT(hlen >= 3, ("if_simloop: hlen too small")); 330178883Srwatson bcopy(m->m_data, 331178883Srwatson (char *)(mtod(m, vm_offset_t) 33260952Sgallatin - (mtod(m, vm_offset_t) & 3)), 33360952Sgallatin m->m_len); 334132780Skan m->m_data -= (mtod(m,vm_offset_t) & 3); 33560952Sgallatin } 33637600Sdfr#endif 33737600Sdfr } 33836908Sjulian 33960889Sarchie /* Deliver to upper layer protocol */ 34060889Sarchie switch (af) { 3411541Srgrimes#ifdef INET 3421541Srgrimes case AF_INET: 3431541Srgrimes isr = NETISR_IP; 3441541Srgrimes break; 3451541Srgrimes#endif 34653541Sshin#ifdef INET6 34753541Sshin case AF_INET6: 34853541Sshin m->m_flags |= M_LOOP; 34953541Sshin isr = NETISR_IPV6; 35053541Sshin break; 35153541Sshin#endif 35211819Sjulian#ifdef IPX 35311819Sjulian case AF_IPX: 35411819Sjulian isr = NETISR_IPX; 35511819Sjulian break; 35611819Sjulian#endif 35715885Sjulian#ifdef NETATALK 35815885Sjulian case AF_APPLETALK: 359111888Sjlemon isr = NETISR_ATALK2; 36015885Sjulian break; 36183268Speter#endif 3621541Srgrimes default: 36360889Sarchie printf("if_simloop: can't handle af=%d\n", af); 3641541Srgrimes m_freem(m); 3651541Srgrimes return (EAFNOSUPPORT); 3661541Srgrimes } 3671541Srgrimes ifp->if_ipackets++; 3681541Srgrimes ifp->if_ibytes += m->m_pkthdr.len; 369134391Sandre netisr_queue(isr, m); /* mbuf is free'd on failure. */ 3701541Srgrimes return (0); 3711541Srgrimes} 3721541Srgrimes 3731541Srgrimes/* ARGSUSED */ 37412706Sphkstatic void 375177965Srwatsonlortrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 3761541Srgrimes{ 377177965Srwatson 378120727Ssam RT_LOCK_ASSERT(rt); 379142352Ssam rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu; 3801541Srgrimes} 3811541Srgrimes 3821541Srgrimes/* 3831541Srgrimes * Process an ioctl request. 3841541Srgrimes */ 3851541Srgrimes/* ARGSUSED */ 38654263Sshinint 387177965Srwatsonloioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 3881541Srgrimes{ 389177965Srwatson struct ifaddr *ifa; 390177965Srwatson struct ifreq *ifr = (struct ifreq *)data; 391189863Srwatson int error = 0, mask; 3921541Srgrimes 3931541Srgrimes switch (cmd) { 3941541Srgrimes case SIOCSIFADDR: 395148887Srwatson ifp->if_flags |= IFF_UP; 396148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 3971541Srgrimes ifa = (struct ifaddr *)data; 39813928Swollman ifa->ifa_rtrequest = lortrequest; 3991541Srgrimes /* 4001541Srgrimes * Everything else is done at a higher level. 4011541Srgrimes */ 4021541Srgrimes break; 4031541Srgrimes 4041541Srgrimes case SIOCADDMULTI: 4051541Srgrimes case SIOCDELMULTI: 4061541Srgrimes if (ifr == 0) { 4071541Srgrimes error = EAFNOSUPPORT; /* XXX */ 4081541Srgrimes break; 4091541Srgrimes } 4101541Srgrimes switch (ifr->ifr_addr.sa_family) { 4111541Srgrimes 4121541Srgrimes#ifdef INET 4131541Srgrimes case AF_INET: 4141541Srgrimes break; 4151541Srgrimes#endif 41653541Sshin#ifdef INET6 41753541Sshin case AF_INET6: 41853541Sshin break; 41953541Sshin#endif 4201541Srgrimes 4211541Srgrimes default: 4221541Srgrimes error = EAFNOSUPPORT; 4231541Srgrimes break; 4241541Srgrimes } 4251541Srgrimes break; 4261541Srgrimes 4271944Sdg case SIOCSIFMTU: 42849468Sbrian ifp->if_mtu = ifr->ifr_mtu; 4291944Sdg break; 4301944Sdg 43135563Sphk case SIOCSIFFLAGS: 43235563Sphk break; 43335563Sphk 434189863Srwatson case SIOCSIFCAP: 435189863Srwatson mask = ifp->if_capenable ^ ifr->ifr_reqcap; 436189863Srwatson if ((mask & IFCAP_RXCSUM) != 0) 437189863Srwatson ifp->if_capenable ^= IFCAP_RXCSUM; 438189863Srwatson if ((mask & IFCAP_TXCSUM) != 0) 439189863Srwatson ifp->if_capenable ^= IFCAP_TXCSUM; 440189863Srwatson if (ifp->if_capenable & IFCAP_TXCSUM) 441189873Srwatson ifp->if_hwassist = LO_CSUM_FEATURES; 442189863Srwatson else 443189863Srwatson ifp->if_hwassist = 0; 444189863Srwatson break; 445189863Srwatson 4461541Srgrimes default: 4471541Srgrimes error = EINVAL; 4481541Srgrimes } 4491541Srgrimes return (error); 4501541Srgrimes} 451