159d8d13fSGarrett Wollman /* 259d8d13fSGarrett Wollman * Copyright (c) 1982, 1986, 1993 359d8d13fSGarrett Wollman * The Regents of the University of California. All rights reserved. 459d8d13fSGarrett Wollman * 559d8d13fSGarrett Wollman * Redistribution and use in source and binary forms, with or without 659d8d13fSGarrett Wollman * modification, are permitted provided that the following conditions 759d8d13fSGarrett Wollman * are met: 859d8d13fSGarrett Wollman * 1. Redistributions of source code must retain the above copyright 959d8d13fSGarrett Wollman * notice, this list of conditions and the following disclaimer. 1059d8d13fSGarrett Wollman * 2. Redistributions in binary form must reproduce the above copyright 1159d8d13fSGarrett Wollman * notice, this list of conditions and the following disclaimer in the 1259d8d13fSGarrett Wollman * documentation and/or other materials provided with the distribution. 1359d8d13fSGarrett Wollman * 4. Neither the name of the University nor the names of its contributors 1459d8d13fSGarrett Wollman * may be used to endorse or promote products derived from this software 1559d8d13fSGarrett Wollman * without specific prior written permission. 1659d8d13fSGarrett Wollman * 1759d8d13fSGarrett Wollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1859d8d13fSGarrett Wollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1959d8d13fSGarrett Wollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2059d8d13fSGarrett Wollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2159d8d13fSGarrett Wollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2259d8d13fSGarrett Wollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2359d8d13fSGarrett Wollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2459d8d13fSGarrett Wollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2559d8d13fSGarrett Wollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2659d8d13fSGarrett Wollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2759d8d13fSGarrett Wollman * SUCH DAMAGE. 2859d8d13fSGarrett Wollman * 2959d8d13fSGarrett Wollman * From: @(#)if_loop.c 8.1 (Berkeley) 6/10/93 30c3aac50fSPeter Wemm * $FreeBSD$ 3159d8d13fSGarrett Wollman */ 3259d8d13fSGarrett Wollman 3359d8d13fSGarrett Wollman /* 3459d8d13fSGarrett Wollman * Discard interface driver for protocol testing and timing. 3559d8d13fSGarrett Wollman * (Based on the loopback.) 3659d8d13fSGarrett Wollman */ 3759d8d13fSGarrett Wollman 3859d8d13fSGarrett Wollman #include <sys/param.h> 3959d8d13fSGarrett Wollman #include <sys/systm.h> 4059d8d13fSGarrett Wollman #include <sys/kernel.h> 41c69b7ffeSBrooks Davis #include <sys/malloc.h> 422b120974SPeter Wemm #include <sys/module.h> 4359d8d13fSGarrett Wollman #include <sys/mbuf.h> 4459d8d13fSGarrett Wollman #include <sys/socket.h> 4551a53488SBruce Evans #include <sys/sockio.h> 4659d8d13fSGarrett Wollman 4759d8d13fSGarrett Wollman #include <net/if.h> 48f889d2efSBrooks Davis #include <net/if_clone.h> 4959d8d13fSGarrett Wollman #include <net/if_types.h> 5059d8d13fSGarrett Wollman #include <net/route.h> 5159d8d13fSGarrett Wollman #include <net/bpf.h> 5259d8d13fSGarrett Wollman 531d5e9e22SEivind Eklund #include "opt_inet.h" 54cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 5559d8d13fSGarrett Wollman 5659d8d13fSGarrett Wollman #ifdef TINY_DSMTU 5759d8d13fSGarrett Wollman #define DSMTU (1024+512) 5859d8d13fSGarrett Wollman #else 5959d8d13fSGarrett Wollman #define DSMTU 65532 6059d8d13fSGarrett Wollman #endif 6159d8d13fSGarrett Wollman 62c69b7ffeSBrooks Davis #define DISCNAME "disc" 63b6f5c0b8SBruce Evans 64c69b7ffeSBrooks Davis struct disc_softc { 65c69b7ffeSBrooks Davis struct ifnet sc_if; /* must be first */ 66c69b7ffeSBrooks Davis LIST_ENTRY(disc_softc) sc_list; 67c69b7ffeSBrooks Davis }; 68c69b7ffeSBrooks Davis 69eb6bd594SMark Murray static int discoutput(struct ifnet *, struct mbuf *, 70eb6bd594SMark Murray struct sockaddr *, struct rtentry *); 718071913dSRuslan Ermilov static void discrtrequest(int, struct rtentry *, struct rt_addrinfo *); 72537ad974SEivind Eklund static int discioctl(struct ifnet *, u_long, caddr_t); 73c69b7ffeSBrooks Davis static int disc_clone_create(struct if_clone *, int); 74c69b7ffeSBrooks Davis static void disc_clone_destroy(struct ifnet *); 7559d8d13fSGarrett Wollman 76d6e2616aSRobert Watson static struct mtx disc_mtx; 77c69b7ffeSBrooks Davis static MALLOC_DEFINE(M_DISC, DISCNAME, "Discard interface"); 78c69b7ffeSBrooks Davis static LIST_HEAD(, disc_softc) disc_softc_list; 79f889d2efSBrooks Davis 80f889d2efSBrooks Davis IFC_SIMPLE_DECLARE(disc, 0); 81c69b7ffeSBrooks Davis 82c69b7ffeSBrooks Davis static int 83c69b7ffeSBrooks Davis disc_clone_create(struct if_clone *ifc, int unit) 8459d8d13fSGarrett Wollman { 85c69b7ffeSBrooks Davis struct ifnet *ifp; 86c69b7ffeSBrooks Davis struct disc_softc *sc; 8759d8d13fSGarrett Wollman 88a163d034SWarner Losh sc = malloc(sizeof(struct disc_softc), M_DISC, M_WAITOK); 89c69b7ffeSBrooks Davis bzero(sc, sizeof(struct disc_softc)); 90c69b7ffeSBrooks Davis 91c69b7ffeSBrooks Davis ifp = &sc->sc_if; 92c69b7ffeSBrooks Davis 93c69b7ffeSBrooks Davis ifp->if_softc = sc; 949bf40edeSBrooks Davis if_initname(ifp, ifc->ifc_name, unit); 9559d8d13fSGarrett Wollman ifp->if_mtu = DSMTU; 9659d8d13fSGarrett Wollman ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 97537ad974SEivind Eklund ifp->if_ioctl = discioctl; 98537ad974SEivind Eklund ifp->if_output = discoutput; 9959d8d13fSGarrett Wollman ifp->if_type = IFT_LOOP; 10059d8d13fSGarrett Wollman ifp->if_hdrlen = 0; 10159d8d13fSGarrett Wollman ifp->if_addrlen = 0; 102422fd76fSPoul-Henning Kamp ifp->if_snd.ifq_maxlen = 20; 10359d8d13fSGarrett Wollman if_attach(ifp); 1049b44ff22SGarrett Wollman bpfattach(ifp, DLT_NULL, sizeof(u_int)); 105d6e2616aSRobert Watson mtx_lock(&disc_mtx); 106c69b7ffeSBrooks Davis LIST_INSERT_HEAD(&disc_softc_list, sc, sc_list); 107d6e2616aSRobert Watson mtx_unlock(&disc_mtx); 108c69b7ffeSBrooks Davis 109c69b7ffeSBrooks Davis return (0); 110c69b7ffeSBrooks Davis } 111c69b7ffeSBrooks Davis 112c69b7ffeSBrooks Davis static void 113d6e2616aSRobert Watson disc_destroy(struct disc_softc *sc) 114d6e2616aSRobert Watson { 115d6e2616aSRobert Watson 116d6e2616aSRobert Watson bpfdetach(&sc->sc_if); 117d6e2616aSRobert Watson if_detach(&sc->sc_if); 118d6e2616aSRobert Watson 119d6e2616aSRobert Watson free(sc, M_DISC); 120d6e2616aSRobert Watson } 121d6e2616aSRobert Watson 122d6e2616aSRobert Watson static void 123c69b7ffeSBrooks Davis disc_clone_destroy(struct ifnet *ifp) 124c69b7ffeSBrooks Davis { 125c69b7ffeSBrooks Davis struct disc_softc *sc; 126c69b7ffeSBrooks Davis 127c69b7ffeSBrooks Davis sc = ifp->if_softc; 128d6e2616aSRobert Watson mtx_lock(&disc_mtx); 129c69b7ffeSBrooks Davis LIST_REMOVE(sc, sc_list); 130d6e2616aSRobert Watson mtx_unlock(&disc_mtx); 131c69b7ffeSBrooks Davis 132d6e2616aSRobert Watson disc_destroy(sc); 13359d8d13fSGarrett Wollman } 13459d8d13fSGarrett Wollman 13559d8d13fSGarrett Wollman static int 1362b120974SPeter Wemm disc_modevent(module_t mod, int type, void *data) 1372b120974SPeter Wemm { 138d6e2616aSRobert Watson struct disc_softc *sc; 139d6e2616aSRobert Watson 1402b120974SPeter Wemm switch (type) { 1412b120974SPeter Wemm case MOD_LOAD: 142d6e2616aSRobert Watson mtx_init(&disc_mtx, "disc_mtx", NULL, MTX_DEF); 143c69b7ffeSBrooks Davis LIST_INIT(&disc_softc_list); 144c69b7ffeSBrooks Davis if_clone_attach(&disc_cloner); 1452b120974SPeter Wemm break; 1462b120974SPeter Wemm case MOD_UNLOAD: 147c69b7ffeSBrooks Davis if_clone_detach(&disc_cloner); 148c69b7ffeSBrooks Davis 149d6e2616aSRobert Watson mtx_lock(&disc_mtx); 150d6e2616aSRobert Watson while ((sc = LIST_FIRST(&disc_softc_list)) != NULL) { 151d6e2616aSRobert Watson LIST_REMOVE(sc, sc_list); 152d6e2616aSRobert Watson mtx_unlock(&disc_mtx); 153d6e2616aSRobert Watson disc_destroy(sc); 154d6e2616aSRobert Watson mtx_lock(&disc_mtx); 155d6e2616aSRobert Watson } 156d6e2616aSRobert Watson mtx_unlock(&disc_mtx); 157d6e2616aSRobert Watson mtx_destroy(&disc_mtx); 158c69b7ffeSBrooks Davis break; 1592b120974SPeter Wemm } 1602b120974SPeter Wemm return 0; 1612b120974SPeter Wemm } 1622b120974SPeter Wemm 1632b120974SPeter Wemm static moduledata_t disc_mod = { 1642b120974SPeter Wemm "if_disc", 1652b120974SPeter Wemm disc_modevent, 1662b120974SPeter Wemm NULL 1672b120974SPeter Wemm }; 1682b120974SPeter Wemm 1692b120974SPeter Wemm DECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1702b120974SPeter Wemm 1712b120974SPeter Wemm static int 172eb6bd594SMark Murray discoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 173eb6bd594SMark Murray struct rtentry *rt) 17459d8d13fSGarrett Wollman { 175fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); 176963e4c2aSGarrett Wollman /* BPF write needs to be handled specially */ 177963e4c2aSGarrett Wollman if (dst->sa_family == AF_UNSPEC) { 178963e4c2aSGarrett Wollman dst->sa_family = *(mtod(m, int *)); 179963e4c2aSGarrett Wollman m->m_len -= sizeof(int); 180963e4c2aSGarrett Wollman m->m_pkthdr.len -= sizeof(int); 181963e4c2aSGarrett Wollman m->m_data += sizeof(int); 182963e4c2aSGarrett Wollman } 183963e4c2aSGarrett Wollman 184c69b7ffeSBrooks Davis if (ifp->if_bpf) { 18559d8d13fSGarrett Wollman u_int af = dst->sa_family; 186437ffe18SSam Leffler bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 18759d8d13fSGarrett Wollman } 18859d8d13fSGarrett Wollman m->m_pkthdr.rcvif = ifp; 18959d8d13fSGarrett Wollman 19059d8d13fSGarrett Wollman ifp->if_opackets++; 19159d8d13fSGarrett Wollman ifp->if_obytes += m->m_pkthdr.len; 19259d8d13fSGarrett Wollman 19359d8d13fSGarrett Wollman m_freem(m); 19459d8d13fSGarrett Wollman return 0; 19559d8d13fSGarrett Wollman } 19659d8d13fSGarrett Wollman 19759d8d13fSGarrett Wollman /* ARGSUSED */ 19859d8d13fSGarrett Wollman static void 1998071913dSRuslan Ermilov discrtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 20059d8d13fSGarrett Wollman { 201d1dd20beSSam Leffler RT_LOCK_ASSERT(rt); 202d1dd20beSSam Leffler 20359d8d13fSGarrett Wollman if (rt) 20459d8d13fSGarrett Wollman rt->rt_rmx.rmx_mtu = DSMTU; 20559d8d13fSGarrett Wollman } 20659d8d13fSGarrett Wollman 20759d8d13fSGarrett Wollman /* 20859d8d13fSGarrett Wollman * Process an ioctl request. 20959d8d13fSGarrett Wollman */ 21088e2f526SBruce Evans static int 211eb6bd594SMark Murray discioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 21259d8d13fSGarrett Wollman { 213eb6bd594SMark Murray struct ifaddr *ifa; 214eb6bd594SMark Murray struct ifreq *ifr = (struct ifreq *)data; 215eb6bd594SMark Murray int error = 0; 21659d8d13fSGarrett Wollman 21759d8d13fSGarrett Wollman switch (cmd) { 21859d8d13fSGarrett Wollman 21959d8d13fSGarrett Wollman case SIOCSIFADDR: 22059d8d13fSGarrett Wollman ifp->if_flags |= IFF_UP; 22159d8d13fSGarrett Wollman ifa = (struct ifaddr *)data; 22259d8d13fSGarrett Wollman if (ifa != 0) 223537ad974SEivind Eklund ifa->ifa_rtrequest = discrtrequest; 22459d8d13fSGarrett Wollman /* 22559d8d13fSGarrett Wollman * Everything else is done at a higher level. 22659d8d13fSGarrett Wollman */ 22759d8d13fSGarrett Wollman break; 22859d8d13fSGarrett Wollman 22959d8d13fSGarrett Wollman case SIOCADDMULTI: 23059d8d13fSGarrett Wollman case SIOCDELMULTI: 23159d8d13fSGarrett Wollman if (ifr == 0) { 23259d8d13fSGarrett Wollman error = EAFNOSUPPORT; /* XXX */ 23359d8d13fSGarrett Wollman break; 23459d8d13fSGarrett Wollman } 23559d8d13fSGarrett Wollman switch (ifr->ifr_addr.sa_family) { 23659d8d13fSGarrett Wollman 23759d8d13fSGarrett Wollman #ifdef INET 23859d8d13fSGarrett Wollman case AF_INET: 23959d8d13fSGarrett Wollman break; 24059d8d13fSGarrett Wollman #endif 241cfa1ca9dSYoshinobu Inoue #ifdef INET6 242cfa1ca9dSYoshinobu Inoue case AF_INET6: 243cfa1ca9dSYoshinobu Inoue break; 244cfa1ca9dSYoshinobu Inoue #endif 24559d8d13fSGarrett Wollman 24659d8d13fSGarrett Wollman default: 24759d8d13fSGarrett Wollman error = EAFNOSUPPORT; 24859d8d13fSGarrett Wollman break; 24959d8d13fSGarrett Wollman } 25059d8d13fSGarrett Wollman break; 25159d8d13fSGarrett Wollman 25259d8d13fSGarrett Wollman case SIOCSIFMTU: 25359d8d13fSGarrett Wollman ifp->if_mtu = ifr->ifr_mtu; 25459d8d13fSGarrett Wollman break; 25559d8d13fSGarrett Wollman 25659d8d13fSGarrett Wollman default: 25759d8d13fSGarrett Wollman error = EINVAL; 25859d8d13fSGarrett Wollman } 25964b15424SJonathan Lemon return (error); 26059d8d13fSGarrett Wollman } 261