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);
88c69b7ffeSBrooks Davis ifp->if_softc = sc;
8942a58907SGleb Smirnoff if_initname(ifp, discname, unit);
9059d8d13fSGarrett Wollman ifp->if_mtu = DSMTU;
9168b11e74SYaroslav Tykhiy /*
9268b11e74SYaroslav Tykhiy * IFF_LOOPBACK should not be removed from disc's flags because
9368b11e74SYaroslav Tykhiy * it controls what PF-specific routes are magically added when
9468b11e74SYaroslav Tykhiy * a network address is assigned to the interface. Things just
9568b11e74SYaroslav Tykhiy * won't work as intended w/o such routes because the output
9668b11e74SYaroslav Tykhiy * interface selection for a packet is totally route-driven.
9768b11e74SYaroslav Tykhiy * A valid alternative to IFF_LOOPBACK can be IFF_BROADCAST or
9868b11e74SYaroslav Tykhiy * IFF_POINTOPOINT, but it would result in different properties
9968b11e74SYaroslav Tykhiy * of the interface.
10068b11e74SYaroslav Tykhiy */
10159d8d13fSGarrett Wollman ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
102d314617eSGleb Smirnoff ifp->if_drv_flags = IFF_DRV_RUNNING;
103537ad974SEivind Eklund ifp->if_ioctl = discioctl;
104537ad974SEivind Eklund ifp->if_output = discoutput;
10559d8d13fSGarrett Wollman ifp->if_hdrlen = 0;
10659d8d13fSGarrett Wollman ifp->if_addrlen = 0;
107422fd76fSPoul-Henning Kamp ifp->if_snd.ifq_maxlen = 20;
10859d8d13fSGarrett Wollman if_attach(ifp);
10901399f34SDavid Malone bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
110c69b7ffeSBrooks Davis
111c69b7ffeSBrooks Davis return (0);
112c69b7ffeSBrooks Davis }
113c69b7ffeSBrooks Davis
114c69b7ffeSBrooks Davis static void
disc_clone_destroy(struct ifnet * ifp)115c69b7ffeSBrooks Davis disc_clone_destroy(struct ifnet *ifp)
116c69b7ffeSBrooks Davis {
117c69b7ffeSBrooks Davis struct disc_softc *sc;
118c69b7ffeSBrooks Davis
119c69b7ffeSBrooks Davis sc = ifp->if_softc;
120c69b7ffeSBrooks Davis
121febd0759SAndrew Thompson bpfdetach(ifp);
122febd0759SAndrew Thompson if_detach(ifp);
123febd0759SAndrew Thompson if_free(ifp);
124febd0759SAndrew Thompson
125febd0759SAndrew Thompson free(sc, M_DISC);
12659d8d13fSGarrett Wollman }
12759d8d13fSGarrett Wollman
128d6f59204SHiroki Sato static void
vnet_disc_init(const void * unused __unused)129d6f59204SHiroki Sato vnet_disc_init(const void *unused __unused)
130d6f59204SHiroki Sato {
131d6f59204SHiroki Sato
132d6f59204SHiroki Sato V_disc_cloner = if_clone_simple(discname, disc_clone_create,
133d6f59204SHiroki Sato disc_clone_destroy, 0);
134d6f59204SHiroki Sato }
13589856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_disc_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
136d6f59204SHiroki Sato vnet_disc_init, NULL);
137d6f59204SHiroki Sato
138d6f59204SHiroki Sato static void
vnet_disc_uninit(const void * unused __unused)139d6f59204SHiroki Sato vnet_disc_uninit(const void *unused __unused)
140d6f59204SHiroki Sato {
141d6f59204SHiroki Sato
142d6f59204SHiroki Sato if_clone_detach(V_disc_cloner);
143d6f59204SHiroki Sato }
14489856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_disc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
145d6f59204SHiroki Sato vnet_disc_uninit, NULL);
146d6f59204SHiroki Sato
14759d8d13fSGarrett Wollman static int
disc_modevent(module_t mod,int type,void * data)1482b120974SPeter Wemm disc_modevent(module_t mod, int type, void *data)
1492b120974SPeter Wemm {
150d6e2616aSRobert Watson
1512b120974SPeter Wemm switch (type) {
1522b120974SPeter Wemm case MOD_LOAD:
1532b120974SPeter Wemm case MOD_UNLOAD:
154c69b7ffeSBrooks Davis break;
1553e019deaSPoul-Henning Kamp default:
1563e019deaSPoul-Henning Kamp return (EOPNOTSUPP);
1572b120974SPeter Wemm }
158832cb4aeSBruce M Simpson return (0);
1592b120974SPeter Wemm }
1602b120974SPeter Wemm
1612b120974SPeter Wemm static moduledata_t disc_mod = {
1622b120974SPeter Wemm "if_disc",
1632b120974SPeter Wemm disc_modevent,
1642b120974SPeter Wemm NULL
1652b120974SPeter Wemm };
1662b120974SPeter Wemm
1672b120974SPeter Wemm DECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
1682b120974SPeter Wemm
1692b120974SPeter Wemm static int
discoutput(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro)17047e8d432SGleb Smirnoff discoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
171279aa3d4SKip Macy struct route *ro)
17259d8d13fSGarrett Wollman {
17301399f34SDavid Malone u_int32_t af;
174832cb4aeSBruce M Simpson
175fe584538SDag-Erling Smørgrav M_ASSERTPKTHDR(m);
176832cb4aeSBruce M Simpson
17701399f34SDavid Malone /* BPF writes need to be handled specially. */
178*2cb0fce2SSeth Hoffert if (dst->sa_family == AF_UNSPEC || dst->sa_family == pseudo_AF_HDRCMPLT)
17901399f34SDavid Malone bcopy(dst->sa_data, &af, sizeof(af));
18047e8d432SGleb Smirnoff else
18162e1a437SZhenlei Huang af = RO_GET_FAMILY(ro, dst);
182963e4c2aSGarrett Wollman
18347e8d432SGleb Smirnoff if (bpf_peers_present(ifp->if_bpf))
184437ffe18SSam Leffler bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
18547e8d432SGleb Smirnoff
18659d8d13fSGarrett Wollman m->m_pkthdr.rcvif = ifp;
18759d8d13fSGarrett Wollman
1883751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1893751dddbSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
19059d8d13fSGarrett Wollman
19159d8d13fSGarrett Wollman m_freem(m);
192832cb4aeSBruce M Simpson return (0);
19359d8d13fSGarrett Wollman }
19459d8d13fSGarrett Wollman
19559d8d13fSGarrett Wollman /*
19659d8d13fSGarrett Wollman * Process an ioctl request.
19759d8d13fSGarrett Wollman */
19888e2f526SBruce Evans static int
discioctl(struct ifnet * ifp,u_long cmd,caddr_t data)199eb6bd594SMark Murray discioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
20059d8d13fSGarrett Wollman {
201eb6bd594SMark Murray struct ifreq *ifr = (struct ifreq *)data;
202eb6bd594SMark Murray int error = 0;
20359d8d13fSGarrett Wollman
20459d8d13fSGarrett Wollman switch (cmd) {
20559d8d13fSGarrett Wollman case SIOCSIFADDR:
20659d8d13fSGarrett Wollman ifp->if_flags |= IFF_UP;
2071a75e3b2SAlexander V. Chernikov
20859d8d13fSGarrett Wollman /*
20959d8d13fSGarrett Wollman * Everything else is done at a higher level.
21059d8d13fSGarrett Wollman */
21159d8d13fSGarrett Wollman break;
21259d8d13fSGarrett Wollman case SIOCADDMULTI:
21359d8d13fSGarrett Wollman case SIOCDELMULTI:
214155d72c4SPedro F. Giffuni if (ifr == NULL) {
21559d8d13fSGarrett Wollman error = EAFNOSUPPORT; /* XXX */
21659d8d13fSGarrett Wollman break;
21759d8d13fSGarrett Wollman }
21859d8d13fSGarrett Wollman switch (ifr->ifr_addr.sa_family) {
21959d8d13fSGarrett Wollman #ifdef INET
22059d8d13fSGarrett Wollman case AF_INET:
22159d8d13fSGarrett Wollman break;
22259d8d13fSGarrett Wollman #endif
223cfa1ca9dSYoshinobu Inoue #ifdef INET6
224cfa1ca9dSYoshinobu Inoue case AF_INET6:
225cfa1ca9dSYoshinobu Inoue break;
226cfa1ca9dSYoshinobu Inoue #endif
22759d8d13fSGarrett Wollman default:
22859d8d13fSGarrett Wollman error = EAFNOSUPPORT;
22959d8d13fSGarrett Wollman break;
23059d8d13fSGarrett Wollman }
23159d8d13fSGarrett Wollman break;
23259d8d13fSGarrett Wollman case SIOCSIFMTU:
23359d8d13fSGarrett Wollman ifp->if_mtu = ifr->ifr_mtu;
23459d8d13fSGarrett Wollman break;
23559d8d13fSGarrett Wollman default:
23659d8d13fSGarrett Wollman error = EINVAL;
23759d8d13fSGarrett Wollman }
23864b15424SJonathan Lemon return (error);
23959d8d13fSGarrett Wollman }
240