if_disc.c revision 120727
1249423Sdim/* 2249423Sdim * Copyright (c) 1982, 1986, 1993 3249423Sdim * The Regents of the University of California. All rights reserved. 4249423Sdim * 5249423Sdim * Redistribution and use in source and binary forms, with or without 6249423Sdim * modification, are permitted provided that the following conditions 7249423Sdim * are met: 8249423Sdim * 1. Redistributions of source code must retain the above copyright 9249423Sdim * notice, this list of conditions and the following disclaimer. 10249423Sdim * 2. Redistributions in binary form must reproduce the above copyright 11249423Sdim * notice, this list of conditions and the following disclaimer in the 12249423Sdim * documentation and/or other materials provided with the distribution. 13249423Sdim * 3. All advertising materials mentioning features or use of this software 14193326Sed * must display the following acknowledgement: 15249423Sdim * This product includes software developed by the University of 16249423Sdim * California, Berkeley and its contributors. 17234353Sdim * 4. Neither the name of the University nor the names of its contributors 18249423Sdim * may be used to endorse or promote products derived from this software 19198092Srdivacky * without specific prior written permission. 20249423Sdim * 21226633Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22249423Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23226633Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24226633Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25193326Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26226633Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29198092Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30226633Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31226633Sdim * SUCH DAMAGE. 32226633Sdim * 33234353Sdim * From: @(#)if_loop.c 8.1 (Berkeley) 6/10/93 34193326Sed * $FreeBSD: head/sys/net/if_disc.c 120727 2003-10-04 03:44:50Z sam $ 35234353Sdim */ 36226633Sdim 37234353Sdim/* 38226633Sdim * Discard interface driver for protocol testing and timing. 39226633Sdim * (Based on the loopback.) 40226633Sdim */ 41226633Sdim 42193326Sed#include <sys/param.h> 43226633Sdim#include <sys/systm.h> 44193326Sed#include <sys/kernel.h> 45226633Sdim#include <sys/malloc.h> 46226633Sdim#include <sys/module.h> 47198092Srdivacky#include <sys/mbuf.h> 48226633Sdim#include <sys/socket.h> 49193326Sed#include <sys/sockio.h> 50226633Sdim 51226633Sdim#include <net/if.h> 52226633Sdim#include <net/if_types.h> 53226633Sdim#include <net/route.h> 54193326Sed#include <net/bpf.h> 55226633Sdim 56226633Sdim#include "opt_inet.h" 57226633Sdim#include "opt_inet6.h" 58226633Sdim 59226633Sdim#ifdef TINY_DSMTU 60226633Sdim#define DSMTU (1024+512) 61226633Sdim#else 62226633Sdim#define DSMTU 65532 63193326Sed#endif 64226633Sdim 65226633Sdim#define DISCNAME "disc" 66198092Srdivacky 67226633Sdimstruct disc_softc { 68226633Sdim struct ifnet sc_if; /* must be first */ 69226633Sdim LIST_ENTRY(disc_softc) sc_list; 70226633Sdim}; 71226633Sdim 72226633Sdimstatic int discoutput(struct ifnet *, struct mbuf *, 73226633Sdim struct sockaddr *, struct rtentry *); 74226633Sdimstatic void discrtrequest(int, struct rtentry *, struct rt_addrinfo *); 75193326Sedstatic int discioctl(struct ifnet *, u_long, caddr_t); 76226633Sdimstatic int disc_clone_create(struct if_clone *, int); 77226633Sdimstatic void disc_clone_destroy(struct ifnet *); 78226633Sdim 79198092Srdivackystatic MALLOC_DEFINE(M_DISC, DISCNAME, "Discard interface"); 80226633Sdimstatic LIST_HEAD(, disc_softc) disc_softc_list; 81226633Sdimstatic struct if_clone disc_cloner = IF_CLONE_INITIALIZER(DISCNAME, 82193326Sed disc_clone_create, disc_clone_destroy, 0, IF_MAXUNIT); 83226633Sdim 84234353Sdimstatic int 85226633Sdimdisc_clone_create(struct if_clone *ifc, int unit) 86198092Srdivacky{ 87226633Sdim struct ifnet *ifp; 88226633Sdim struct disc_softc *sc; 89226633Sdim 90263508Sdim sc = malloc(sizeof(struct disc_softc), M_DISC, M_WAITOK); 91226633Sdim bzero(sc, sizeof(struct disc_softc)); 92226633Sdim 93193326Sed ifp = &sc->sc_if; 94193326Sed 95226633Sdim ifp->if_softc = sc; 96226633Sdim ifp->if_name = DISCNAME; 97226633Sdim ifp->if_unit = unit; 98234353Sdim ifp->if_mtu = DSMTU; 99226633Sdim ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 100226633Sdim ifp->if_ioctl = discioctl; 101226633Sdim ifp->if_output = discoutput; 102226633Sdim ifp->if_type = IFT_LOOP; 103226633Sdim ifp->if_hdrlen = 0; 104226633Sdim ifp->if_addrlen = 0; 105226633Sdim ifp->if_snd.ifq_maxlen = 20; 106226633Sdim if_attach(ifp); 107226633Sdim bpfattach(ifp, DLT_NULL, sizeof(u_int)); 108226633Sdim LIST_INSERT_HEAD(&disc_softc_list, sc, sc_list); 109226633Sdim 110226633Sdim return (0); 111226633Sdim} 112226633Sdim 113226633Sdimstatic void 114226633Sdimdisc_clone_destroy(struct ifnet *ifp) 115226633Sdim{ 116226633Sdim struct disc_softc *sc; 117226633Sdim 118234353Sdim sc = ifp->if_softc; 119226633Sdim 120226633Sdim LIST_REMOVE(sc, sc_list); 121226633Sdim bpfdetach(ifp); 122226633Sdim if_detach(ifp); 123226633Sdim 124226633Sdim free(sc, M_DISC); 125226633Sdim} 126226633Sdim 127226633Sdimstatic int 128226633Sdimdisc_modevent(module_t mod, int type, void *data) 129226633Sdim{ 130193326Sed switch (type) { 131226633Sdim case MOD_LOAD: 132198092Srdivacky LIST_INIT(&disc_softc_list); 133193326Sed if_clone_attach(&disc_cloner); 134226633Sdim break; 135226633Sdim case MOD_UNLOAD: 136226633Sdim if_clone_detach(&disc_cloner); 137193326Sed 138226633Sdim while (!LIST_EMPTY(&disc_softc_list)) 139226633Sdim disc_clone_destroy( 140226633Sdim &LIST_FIRST(&disc_softc_list)->sc_if); 141193326Sed break; 142226633Sdim } 143226633Sdim return 0; 144226633Sdim} 145226633Sdim 146226633Sdimstatic moduledata_t disc_mod = { 147226633Sdim "if_disc", 148226633Sdim disc_modevent, 149226633Sdim NULL 150226633Sdim}; 151226633Sdim 152226633SdimDECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 153226633Sdim 154198092Srdivackystatic int 155234353Sdimdiscoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 156234353Sdim struct rtentry *rt) 157226633Sdim{ 158226633Sdim M_ASSERTPKTHDR(m); 159226633Sdim /* BPF write needs to be handled specially */ 160201361Srdivacky if (dst->sa_family == AF_UNSPEC) { 161226633Sdim dst->sa_family = *(mtod(m, int *)); 162226633Sdim m->m_len -= sizeof(int); 163226633Sdim m->m_pkthdr.len -= sizeof(int); 164226633Sdim m->m_data += sizeof(int); 165226633Sdim } 166226633Sdim 167226633Sdim if (ifp->if_bpf) { 168226633Sdim /* 169226633Sdim * We need to prepend the address family as 170198092Srdivacky * a four byte field. Cons up a dummy header 171226633Sdim * to pacify bpf. This is safe because bpf 172226633Sdim * will only read from the mbuf (i.e., it won't 173218893Sdim * try to free it or keep a pointer a to it). 174226633Sdim */ 175226633Sdim struct mbuf m0; 176226633Sdim u_int af = dst->sa_family; 177226633Sdim 178226633Sdim m0.m_next = m; 179198092Srdivacky m0.m_len = 4; 180226633Sdim m0.m_data = (char *)⁡ 181226633Sdim 182226633Sdim BPF_MTAP(ifp, &m0); 183198092Srdivacky } 184226633Sdim m->m_pkthdr.rcvif = ifp; 185226633Sdim 186226633Sdim ifp->if_opackets++; 187198092Srdivacky ifp->if_obytes += m->m_pkthdr.len; 188226633Sdim 189226633Sdim m_freem(m); 190226633Sdim return 0; 191198092Srdivacky} 192226633Sdim 193226633Sdim/* ARGSUSED */ 194226633Sdimstatic void 195201361Srdivackydiscrtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 196226633Sdim{ 197226633Sdim RT_LOCK_ASSERT(rt); 198226633Sdim 199198092Srdivacky if (rt) 200226633Sdim rt->rt_rmx.rmx_mtu = DSMTU; 201226633Sdim} 202226633Sdim 203198092Srdivacky/* 204226633Sdim * Process an ioctl request. 205226633Sdim */ 206226633Sdimstatic int 207198092Srdivackydiscioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 208226633Sdim{ 209226633Sdim struct ifaddr *ifa; 210226633Sdim struct ifreq *ifr = (struct ifreq *)data; 211226633Sdim int error = 0; 212226633Sdim 213226633Sdim switch (cmd) { 214226633Sdim 215226633Sdim case SIOCSIFADDR: 216226633Sdim ifp->if_flags |= IFF_UP; 217226633Sdim ifa = (struct ifaddr *)data; 218226633Sdim if (ifa != 0) 219226633Sdim ifa->ifa_rtrequest = discrtrequest; 220226633Sdim /* 221226633Sdim * Everything else is done at a higher level. 222226633Sdim */ 223226633Sdim break; 224226633Sdim 225226633Sdim case SIOCADDMULTI: 226226633Sdim case SIOCDELMULTI: 227226633Sdim if (ifr == 0) { 228226633Sdim error = EAFNOSUPPORT; /* XXX */ 229226633Sdim break; 230226633Sdim } 231226633Sdim switch (ifr->ifr_addr.sa_family) { 232226633Sdim 233226633Sdim#ifdef INET 234226633Sdim case AF_INET: 235226633Sdim break; 236226633Sdim#endif 237226633Sdim#ifdef INET6 238226633Sdim case AF_INET6: 239226633Sdim break; 240193326Sed#endif 241226633Sdim 242226633Sdim default: 243193326Sed error = EAFNOSUPPORT; 244226633Sdim break; 245234353Sdim } 246234353Sdim break; 247234353Sdim 248234353Sdim case SIOCSIFMTU: 249234353Sdim ifp->if_mtu = ifr->ifr_mtu; 250234353Sdim break; 251234353Sdim 252234353Sdim default: 253234353Sdim error = EINVAL; 254234353Sdim } 255234353Sdim return (error); 256234353Sdim} 257234353Sdim