1139823Simp/*- 25191Swollman * Copyright (c) 1982, 1986, 1993 35191Swollman * The Regents of the University of California. All rights reserved. 45191Swollman * 55191Swollman * Redistribution and use in source and binary forms, with or without 65191Swollman * modification, are permitted provided that the following conditions 75191Swollman * are met: 85191Swollman * 1. Redistributions of source code must retain the above copyright 95191Swollman * notice, this list of conditions and the following disclaimer. 105191Swollman * 2. Redistributions in binary form must reproduce the above copyright 115191Swollman * notice, this list of conditions and the following disclaimer in the 125191Swollman * documentation and/or other materials provided with the distribution. 135191Swollman * 4. Neither the name of the University nor the names of its contributors 145191Swollman * may be used to endorse or promote products derived from this software 155191Swollman * without specific prior written permission. 165191Swollman * 175191Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 185191Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 195191Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 205191Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 215191Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 225191Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 235191Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 245191Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 255191Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 265191Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 275191Swollman * SUCH DAMAGE. 285191Swollman * 295191Swollman * From: @(#)if_loop.c 8.1 (Berkeley) 6/10/93 3050477Speter * $FreeBSD$ 315191Swollman */ 325191Swollman 335191Swollman/* 345191Swollman * Discard interface driver for protocol testing and timing. 355191Swollman * (Based on the loopback.) 365191Swollman */ 375191Swollman 385191Swollman#include <sys/param.h> 395191Swollman#include <sys/systm.h> 405191Swollman#include <sys/kernel.h> 4197290Sbrooks#include <sys/malloc.h> 4271862Speter#include <sys/module.h> 435191Swollman#include <sys/mbuf.h> 445191Swollman#include <sys/socket.h> 4524204Sbde#include <sys/sockio.h> 465191Swollman 475191Swollman#include <net/if.h> 48130933Sbrooks#include <net/if_clone.h> 495191Swollman#include <net/if_types.h> 505191Swollman#include <net/route.h> 515191Swollman#include <net/bpf.h> 525191Swollman 5332350Seivind#include "opt_inet.h" 5454263Sshin#include "opt_inet6.h" 555191Swollman 565191Swollman#ifdef TINY_DSMTU 575191Swollman#define DSMTU (1024+512) 585191Swollman#else 595191Swollman#define DSMTU 65532 605191Swollman#endif 615191Swollman 6297290Sbrooksstruct disc_softc { 63167897Syar struct ifnet *sc_ifp; 6497290Sbrooks}; 655191Swollman 6697290Sbrooksstatic int discoutput(struct ifnet *, struct mbuf *, 67249925Sglebius const struct sockaddr *, struct route *); 6897290Sbrooksstatic void discrtrequest(int, struct rtentry *, struct rt_addrinfo *); 6997290Sbrooksstatic int discioctl(struct ifnet *, u_long, caddr_t); 70160195Ssamstatic int disc_clone_create(struct if_clone *, int, caddr_t); 7197290Sbrooksstatic void disc_clone_destroy(struct ifnet *); 7297290Sbrooks 73241610Sglebiusstatic const char discname[] = "disc"; 74241610Sglebiusstatic MALLOC_DEFINE(M_DISC, discname, "Discard interface"); 7597290Sbrooks 76241610Sglebiusstatic struct if_clone *disc_cloner; 77130933Sbrooks 7897290Sbrooksstatic int 79160195Ssamdisc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 805191Swollman{ 8197290Sbrooks struct ifnet *ifp; 8297290Sbrooks struct disc_softc *sc; 835191Swollman 84131670Sbms sc = malloc(sizeof(struct disc_softc), M_DISC, M_WAITOK | M_ZERO); 85147256Sbrooks ifp = sc->sc_ifp = if_alloc(IFT_LOOP); 86147256Sbrooks if (ifp == NULL) { 87147256Sbrooks free(sc, M_DISC); 88147256Sbrooks return (ENOSPC); 89147256Sbrooks } 9097290Sbrooks 9197290Sbrooks ifp->if_softc = sc; 92241610Sglebius if_initname(ifp, discname, unit); 935191Swollman ifp->if_mtu = DSMTU; 94173076Syar /* 95173076Syar * IFF_LOOPBACK should not be removed from disc's flags because 96173076Syar * it controls what PF-specific routes are magically added when 97173076Syar * a network address is assigned to the interface. Things just 98173076Syar * won't work as intended w/o such routes because the output 99173076Syar * interface selection for a packet is totally route-driven. 100173076Syar * A valid alternative to IFF_LOOPBACK can be IFF_BROADCAST or 101173076Syar * IFF_POINTOPOINT, but it would result in different properties 102173076Syar * of the interface. 103173076Syar */ 1045191Swollman ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 105152308Sglebius ifp->if_drv_flags = IFF_DRV_RUNNING; 10641757Seivind ifp->if_ioctl = discioctl; 10741757Seivind ifp->if_output = discoutput; 1085191Swollman ifp->if_hdrlen = 0; 1095191Swollman ifp->if_addrlen = 0; 11053115Sphk ifp->if_snd.ifq_maxlen = 20; 1115191Swollman if_attach(ifp); 112147611Sdwmalone bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 11397290Sbrooks 11497290Sbrooks return (0); 1155191Swollman} 1165191Swollman 11797290Sbrooksstatic void 11897290Sbrooksdisc_clone_destroy(struct ifnet *ifp) 11997290Sbrooks{ 12097290Sbrooks struct disc_softc *sc; 12197290Sbrooks 12297290Sbrooks sc = ifp->if_softc; 12397290Sbrooks 124151266Sthompsa bpfdetach(ifp); 125151266Sthompsa if_detach(ifp); 126151266Sthompsa if_free(ifp); 127151266Sthompsa 128151266Sthompsa free(sc, M_DISC); 12997290Sbrooks} 13097290Sbrooks 1315191Swollmanstatic int 132131669Sbmsdisc_modevent(module_t mod, int type, void *data) 133126777Srwatson{ 134126777Srwatson 135131669Sbms switch (type) { 136131669Sbms case MOD_LOAD: 137241610Sglebius disc_cloner = if_clone_simple(discname, disc_clone_create, 138241610Sglebius disc_clone_destroy, 0); 139131669Sbms break; 140131669Sbms case MOD_UNLOAD: 141241610Sglebius if_clone_detach(disc_cloner); 14297290Sbrooks break; 143132199Sphk default: 144132199Sphk return (EOPNOTSUPP); 145131669Sbms } 146131669Sbms return (0); 147131669Sbms} 14871862Speter 149131669Sbmsstatic moduledata_t disc_mod = { 150131669Sbms "if_disc", 151131669Sbms disc_modevent, 15271862Speter NULL 153131669Sbms}; 15471862Speter 15571862SpeterDECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 15671862Speter 15771862Speterstatic int 158249925Sglebiusdiscoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 159191148Skmacy struct route *ro) 1605191Swollman{ 161147611Sdwmalone u_int32_t af; 162131669Sbms 163113255Sdes M_ASSERTPKTHDR(m); 164131669Sbms 165147611Sdwmalone /* BPF writes need to be handled specially. */ 166249925Sglebius if (dst->sa_family == AF_UNSPEC) 167147611Sdwmalone bcopy(dst->sa_data, &af, sizeof(af)); 168249925Sglebius else 169249925Sglebius af = dst->sa_family; 17010957Swollman 171249925Sglebius if (bpf_peers_present(ifp->if_bpf)) 172123922Ssam bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 173249925Sglebius 1745191Swollman m->m_pkthdr.rcvif = ifp; 1755191Swollman 1765191Swollman ifp->if_opackets++; 1775191Swollman ifp->if_obytes += m->m_pkthdr.len; 1785191Swollman 1795191Swollman m_freem(m); 180131669Sbms return (0); 1815191Swollman} 1825191Swollman 1835191Swollman/* ARGSUSED */ 1845191Swollmanstatic void 18585074Srudiscrtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 1865191Swollman{ 187120727Ssam RT_LOCK_ASSERT(rt); 188263478Sglebius rt->rt_mtu = DSMTU; 1895191Swollman} 1905191Swollman 1915191Swollman/* 1925191Swollman * Process an ioctl request. 1935191Swollman */ 19412611Sbdestatic int 19578351Smarkmdiscioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1965191Swollman{ 19778351Smarkm struct ifaddr *ifa; 19878351Smarkm struct ifreq *ifr = (struct ifreq *)data; 19978351Smarkm int error = 0; 2005191Swollman 2015191Swollman switch (cmd) { 2025191Swollman 2035191Swollman case SIOCSIFADDR: 2045191Swollman ifp->if_flags |= IFF_UP; 2055191Swollman ifa = (struct ifaddr *)data; 2065191Swollman if (ifa != 0) 20741757Seivind ifa->ifa_rtrequest = discrtrequest; 2085191Swollman /* 2095191Swollman * Everything else is done at a higher level. 2105191Swollman */ 2115191Swollman break; 2125191Swollman 2135191Swollman case SIOCADDMULTI: 2145191Swollman case SIOCDELMULTI: 2155191Swollman if (ifr == 0) { 2165191Swollman error = EAFNOSUPPORT; /* XXX */ 2175191Swollman break; 2185191Swollman } 2195191Swollman switch (ifr->ifr_addr.sa_family) { 2205191Swollman 2215191Swollman#ifdef INET 2225191Swollman case AF_INET: 2235191Swollman break; 2245191Swollman#endif 22554263Sshin#ifdef INET6 22654263Sshin case AF_INET6: 22754263Sshin break; 22854263Sshin#endif 2295191Swollman 2305191Swollman default: 2315191Swollman error = EAFNOSUPPORT; 2325191Swollman break; 2335191Swollman } 2345191Swollman break; 2355191Swollman 2365191Swollman case SIOCSIFMTU: 2375191Swollman ifp->if_mtu = ifr->ifr_mtu; 2385191Swollman break; 2395191Swollman 2405191Swollman default: 2415191Swollman error = EINVAL; 2425191Swollman } 24387912Sjlemon return (error); 2445191Swollman} 245