1c398230bSWarner Losh /*- 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. 13*fbbd9655SWarner Losh * 3. 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> 4876039bc8SGleb Smirnoff #include <net/if_var.h> 49f889d2efSBrooks Davis #include <net/if_clone.h> 5059d8d13fSGarrett Wollman #include <net/if_types.h> 5159d8d13fSGarrett Wollman #include <net/route.h> 5259d8d13fSGarrett Wollman #include <net/bpf.h> 53d6f59204SHiroki Sato #include <net/vnet.h> 5459d8d13fSGarrett Wollman 551d5e9e22SEivind Eklund #include "opt_inet.h" 56cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 5759d8d13fSGarrett Wollman 5859d8d13fSGarrett Wollman #ifdef TINY_DSMTU 5959d8d13fSGarrett Wollman #define DSMTU (1024+512) 6059d8d13fSGarrett Wollman #else 6159d8d13fSGarrett Wollman #define DSMTU 65532 6259d8d13fSGarrett Wollman #endif 6359d8d13fSGarrett Wollman 64c69b7ffeSBrooks Davis struct disc_softc { 6570e04181SYaroslav Tykhiy struct ifnet *sc_ifp; 66c69b7ffeSBrooks Davis }; 67c69b7ffeSBrooks Davis 68eb6bd594SMark Murray static int discoutput(struct ifnet *, struct mbuf *, 6947e8d432SGleb Smirnoff const struct sockaddr *, struct route *); 70537ad974SEivind Eklund static int discioctl(struct ifnet *, u_long, caddr_t); 716b7330e2SSam Leffler static int disc_clone_create(struct if_clone *, int, caddr_t); 72c69b7ffeSBrooks Davis static void disc_clone_destroy(struct ifnet *); 7359d8d13fSGarrett Wollman 7442a58907SGleb Smirnoff static const char discname[] = "disc"; 7542a58907SGleb Smirnoff static MALLOC_DEFINE(M_DISC, discname, "Discard interface"); 76f889d2efSBrooks Davis 77d6f59204SHiroki Sato static VNET_DEFINE(struct if_clone *, disc_cloner); 78d6f59204SHiroki Sato #define V_disc_cloner VNET(disc_cloner) 79c69b7ffeSBrooks Davis 80c69b7ffeSBrooks Davis static int 816b7330e2SSam Leffler disc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 8259d8d13fSGarrett Wollman { 83c69b7ffeSBrooks Davis struct ifnet *ifp; 84c69b7ffeSBrooks Davis struct disc_softc *sc; 8559d8d13fSGarrett Wollman 8660323f48SBruce M Simpson sc = malloc(sizeof(struct disc_softc), M_DISC, M_WAITOK | M_ZERO); 87fc74a9f9SBrooks Davis ifp = sc->sc_ifp = if_alloc(IFT_LOOP); 88fc74a9f9SBrooks Davis if (ifp == NULL) { 89fc74a9f9SBrooks Davis free(sc, M_DISC); 90fc74a9f9SBrooks Davis return (ENOSPC); 91fc74a9f9SBrooks Davis } 92c69b7ffeSBrooks Davis 93c69b7ffeSBrooks Davis ifp->if_softc = sc; 9442a58907SGleb Smirnoff if_initname(ifp, discname, unit); 9559d8d13fSGarrett Wollman ifp->if_mtu = DSMTU; 9668b11e74SYaroslav Tykhiy /* 9768b11e74SYaroslav Tykhiy * IFF_LOOPBACK should not be removed from disc's flags because 9868b11e74SYaroslav Tykhiy * it controls what PF-specific routes are magically added when 9968b11e74SYaroslav Tykhiy * a network address is assigned to the interface. Things just 10068b11e74SYaroslav Tykhiy * won't work as intended w/o such routes because the output 10168b11e74SYaroslav Tykhiy * interface selection for a packet is totally route-driven. 10268b11e74SYaroslav Tykhiy * A valid alternative to IFF_LOOPBACK can be IFF_BROADCAST or 10368b11e74SYaroslav Tykhiy * IFF_POINTOPOINT, but it would result in different properties 10468b11e74SYaroslav Tykhiy * of the interface. 10568b11e74SYaroslav Tykhiy */ 10659d8d13fSGarrett Wollman ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 107d314617eSGleb Smirnoff ifp->if_drv_flags = IFF_DRV_RUNNING; 108537ad974SEivind Eklund ifp->if_ioctl = discioctl; 109537ad974SEivind Eklund ifp->if_output = discoutput; 11059d8d13fSGarrett Wollman ifp->if_hdrlen = 0; 11159d8d13fSGarrett Wollman ifp->if_addrlen = 0; 112422fd76fSPoul-Henning Kamp ifp->if_snd.ifq_maxlen = 20; 11359d8d13fSGarrett Wollman if_attach(ifp); 11401399f34SDavid Malone bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); 115c69b7ffeSBrooks Davis 116c69b7ffeSBrooks Davis return (0); 117c69b7ffeSBrooks Davis } 118c69b7ffeSBrooks Davis 119c69b7ffeSBrooks Davis static void 120c69b7ffeSBrooks Davis disc_clone_destroy(struct ifnet *ifp) 121c69b7ffeSBrooks Davis { 122c69b7ffeSBrooks Davis struct disc_softc *sc; 123c69b7ffeSBrooks Davis 124c69b7ffeSBrooks Davis sc = ifp->if_softc; 125c69b7ffeSBrooks Davis 126febd0759SAndrew Thompson bpfdetach(ifp); 127febd0759SAndrew Thompson if_detach(ifp); 128febd0759SAndrew Thompson if_free(ifp); 129febd0759SAndrew Thompson 130febd0759SAndrew Thompson free(sc, M_DISC); 13159d8d13fSGarrett Wollman } 13259d8d13fSGarrett Wollman 133d6f59204SHiroki Sato static void 134d6f59204SHiroki Sato vnet_disc_init(const void *unused __unused) 135d6f59204SHiroki Sato { 136d6f59204SHiroki Sato 137d6f59204SHiroki Sato V_disc_cloner = if_clone_simple(discname, disc_clone_create, 138d6f59204SHiroki Sato disc_clone_destroy, 0); 139d6f59204SHiroki Sato } 14089856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_disc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 141d6f59204SHiroki Sato vnet_disc_init, NULL); 142d6f59204SHiroki Sato 143d6f59204SHiroki Sato static void 144d6f59204SHiroki Sato vnet_disc_uninit(const void *unused __unused) 145d6f59204SHiroki Sato { 146d6f59204SHiroki Sato 147d6f59204SHiroki Sato if_clone_detach(V_disc_cloner); 148d6f59204SHiroki Sato } 14989856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_disc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 150d6f59204SHiroki Sato vnet_disc_uninit, NULL); 151d6f59204SHiroki Sato 15259d8d13fSGarrett Wollman static int 1532b120974SPeter Wemm disc_modevent(module_t mod, int type, void *data) 1542b120974SPeter Wemm { 155d6e2616aSRobert Watson 1562b120974SPeter Wemm switch (type) { 1572b120974SPeter Wemm case MOD_LOAD: 1582b120974SPeter Wemm case MOD_UNLOAD: 159c69b7ffeSBrooks Davis break; 1603e019deaSPoul-Henning Kamp default: 1613e019deaSPoul-Henning Kamp return (EOPNOTSUPP); 1622b120974SPeter Wemm } 163832cb4aeSBruce M Simpson return (0); 1642b120974SPeter Wemm } 1652b120974SPeter Wemm 1662b120974SPeter Wemm static moduledata_t disc_mod = { 1672b120974SPeter Wemm "if_disc", 1682b120974SPeter Wemm disc_modevent, 1692b120974SPeter Wemm NULL 1702b120974SPeter Wemm }; 1712b120974SPeter Wemm 1722b120974SPeter Wemm DECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1732b120974SPeter Wemm 1742b120974SPeter Wemm static int 17547e8d432SGleb Smirnoff discoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 176279aa3d4SKip Macy struct route *ro) 17759d8d13fSGarrett Wollman { 17801399f34SDavid Malone u_int32_t af; 179832cb4aeSBruce M Simpson 180fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m); 181832cb4aeSBruce M Simpson 18201399f34SDavid Malone /* BPF writes need to be handled specially. */ 18347e8d432SGleb Smirnoff if (dst->sa_family == AF_UNSPEC) 18401399f34SDavid Malone bcopy(dst->sa_data, &af, sizeof(af)); 18547e8d432SGleb Smirnoff else 18647e8d432SGleb Smirnoff af = dst->sa_family; 187963e4c2aSGarrett Wollman 18847e8d432SGleb Smirnoff if (bpf_peers_present(ifp->if_bpf)) 189437ffe18SSam Leffler bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 19047e8d432SGleb Smirnoff 19159d8d13fSGarrett Wollman m->m_pkthdr.rcvif = ifp; 19259d8d13fSGarrett Wollman 1933751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 1943751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); 19559d8d13fSGarrett Wollman 19659d8d13fSGarrett Wollman m_freem(m); 197832cb4aeSBruce M Simpson return (0); 19859d8d13fSGarrett Wollman } 19959d8d13fSGarrett Wollman 20059d8d13fSGarrett Wollman /* 20159d8d13fSGarrett Wollman * Process an ioctl request. 20259d8d13fSGarrett Wollman */ 20388e2f526SBruce Evans static int 204eb6bd594SMark Murray discioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 20559d8d13fSGarrett Wollman { 206eb6bd594SMark Murray struct ifreq *ifr = (struct ifreq *)data; 207eb6bd594SMark Murray int error = 0; 20859d8d13fSGarrett Wollman 20959d8d13fSGarrett Wollman switch (cmd) { 21059d8d13fSGarrett Wollman case SIOCSIFADDR: 21159d8d13fSGarrett Wollman ifp->if_flags |= IFF_UP; 2121a75e3b2SAlexander V. Chernikov 21359d8d13fSGarrett Wollman /* 21459d8d13fSGarrett Wollman * Everything else is done at a higher level. 21559d8d13fSGarrett Wollman */ 21659d8d13fSGarrett Wollman break; 21759d8d13fSGarrett Wollman case SIOCADDMULTI: 21859d8d13fSGarrett Wollman case SIOCDELMULTI: 219155d72c4SPedro F. Giffuni if (ifr == NULL) { 22059d8d13fSGarrett Wollman error = EAFNOSUPPORT; /* XXX */ 22159d8d13fSGarrett Wollman break; 22259d8d13fSGarrett Wollman } 22359d8d13fSGarrett Wollman switch (ifr->ifr_addr.sa_family) { 22459d8d13fSGarrett Wollman #ifdef INET 22559d8d13fSGarrett Wollman case AF_INET: 22659d8d13fSGarrett Wollman break; 22759d8d13fSGarrett Wollman #endif 228cfa1ca9dSYoshinobu Inoue #ifdef INET6 229cfa1ca9dSYoshinobu Inoue case AF_INET6: 230cfa1ca9dSYoshinobu Inoue break; 231cfa1ca9dSYoshinobu Inoue #endif 23259d8d13fSGarrett Wollman default: 23359d8d13fSGarrett Wollman error = EAFNOSUPPORT; 23459d8d13fSGarrett Wollman break; 23559d8d13fSGarrett Wollman } 23659d8d13fSGarrett Wollman break; 23759d8d13fSGarrett Wollman case SIOCSIFMTU: 23859d8d13fSGarrett Wollman ifp->if_mtu = ifr->ifr_mtu; 23959d8d13fSGarrett Wollman break; 24059d8d13fSGarrett Wollman default: 24159d8d13fSGarrett Wollman error = EINVAL; 24259d8d13fSGarrett Wollman } 24364b15424SJonathan Lemon return (error); 24459d8d13fSGarrett Wollman } 245