Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/net/if_disc.c
39477 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1982, 1986, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
/*
33
* Discard interface driver for protocol testing and timing.
34
* (Based on the loopback.)
35
*/
36
37
#include <sys/param.h>
38
#include <sys/systm.h>
39
#include <sys/kernel.h>
40
#include <sys/malloc.h>
41
#include <sys/module.h>
42
#include <sys/mbuf.h>
43
#include <sys/socket.h>
44
#include <sys/sockio.h>
45
46
#include <net/if.h>
47
#include <net/if_var.h>
48
#include <net/if_private.h>
49
#include <net/if_clone.h>
50
#include <net/if_types.h>
51
#include <net/route.h>
52
#include <net/bpf.h>
53
#include <net/vnet.h>
54
55
#include "opt_inet.h"
56
#include "opt_inet6.h"
57
58
#ifdef TINY_DSMTU
59
#define DSMTU (1024+512)
60
#else
61
#define DSMTU 65532
62
#endif
63
64
struct disc_softc {
65
struct ifnet *sc_ifp;
66
};
67
68
static int discoutput(struct ifnet *, struct mbuf *,
69
const struct sockaddr *, struct route *);
70
static int discioctl(struct ifnet *, u_long, caddr_t);
71
static int disc_clone_create(struct if_clone *, int, caddr_t);
72
static void disc_clone_destroy(struct ifnet *);
73
74
static const char discname[] = "disc";
75
static MALLOC_DEFINE(M_DISC, discname, "Discard interface");
76
77
VNET_DEFINE_STATIC(struct if_clone *, disc_cloner);
78
#define V_disc_cloner VNET(disc_cloner)
79
80
static int
81
disc_clone_create(struct if_clone *ifc, int unit, caddr_t params)
82
{
83
struct ifnet *ifp;
84
struct disc_softc *sc;
85
86
sc = malloc(sizeof(struct disc_softc), M_DISC, M_WAITOK | M_ZERO);
87
ifp = sc->sc_ifp = if_alloc(IFT_LOOP);
88
ifp->if_softc = sc;
89
if_initname(ifp, discname, unit);
90
ifp->if_mtu = DSMTU;
91
/*
92
* IFF_LOOPBACK should not be removed from disc's flags because
93
* it controls what PF-specific routes are magically added when
94
* a network address is assigned to the interface. Things just
95
* won't work as intended w/o such routes because the output
96
* interface selection for a packet is totally route-driven.
97
* A valid alternative to IFF_LOOPBACK can be IFF_BROADCAST or
98
* IFF_POINTOPOINT, but it would result in different properties
99
* of the interface.
100
*/
101
ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
102
ifp->if_drv_flags = IFF_DRV_RUNNING;
103
ifp->if_ioctl = discioctl;
104
ifp->if_output = discoutput;
105
ifp->if_hdrlen = 0;
106
ifp->if_addrlen = 0;
107
ifp->if_snd.ifq_maxlen = 20;
108
if_attach(ifp);
109
bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
110
111
return (0);
112
}
113
114
static void
115
disc_clone_destroy(struct ifnet *ifp)
116
{
117
struct disc_softc *sc;
118
119
sc = ifp->if_softc;
120
121
bpfdetach(ifp);
122
if_detach(ifp);
123
if_free(ifp);
124
125
free(sc, M_DISC);
126
}
127
128
static void
129
vnet_disc_init(const void *unused __unused)
130
{
131
132
V_disc_cloner = if_clone_simple(discname, disc_clone_create,
133
disc_clone_destroy, 0);
134
}
135
VNET_SYSINIT(vnet_disc_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
136
vnet_disc_init, NULL);
137
138
static void
139
vnet_disc_uninit(const void *unused __unused)
140
{
141
142
if_clone_detach(V_disc_cloner);
143
}
144
VNET_SYSUNINIT(vnet_disc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
145
vnet_disc_uninit, NULL);
146
147
static int
148
disc_modevent(module_t mod, int type, void *data)
149
{
150
151
switch (type) {
152
case MOD_LOAD:
153
case MOD_UNLOAD:
154
break;
155
default:
156
return (EOPNOTSUPP);
157
}
158
return (0);
159
}
160
161
static moduledata_t disc_mod = {
162
"if_disc",
163
disc_modevent,
164
NULL
165
};
166
167
DECLARE_MODULE(if_disc, disc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
168
169
static int
170
discoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
171
struct route *ro)
172
{
173
u_int32_t af;
174
175
M_ASSERTPKTHDR(m);
176
177
/* BPF writes need to be handled specially. */
178
if (dst->sa_family == AF_UNSPEC || dst->sa_family == pseudo_AF_HDRCMPLT)
179
bcopy(dst->sa_data, &af, sizeof(af));
180
else
181
af = RO_GET_FAMILY(ro, dst);
182
183
if (bpf_peers_present(ifp->if_bpf))
184
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
185
186
m->m_pkthdr.rcvif = ifp;
187
188
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
189
if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
190
191
m_freem(m);
192
return (0);
193
}
194
195
/*
196
* Process an ioctl request.
197
*/
198
static int
199
discioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
200
{
201
struct ifreq *ifr = (struct ifreq *)data;
202
int error = 0;
203
204
switch (cmd) {
205
case SIOCSIFADDR:
206
ifp->if_flags |= IFF_UP;
207
208
/*
209
* Everything else is done at a higher level.
210
*/
211
break;
212
case SIOCADDMULTI:
213
case SIOCDELMULTI:
214
if (ifr == NULL) {
215
error = EAFNOSUPPORT; /* XXX */
216
break;
217
}
218
switch (ifr->ifr_addr.sa_family) {
219
#ifdef INET
220
case AF_INET:
221
break;
222
#endif
223
#ifdef INET6
224
case AF_INET6:
225
break;
226
#endif
227
default:
228
error = EAFNOSUPPORT;
229
break;
230
}
231
break;
232
case SIOCSIFMTU:
233
ifp->if_mtu = ifr->ifr_mtu;
234
break;
235
default:
236
error = EINVAL;
237
}
238
return (error);
239
}
240
241