1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
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 edsclaimer. |
---|
12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
13 | * notice, this list of conditions and the following edsclaimer 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 EDSCLAIMED. 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 | * From: @(#)if_loop.c 8.1 (Berkeley) 6/10/93 |
---|
32 | * $FreeBSD$ |
---|
33 | */ |
---|
34 | |
---|
35 | /* |
---|
36 | * Discard interface driver for protocol testing and timing. |
---|
37 | * Mimics an Ethernet device so that VLANs can be attached to it etc. |
---|
38 | */ |
---|
39 | |
---|
40 | #include <sys/param.h> /* types, important constants */ |
---|
41 | #include <sys/kernel.h> /* SYSINIT for load-time initializations */ |
---|
42 | #include <sys/malloc.h> /* malloc(9) */ |
---|
43 | #include <sys/module.h> /* module(9) */ |
---|
44 | #include <sys/mbuf.h> /* mbuf(9) */ |
---|
45 | #include <sys/socket.h> /* struct ifreq */ |
---|
46 | #include <sys/sockio.h> /* socket ioctl's */ |
---|
47 | /* #include <sys/systm.h> if you need printf(9) or other all-purpose globals */ |
---|
48 | |
---|
49 | #include <net/bpf.h> /* bpf(9) */ |
---|
50 | #include <net/ethernet.h> /* Ethernet related constants and types */ |
---|
51 | #include <net/if.h> |
---|
52 | #include <net/if_var.h> /* basic part of ifnet(9) */ |
---|
53 | #include <net/if_clone.h> /* network interface cloning */ |
---|
54 | #include <net/if_types.h> /* IFT_ETHER and friends */ |
---|
55 | #include <net/if_var.h> /* kernel-only part of ifnet(9) */ |
---|
56 | #include <net/vnet.h> |
---|
57 | |
---|
58 | static const char edscname[] = "edsc"; |
---|
59 | |
---|
60 | /* |
---|
61 | * Software configuration of an interface specific to this device type. |
---|
62 | */ |
---|
63 | struct edsc_softc { |
---|
64 | struct ifnet *sc_ifp; /* ptr to generic interface configuration */ |
---|
65 | |
---|
66 | /* |
---|
67 | * A non-null driver can keep various things here, for instance, |
---|
68 | * the hardware revision, cached values of write-only registers, etc. |
---|
69 | */ |
---|
70 | }; |
---|
71 | |
---|
72 | /* |
---|
73 | * Attach to the interface cloning framework. |
---|
74 | */ |
---|
75 | static VNET_DEFINE(struct if_clone *, edsc_cloner); |
---|
76 | #define V_edsc_cloner VNET(edsc_cloner) |
---|
77 | static int edsc_clone_create(struct if_clone *, int, caddr_t); |
---|
78 | static void edsc_clone_destroy(struct ifnet *); |
---|
79 | |
---|
80 | /* |
---|
81 | * Interface driver methods. |
---|
82 | */ |
---|
83 | static void edsc_init(void *dummy); |
---|
84 | /* static void edsc_input(struct ifnet *ifp, struct mbuf *m); would be here */ |
---|
85 | static int edsc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); |
---|
86 | static void edsc_start(struct ifnet *ifp); |
---|
87 | |
---|
88 | /* |
---|
89 | * We'll allocate softc instances from this. |
---|
90 | */ |
---|
91 | static MALLOC_DEFINE(M_EDSC, edscname, "Ethernet discard interface"); |
---|
92 | |
---|
93 | /* |
---|
94 | * Create an interface instance. |
---|
95 | */ |
---|
96 | static int |
---|
97 | edsc_clone_create(struct if_clone *ifc, int unit, caddr_t params) |
---|
98 | { |
---|
99 | struct edsc_softc *sc; |
---|
100 | struct ifnet *ifp; |
---|
101 | static u_char eaddr[ETHER_ADDR_LEN]; /* 0:0:0:0:0:0 */ |
---|
102 | |
---|
103 | /* |
---|
104 | * Allocate soft and ifnet structures. Link each to the other. |
---|
105 | */ |
---|
106 | sc = malloc(sizeof(struct edsc_softc), M_EDSC, M_WAITOK | M_ZERO); |
---|
107 | ifp = sc->sc_ifp = if_alloc(IFT_ETHER); |
---|
108 | if (ifp == NULL) { |
---|
109 | free(sc, M_EDSC); |
---|
110 | return (ENOSPC); |
---|
111 | } |
---|
112 | |
---|
113 | ifp->if_softc = sc; |
---|
114 | |
---|
115 | /* |
---|
116 | * Get a name for this particular interface in its ifnet structure. |
---|
117 | */ |
---|
118 | if_initname(ifp, edscname, unit); |
---|
119 | |
---|
120 | /* |
---|
121 | * Typical Ethernet interface flags: we can do broadcast and |
---|
122 | * multicast but can't hear our own broadcasts or multicasts. |
---|
123 | */ |
---|
124 | ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; |
---|
125 | |
---|
126 | /* |
---|
127 | * We can pretent we have the whole set of hardware features |
---|
128 | * because we just discard all packets we get from the upper layer. |
---|
129 | * However, the features are disabled initially. They can be |
---|
130 | * enabled via edsc_ioctl() when needed. |
---|
131 | */ |
---|
132 | ifp->if_capabilities = |
---|
133 | IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM | |
---|
134 | IFCAP_HWCSUM | IFCAP_TSO | |
---|
135 | IFCAP_JUMBO_MTU; |
---|
136 | ifp->if_capenable = 0; |
---|
137 | |
---|
138 | /* |
---|
139 | * Set the interface driver methods. |
---|
140 | */ |
---|
141 | ifp->if_init = edsc_init; |
---|
142 | /* ifp->if_input = edsc_input; */ |
---|
143 | ifp->if_ioctl = edsc_ioctl; |
---|
144 | ifp->if_start = edsc_start; |
---|
145 | |
---|
146 | /* |
---|
147 | * Set the maximum output queue length from the global parameter. |
---|
148 | */ |
---|
149 | ifp->if_snd.ifq_maxlen = ifqmaxlen; |
---|
150 | |
---|
151 | /* |
---|
152 | * Do ifnet initializations common to all Ethernet drivers |
---|
153 | * and attach to the network interface framework. |
---|
154 | * TODO: Pick a non-zero link level address. |
---|
155 | */ |
---|
156 | ether_ifattach(ifp, eaddr); |
---|
157 | |
---|
158 | /* |
---|
159 | * Now we can mark the interface as running, i.e., ready |
---|
160 | * for operation. |
---|
161 | */ |
---|
162 | ifp->if_drv_flags |= IFF_DRV_RUNNING; |
---|
163 | |
---|
164 | return (0); |
---|
165 | } |
---|
166 | |
---|
167 | /* |
---|
168 | * Destroy an interface instance. |
---|
169 | */ |
---|
170 | static void |
---|
171 | edsc_clone_destroy(struct ifnet *ifp) |
---|
172 | { |
---|
173 | struct edsc_softc *sc = ifp->if_softc; |
---|
174 | |
---|
175 | /* |
---|
176 | * Detach from the network interface framework. |
---|
177 | */ |
---|
178 | ether_ifdetach(ifp); |
---|
179 | |
---|
180 | /* |
---|
181 | * Free memory occupied by ifnet and softc. |
---|
182 | */ |
---|
183 | if_free(ifp); |
---|
184 | free(sc, M_EDSC); |
---|
185 | } |
---|
186 | |
---|
187 | /* |
---|
188 | * This method is invoked from ether_ioctl() when it's time |
---|
189 | * to bring up the hardware. |
---|
190 | */ |
---|
191 | static void |
---|
192 | edsc_init(void *dummy) |
---|
193 | { |
---|
194 | #if 0 /* what a hardware driver would do here... */ |
---|
195 | struct edsc_soft *sc = (struct edsc_softc *)dummy; |
---|
196 | struct ifnet *ifp = sc->sc_ifp; |
---|
197 | |
---|
198 | /* blah-blah-blah */ |
---|
199 | #endif |
---|
200 | } |
---|
201 | |
---|
202 | /* |
---|
203 | * Network interfaces are controlled via the ioctl(2) syscall. |
---|
204 | */ |
---|
205 | static int |
---|
206 | edsc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) |
---|
207 | { |
---|
208 | struct ifreq *ifr = (struct ifreq *)data; |
---|
209 | |
---|
210 | switch (cmd) { |
---|
211 | case SIOCSIFCAP: |
---|
212 | #if 1 |
---|
213 | /* |
---|
214 | * Just turn on any capabilities requested. |
---|
215 | * The generic ifioctl() function has already made sure |
---|
216 | * that they are supported, i.e., set in if_capabilities. |
---|
217 | */ |
---|
218 | ifp->if_capenable = ifr->ifr_reqcap; |
---|
219 | #else |
---|
220 | /* |
---|
221 | * A h/w driver would need to analyze the requested |
---|
222 | * bits and program the hardware, e.g.: |
---|
223 | */ |
---|
224 | mask = ifp->if_capenable ^ ifr->ifr_reqcap; |
---|
225 | |
---|
226 | if (mask & IFCAP_VLAN_HWTAGGING) { |
---|
227 | ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; |
---|
228 | |
---|
229 | if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) |
---|
230 | /* blah-blah-blah */ |
---|
231 | else |
---|
232 | /* etc-etc-etc */ |
---|
233 | } |
---|
234 | #endif |
---|
235 | break; |
---|
236 | |
---|
237 | default: |
---|
238 | /* |
---|
239 | * Offload the rest onto the common Ethernet handler. |
---|
240 | */ |
---|
241 | return (ether_ioctl(ifp, cmd, data)); |
---|
242 | } |
---|
243 | |
---|
244 | return (0); |
---|
245 | } |
---|
246 | |
---|
247 | /* |
---|
248 | * Process the output queue. |
---|
249 | */ |
---|
250 | static void |
---|
251 | edsc_start(struct ifnet *ifp) |
---|
252 | { |
---|
253 | struct mbuf *m; |
---|
254 | |
---|
255 | /* |
---|
256 | * A hardware interface driver can set IFF_DRV_OACTIVE |
---|
257 | * in ifp->if_drv_flags: |
---|
258 | * |
---|
259 | * ifp->if_drv_flags |= IFF_DRV_OACTIVE; |
---|
260 | * |
---|
261 | * to prevent if_start from being invoked again while the |
---|
262 | * transmission is under way. The flag is to protect the |
---|
263 | * device's transmitter, not the method itself. The output |
---|
264 | * queue is locked and several threads can process it in |
---|
265 | * parallel safely, so the driver can use other means to |
---|
266 | * serialize access to the transmitter. |
---|
267 | * |
---|
268 | * If using IFF_DRV_OACTIVE, the driver should clear the flag |
---|
269 | * not earlier than the current transmission is complete, e.g., |
---|
270 | * upon an interrupt from the device, not just before returning |
---|
271 | * from if_start. This method merely starts the transmission, |
---|
272 | * which may proceed asynchronously. |
---|
273 | */ |
---|
274 | |
---|
275 | /* |
---|
276 | * We loop getting packets from the queue until it's empty. |
---|
277 | * A h/w driver would loop until the device can accept more |
---|
278 | * data into its buffer, or while there are free transmit |
---|
279 | * descriptors, or whatever. |
---|
280 | */ |
---|
281 | for (;;) { |
---|
282 | /* |
---|
283 | * Try to dequeue one packet. Stop if the queue is empty. |
---|
284 | * Use IF_DEQUEUE() here if ALTQ(9) support is unneeded. |
---|
285 | */ |
---|
286 | IFQ_DEQUEUE(&ifp->if_snd, m); |
---|
287 | if (m == NULL) |
---|
288 | break; |
---|
289 | |
---|
290 | /* |
---|
291 | * Let bpf(9) at the packet. |
---|
292 | */ |
---|
293 | BPF_MTAP(ifp, m); |
---|
294 | |
---|
295 | /* |
---|
296 | * Update the interface counters. |
---|
297 | */ |
---|
298 | if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); |
---|
299 | if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); |
---|
300 | |
---|
301 | /* |
---|
302 | * Finally, just drop the packet. |
---|
303 | * TODO: Reply to ARP requests unless IFF_NOARP is set. |
---|
304 | */ |
---|
305 | m_freem(m); |
---|
306 | } |
---|
307 | |
---|
308 | /* |
---|
309 | * ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; |
---|
310 | * would be here only if the transmission were synchronous. |
---|
311 | */ |
---|
312 | } |
---|
313 | |
---|
314 | static void |
---|
315 | vnet_edsc_init(const void *unused __unused) |
---|
316 | { |
---|
317 | |
---|
318 | /* |
---|
319 | * Connect to the network interface cloning framework. |
---|
320 | * The last argument is the number of units to be created |
---|
321 | * from the outset. It's also the minimum number of units |
---|
322 | * allowed. We don't want any units created as soon as the |
---|
323 | * driver is loaded. |
---|
324 | */ |
---|
325 | V_edsc_cloner = if_clone_simple(edscname, edsc_clone_create, |
---|
326 | edsc_clone_destroy, 0); |
---|
327 | } |
---|
328 | VNET_SYSINIT(vnet_edsc_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, |
---|
329 | vnet_edsc_init, NULL); |
---|
330 | |
---|
331 | static void |
---|
332 | vnet_edsc_uninit(const void *unused __unused) |
---|
333 | { |
---|
334 | |
---|
335 | /* |
---|
336 | * Disconnect from the cloning framework. |
---|
337 | * Existing interfaces will be disposed of properly. |
---|
338 | */ |
---|
339 | if_clone_detach(V_edsc_cloner); |
---|
340 | } |
---|
341 | VNET_SYSUNINIT(vnet_edsc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, |
---|
342 | vnet_edsc_uninit, NULL); |
---|
343 | |
---|
344 | /* |
---|
345 | * This function provides handlers for module events, namely load and unload. |
---|
346 | */ |
---|
347 | static int |
---|
348 | edsc_modevent(module_t mod, int type, void *data) |
---|
349 | { |
---|
350 | |
---|
351 | switch (type) { |
---|
352 | case MOD_LOAD: |
---|
353 | case MOD_UNLOAD: |
---|
354 | break; |
---|
355 | default: |
---|
356 | /* |
---|
357 | * There are other event types, but we don't handle them. |
---|
358 | * See module(9). |
---|
359 | */ |
---|
360 | return (EOPNOTSUPP); |
---|
361 | } |
---|
362 | return (0); |
---|
363 | } |
---|
364 | |
---|
365 | static moduledata_t edsc_mod = { |
---|
366 | "if_edsc", /* name */ |
---|
367 | edsc_modevent, /* event handler */ |
---|
368 | NULL /* additional data */ |
---|
369 | }; |
---|
370 | |
---|
371 | DECLARE_MODULE(if_edsc, edsc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); |
---|