xref: /freebsd/sys/net/if_disc.c (revision 2cb0fce2)
1c398230bSWarner Losh /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
459d8d13fSGarrett Wollman  * Copyright (c) 1982, 1986, 1993
559d8d13fSGarrett Wollman  *	The Regents of the University of California.  All rights reserved.
659d8d13fSGarrett Wollman  *
759d8d13fSGarrett Wollman  * Redistribution and use in source and binary forms, with or without
859d8d13fSGarrett Wollman  * modification, are permitted provided that the following conditions
959d8d13fSGarrett Wollman  * are met:
1059d8d13fSGarrett Wollman  * 1. Redistributions of source code must retain the above copyright
1159d8d13fSGarrett Wollman  *    notice, this list of conditions and the following disclaimer.
1259d8d13fSGarrett Wollman  * 2. Redistributions in binary form must reproduce the above copyright
1359d8d13fSGarrett Wollman  *    notice, this list of conditions and the following disclaimer in the
1459d8d13fSGarrett Wollman  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
1659d8d13fSGarrett Wollman  *    may be used to endorse or promote products derived from this software
1759d8d13fSGarrett Wollman  *    without specific prior written permission.
1859d8d13fSGarrett Wollman  *
1959d8d13fSGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2059d8d13fSGarrett Wollman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2159d8d13fSGarrett Wollman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2259d8d13fSGarrett Wollman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2359d8d13fSGarrett Wollman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2459d8d13fSGarrett Wollman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2559d8d13fSGarrett Wollman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2659d8d13fSGarrett Wollman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2759d8d13fSGarrett Wollman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2859d8d13fSGarrett Wollman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2959d8d13fSGarrett Wollman  * SUCH DAMAGE.
3059d8d13fSGarrett Wollman  */
3159d8d13fSGarrett Wollman 
3259d8d13fSGarrett Wollman /*
3359d8d13fSGarrett Wollman  * Discard interface driver for protocol testing and timing.
3459d8d13fSGarrett Wollman  * (Based on the loopback.)
3559d8d13fSGarrett Wollman  */
3659d8d13fSGarrett Wollman 
3759d8d13fSGarrett Wollman #include <sys/param.h>
3859d8d13fSGarrett Wollman #include <sys/systm.h>
3959d8d13fSGarrett Wollman #include <sys/kernel.h>
40c69b7ffeSBrooks Davis #include <sys/malloc.h>
412b120974SPeter Wemm #include <sys/module.h>
4259d8d13fSGarrett Wollman #include <sys/mbuf.h>
4359d8d13fSGarrett Wollman #include <sys/socket.h>
4451a53488SBruce Evans #include <sys/sockio.h>
4559d8d13fSGarrett Wollman 
4659d8d13fSGarrett Wollman #include <net/if.h>
4776039bc8SGleb Smirnoff #include <net/if_var.h>
482c2b37adSJustin Hibbits #include <net/if_private.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 
775f901c92SAndrew Turner VNET_DEFINE_STATIC(struct if_clone *, disc_cloner);
78d6f59204SHiroki Sato #define	V_disc_cloner	VNET(disc_cloner)
79c69b7ffeSBrooks Davis 
80c69b7ffeSBrooks Davis static int
disc_clone_create(struct if_clone * ifc,int unit,caddr_t params)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
disc_clone_destroy(struct ifnet * ifp)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
vnet_disc_init(const void * unused __unused)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
vnet_disc_uninit(const void * unused __unused)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
disc_modevent(module_t mod,int type,void * data)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
discoutput(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro)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. */
1832cb0fce2SSeth Hoffert 	if (dst->sa_family == AF_UNSPEC || dst->sa_family == pseudo_AF_HDRCMPLT)
18401399f34SDavid Malone 		bcopy(dst->sa_data, &af, sizeof(af));
18547e8d432SGleb Smirnoff 	else
18662e1a437SZhenlei Huang 		af = RO_GET_FAMILY(ro, dst);
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
discioctl(struct ifnet * ifp,u_long cmd,caddr_t data)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