if_disc.c revision 139823
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: head/sys/net/if_disc.c 139823 2005-01-07 01:45:51Z imp $ 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 6297290Sbrooks#define DISCNAME "disc" 6310429Sbde 6497290Sbrooksstruct disc_softc { 6597290Sbrooks struct ifnet sc_if; /* must be first */ 6697290Sbrooks LIST_ENTRY(disc_softc) sc_list; 6797290Sbrooks}; 685191Swollman 6997290Sbrooksstatic int discoutput(struct ifnet *, struct mbuf *, 7097290Sbrooks struct sockaddr *, struct rtentry *); 7197290Sbrooksstatic void discrtrequest(int, struct rtentry *, struct rt_addrinfo *); 7297290Sbrooksstatic int discioctl(struct ifnet *, u_long, caddr_t); 7397290Sbrooksstatic int disc_clone_create(struct if_clone *, int); 7497290Sbrooksstatic void disc_clone_destroy(struct ifnet *); 7597290Sbrooks 76126777Srwatsonstatic struct mtx disc_mtx; 7797290Sbrooksstatic MALLOC_DEFINE(M_DISC, DISCNAME, "Discard interface"); 7897290Sbrooksstatic LIST_HEAD(, disc_softc) disc_softc_list; 7997290Sbrooks 80130933SbrooksIFC_SIMPLE_DECLARE(disc, 0); 81130933Sbrooks 8297290Sbrooksstatic int 8397290Sbrooksdisc_clone_create(struct if_clone *ifc, int unit) 845191Swollman{ 8597290Sbrooks struct ifnet *ifp; 8697290Sbrooks struct disc_softc *sc; 875191Swollman 88131670Sbms sc = malloc(sizeof(struct disc_softc), M_DISC, M_WAITOK | M_ZERO); 8997290Sbrooks 9097290Sbrooks ifp = &sc->sc_if; 9197290Sbrooks 9297290Sbrooks ifp->if_softc = sc; 93121816Sbrooks if_initname(ifp, ifc->ifc_name, unit); 945191Swollman ifp->if_mtu = DSMTU; 955191Swollman ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; 9641757Seivind ifp->if_ioctl = discioctl; 9741757Seivind ifp->if_output = discoutput; 985191Swollman ifp->if_type = IFT_LOOP; 995191Swollman ifp->if_hdrlen = 0; 1005191Swollman ifp->if_addrlen = 0; 10153115Sphk ifp->if_snd.ifq_maxlen = 20; 1025191Swollman if_attach(ifp); 10313937Swollman bpfattach(ifp, DLT_NULL, sizeof(u_int)); 104126777Srwatson mtx_lock(&disc_mtx); 10597290Sbrooks LIST_INSERT_HEAD(&disc_softc_list, sc, sc_list); 106126777Srwatson mtx_unlock(&disc_mtx); 10797290Sbrooks 10897290Sbrooks return (0); 1095191Swollman} 1105191Swollman 11197290Sbrooksstatic void 112126777Srwatsondisc_destroy(struct disc_softc *sc) 113126777Srwatson{ 114126777Srwatson 115126777Srwatson bpfdetach(&sc->sc_if); 116126777Srwatson if_detach(&sc->sc_if); 117126777Srwatson 118126777Srwatson free(sc, M_DISC); 119126777Srwatson} 120126777Srwatson 121126777Srwatsonstatic void 12297290Sbrooksdisc_clone_destroy(struct ifnet *ifp) 12397290Sbrooks{ 12497290Sbrooks struct disc_softc *sc; 12597290Sbrooks 12697290Sbrooks sc = ifp->if_softc; 127126777Srwatson mtx_lock(&disc_mtx); 12897290Sbrooks LIST_REMOVE(sc, sc_list); 129126777Srwatson mtx_unlock(&disc_mtx); 13097290Sbrooks 131126777Srwatson disc_destroy(sc); 13297290Sbrooks} 13397290Sbrooks 1345191Swollmanstatic int 135131669Sbmsdisc_modevent(module_t mod, int type, void *data) 136126777Srwatson{ 137126777Srwatson struct disc_softc *sc; 138126777Srwatson 139131669Sbms switch (type) { 140131669Sbms case MOD_LOAD: 141126777Srwatson mtx_init(&disc_mtx, "disc_mtx", NULL, MTX_DEF); 14297290Sbrooks LIST_INIT(&disc_softc_list); 14397290Sbrooks if_clone_attach(&disc_cloner); 144131669Sbms break; 145131669Sbms case MOD_UNLOAD: 14697290Sbrooks if_clone_detach(&disc_cloner); 14797290Sbrooks 148126777Srwatson mtx_lock(&disc_mtx); 149126777Srwatson while ((sc = LIST_FIRST(&disc_softc_list)) != NULL) { 150126777Srwatson LIST_REMOVE(sc, sc_list); 151126777Srwatson mtx_unlock(&disc_mtx); 152126777Srwatson disc_destroy(sc); 153126777Srwatson mtx_lock(&disc_mtx); 154126777Srwatson } 155126777Srwatson mtx_unlock(&disc_mtx); 156126777Srwatson mtx_destroy(&disc_mtx); 15797290Sbrooks break; 158132199Sphk default: 159132199Sphk return (EOPNOTSUPP); 160131669Sbms } 161131669Sbms return (0); 162131669Sbms} 16371862Speter 164131669Sbmsstatic moduledata_t disc_mod = { 165131669Sbms "if_disc", 166131669Sbms disc_modevent, 16771862Speter NULL 168131669Sbms}; 16971862Speter 17071862SpeterDECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 17171862Speter 17271862Speterstatic int 17378351Smarkmdiscoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 17478351Smarkm struct rtentry *rt) 1755191Swollman{ 176131669Sbms 177113255Sdes M_ASSERTPKTHDR(m); 178131669Sbms 17910957Swollman /* BPF write needs to be handled specially */ 18010957Swollman if (dst->sa_family == AF_UNSPEC) { 18110957Swollman dst->sa_family = *(mtod(m, int *)); 18210957Swollman m->m_len -= sizeof(int); 18310957Swollman m->m_pkthdr.len -= sizeof(int); 18410957Swollman m->m_data += sizeof(int); 18510957Swollman } 18610957Swollman 18797290Sbrooks if (ifp->if_bpf) { 1885191Swollman u_int af = dst->sa_family; 189123922Ssam bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); 1905191Swollman } 1915191Swollman m->m_pkthdr.rcvif = ifp; 1925191Swollman 1935191Swollman ifp->if_opackets++; 1945191Swollman ifp->if_obytes += m->m_pkthdr.len; 1955191Swollman 1965191Swollman m_freem(m); 197131669Sbms return (0); 1985191Swollman} 1995191Swollman 2005191Swollman/* ARGSUSED */ 2015191Swollmanstatic void 20285074Srudiscrtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) 2035191Swollman{ 204120727Ssam RT_LOCK_ASSERT(rt); 205120727Ssam 2065191Swollman if (rt) 2075191Swollman rt->rt_rmx.rmx_mtu = DSMTU; 2085191Swollman} 2095191Swollman 2105191Swollman/* 2115191Swollman * Process an ioctl request. 2125191Swollman */ 21312611Sbdestatic int 21478351Smarkmdiscioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2155191Swollman{ 21678351Smarkm struct ifaddr *ifa; 21778351Smarkm struct ifreq *ifr = (struct ifreq *)data; 21878351Smarkm int error = 0; 2195191Swollman 2205191Swollman switch (cmd) { 2215191Swollman 2225191Swollman case SIOCSIFADDR: 2235191Swollman ifp->if_flags |= IFF_UP; 2245191Swollman ifa = (struct ifaddr *)data; 2255191Swollman if (ifa != 0) 22641757Seivind ifa->ifa_rtrequest = discrtrequest; 2275191Swollman /* 2285191Swollman * Everything else is done at a higher level. 2295191Swollman */ 2305191Swollman break; 2315191Swollman 2325191Swollman case SIOCADDMULTI: 2335191Swollman case SIOCDELMULTI: 2345191Swollman if (ifr == 0) { 2355191Swollman error = EAFNOSUPPORT; /* XXX */ 2365191Swollman break; 2375191Swollman } 2385191Swollman switch (ifr->ifr_addr.sa_family) { 2395191Swollman 2405191Swollman#ifdef INET 2415191Swollman case AF_INET: 2425191Swollman break; 2435191Swollman#endif 24454263Sshin#ifdef INET6 24554263Sshin case AF_INET6: 24654263Sshin break; 24754263Sshin#endif 2485191Swollman 2495191Swollman default: 2505191Swollman error = EAFNOSUPPORT; 2515191Swollman break; 2525191Swollman } 2535191Swollman break; 2545191Swollman 2555191Swollman case SIOCSIFMTU: 2565191Swollman ifp->if_mtu = ifr->ifr_mtu; 2575191Swollman break; 2585191Swollman 2595191Swollman default: 2605191Swollman error = EINVAL; 2615191Swollman } 26287912Sjlemon return (error); 2635191Swollman} 264