Deleted Added
full compact
ng_ether.c (129823) ng_ether.c (131155)
1
2/*
3 * ng_ether.c
4 *
5 * Copyright (c) 1996-2000 Whistle Communications, Inc.
6 * All rights reserved.
7 *
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
18 *
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * Authors: Archie Cobbs <archie@freebsd.org>
38 * Julian Elischer <julian@freebsd.org>
39 *
1
2/*
3 * ng_ether.c
4 *
5 * Copyright (c) 1996-2000 Whistle Communications, Inc.
6 * All rights reserved.
7 *
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
18 *
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * Authors: Archie Cobbs <archie@freebsd.org>
38 * Julian Elischer <julian@freebsd.org>
39 *
40 * $FreeBSD: head/sys/netgraph/ng_ether.c 129823 2004-05-29 00:51:19Z julian $
40 * $FreeBSD: head/sys/netgraph/ng_ether.c 131155 2004-06-26 22:24:16Z julian $
41 */
42
43/*
44 * ng_ether(4) netgraph node type
45 */
46
47#include <sys/param.h>
48#include <sys/systm.h>
49#include <sys/kernel.h>
50#include <sys/malloc.h>
51#include <sys/mbuf.h>
52#include <sys/errno.h>
53#include <sys/syslog.h>
54#include <sys/socket.h>
55
56#include <net/if.h>
57#include <net/if_types.h>
58#include <net/if_arp.h>
59#include <net/if_var.h>
60#include <net/ethernet.h>
61
62#include <netgraph/ng_message.h>
63#include <netgraph/netgraph.h>
64#include <netgraph/ng_parse.h>
65#include <netgraph/ng_ether.h>
66
67#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph)
68
69/* Per-node private data */
70struct private {
71 struct ifnet *ifp; /* associated interface */
72 hook_p upper; /* upper hook connection */
73 hook_p lower; /* lower hook connection */
74 hook_p orphan; /* orphan hook connection */
75 u_char autoSrcAddr; /* always overwrite source address */
76 u_char promisc; /* promiscuous mode enabled */
77 u_long hwassist; /* hardware checksum capabilities */
78 u_int flags; /* flags e.g. really die */
79};
80typedef struct private *priv_p;
81
82/* Hook pointers used by if_ethersubr.c to callback to netgraph */
83extern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
84extern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m);
85extern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
86extern void (*ng_ether_attach_p)(struct ifnet *ifp);
87extern void (*ng_ether_detach_p)(struct ifnet *ifp);
88
89/* Functional hooks called from if_ethersubr.c */
90static void ng_ether_input(struct ifnet *ifp, struct mbuf **mp);
91static void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m);
92static int ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
93static void ng_ether_attach(struct ifnet *ifp);
94static void ng_ether_detach(struct ifnet *ifp);
95
96/* Other functions */
41 */
42
43/*
44 * ng_ether(4) netgraph node type
45 */
46
47#include <sys/param.h>
48#include <sys/systm.h>
49#include <sys/kernel.h>
50#include <sys/malloc.h>
51#include <sys/mbuf.h>
52#include <sys/errno.h>
53#include <sys/syslog.h>
54#include <sys/socket.h>
55
56#include <net/if.h>
57#include <net/if_types.h>
58#include <net/if_arp.h>
59#include <net/if_var.h>
60#include <net/ethernet.h>
61
62#include <netgraph/ng_message.h>
63#include <netgraph/netgraph.h>
64#include <netgraph/ng_parse.h>
65#include <netgraph/ng_ether.h>
66
67#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph)
68
69/* Per-node private data */
70struct private {
71 struct ifnet *ifp; /* associated interface */
72 hook_p upper; /* upper hook connection */
73 hook_p lower; /* lower hook connection */
74 hook_p orphan; /* orphan hook connection */
75 u_char autoSrcAddr; /* always overwrite source address */
76 u_char promisc; /* promiscuous mode enabled */
77 u_long hwassist; /* hardware checksum capabilities */
78 u_int flags; /* flags e.g. really die */
79};
80typedef struct private *priv_p;
81
82/* Hook pointers used by if_ethersubr.c to callback to netgraph */
83extern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
84extern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m);
85extern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
86extern void (*ng_ether_attach_p)(struct ifnet *ifp);
87extern void (*ng_ether_detach_p)(struct ifnet *ifp);
88
89/* Functional hooks called from if_ethersubr.c */
90static void ng_ether_input(struct ifnet *ifp, struct mbuf **mp);
91static void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m);
92static int ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
93static void ng_ether_attach(struct ifnet *ifp);
94static void ng_ether_detach(struct ifnet *ifp);
95
96/* Other functions */
97static int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta);
98static int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta);
97static int ng_ether_rcv_lower(node_p node, struct mbuf *m);
98static int ng_ether_rcv_upper(node_p node, struct mbuf *m);
99
100/* Netgraph node methods */
101static ng_constructor_t ng_ether_constructor;
102static ng_rcvmsg_t ng_ether_rcvmsg;
103static ng_shutdown_t ng_ether_shutdown;
104static ng_newhook_t ng_ether_newhook;
105static ng_connect_t ng_ether_connect;
106static ng_rcvdata_t ng_ether_rcvdata;
107static ng_disconnect_t ng_ether_disconnect;
108static int ng_ether_mod_event(module_t mod, int event, void *data);
109
110/* List of commands and how to convert arguments to/from ASCII */
111static const struct ng_cmdlist ng_ether_cmdlist[] = {
112 {
113 NGM_ETHER_COOKIE,
114 NGM_ETHER_GET_IFNAME,
115 "getifname",
116 NULL,
117 &ng_parse_string_type
118 },
119 {
120 NGM_ETHER_COOKIE,
121 NGM_ETHER_GET_IFINDEX,
122 "getifindex",
123 NULL,
124 &ng_parse_int32_type
125 },
126 {
127 NGM_ETHER_COOKIE,
128 NGM_ETHER_GET_ENADDR,
129 "getenaddr",
130 NULL,
131 &ng_parse_enaddr_type
132 },
133 {
134 NGM_ETHER_COOKIE,
135 NGM_ETHER_SET_ENADDR,
136 "setenaddr",
137 &ng_parse_enaddr_type,
138 NULL
139 },
140 {
141 NGM_ETHER_COOKIE,
142 NGM_ETHER_GET_PROMISC,
143 "getpromisc",
144 NULL,
145 &ng_parse_int32_type
146 },
147 {
148 NGM_ETHER_COOKIE,
149 NGM_ETHER_SET_PROMISC,
150 "setpromisc",
151 &ng_parse_int32_type,
152 NULL
153 },
154 {
155 NGM_ETHER_COOKIE,
156 NGM_ETHER_GET_AUTOSRC,
157 "getautosrc",
158 NULL,
159 &ng_parse_int32_type
160 },
161 {
162 NGM_ETHER_COOKIE,
163 NGM_ETHER_SET_AUTOSRC,
164 "setautosrc",
165 &ng_parse_int32_type,
166 NULL
167 },
168 { 0 }
169};
170
171static struct ng_type ng_ether_typestruct = {
172 .version = NG_ABI_VERSION,
173 .name = NG_ETHER_NODE_TYPE,
174 .mod_event = ng_ether_mod_event,
175 .constructor = ng_ether_constructor,
176 .rcvmsg = ng_ether_rcvmsg,
177 .shutdown = ng_ether_shutdown,
178 .newhook = ng_ether_newhook,
179 .connect = ng_ether_connect,
180 .rcvdata = ng_ether_rcvdata,
181 .disconnect = ng_ether_disconnect,
182 .cmdlist = ng_ether_cmdlist,
183};
184MODULE_VERSION(ng_ether, 1);
185NETGRAPH_INIT(ether, &ng_ether_typestruct);
186
187/******************************************************************
188 ETHERNET FUNCTION HOOKS
189******************************************************************/
190
191/*
192 * Handle a packet that has come in on an interface. We get to
193 * look at it here before any upper layer protocols do.
194 *
195 * NOTE: this function will get called at splimp()
196 */
197static void
198ng_ether_input(struct ifnet *ifp, struct mbuf **mp)
199{
200 const node_p node = IFP2NG(ifp);
201 const priv_p priv = NG_NODE_PRIVATE(node);
202 int error;
203
204 /* If "lower" hook not connected, let packet continue */
205 if (priv->lower == NULL)
206 return;
207 NG_SEND_DATA_ONLY(error, priv->lower, *mp); /* sets *mp = NULL */
208}
209
210/*
211 * Handle a packet that has come in on an interface, and which
212 * does not match any of our known protocols (an ``orphan'').
213 *
214 * NOTE: this function will get called at splimp()
215 */
216static void
217ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m)
218{
219 const node_p node = IFP2NG(ifp);
220 const priv_p priv = NG_NODE_PRIVATE(node);
221 int error;
222
223 /* If "orphan" hook not connected, discard packet */
224 if (priv->orphan == NULL) {
225 m_freem(m);
226 return;
227 }
228 NG_SEND_DATA_ONLY(error, priv->orphan, m);
229}
230
231/*
232 * Handle a packet that is going out on an interface.
233 * The Ethernet header is already attached to the mbuf.
234 */
235static int
236ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
237{
238 const node_p node = IFP2NG(ifp);
239 const priv_p priv = NG_NODE_PRIVATE(node);
240 int error = 0;
241
242 /* If "upper" hook not connected, let packet continue */
243 if (priv->upper == NULL)
244 return (0);
245
246 /* Send it out "upper" hook */
247 NG_SEND_DATA_ONLY(error, priv->upper, *mp);
248 return (error);
249}
250
251/*
252 * A new Ethernet interface has been attached.
253 * Create a new node for it, etc.
254 */
255static void
256ng_ether_attach(struct ifnet *ifp)
257{
258 priv_p priv;
259 node_p node;
260
261 /* Create node */
262 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
263 if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
264 log(LOG_ERR, "%s: can't %s for %s\n",
265 __func__, "create node", ifp->if_xname);
266 return;
267 }
268
269 /* Allocate private data */
270 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
271 if (priv == NULL) {
272 log(LOG_ERR, "%s: can't %s for %s\n",
273 __func__, "allocate memory", ifp->if_xname);
274 NG_NODE_UNREF(node);
275 return;
276 }
277 NG_NODE_SET_PRIVATE(node, priv);
278 priv->ifp = ifp;
279 IFP2NG(ifp) = node;
280 priv->autoSrcAddr = 1;
281 priv->hwassist = ifp->if_hwassist;
282
283 /* Try to give the node the same name as the interface */
284 if (ng_name_node(node, ifp->if_xname) != 0) {
285 log(LOG_WARNING, "%s: can't name node %s\n",
286 __func__, ifp->if_xname);
287 }
288}
289
290/*
291 * An Ethernet interface is being detached.
292 * REALLY Destroy its node.
293 */
294static void
295ng_ether_detach(struct ifnet *ifp)
296{
297 const node_p node = IFP2NG(ifp);
298 const priv_p priv = NG_NODE_PRIVATE(node);
299
300 if (node == NULL) /* no node (why not?), ignore */
301 return;
302 NG_NODE_REALLY_DIE(node); /* Force real removal of node */
303 /*
304 * We can't assume the ifnet is still around when we run shutdown
305 * So zap it now. XXX We HOPE that anything running at this time
306 * handles it (as it should in the non netgraph case).
307 */
308 IFP2NG(ifp) = NULL;
309 priv->ifp = NULL; /* XXX race if interrupted an output packet */
310 ng_rmnode_self(node); /* remove all netgraph parts */
311}
312
313/******************************************************************
314 NETGRAPH NODE METHODS
315******************************************************************/
316
317/*
318 * It is not possible or allowable to create a node of this type.
319 * Nodes get created when the interface is attached (or, when
320 * this node type's KLD is loaded).
321 */
322static int
323ng_ether_constructor(node_p node)
324{
325 return (EINVAL);
326}
327
328/*
329 * Check for attaching a new hook.
330 */
331static int
332ng_ether_newhook(node_p node, hook_p hook, const char *name)
333{
334 const priv_p priv = NG_NODE_PRIVATE(node);
335 hook_p *hookptr;
336
337 /* Divert hook is an alias for lower */
338 if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0)
339 name = NG_ETHER_HOOK_LOWER;
340
341 /* Which hook? */
342 if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0)
343 hookptr = &priv->upper;
344 else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0)
345 hookptr = &priv->lower;
346 else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0)
347 hookptr = &priv->orphan;
348 else
349 return (EINVAL);
350
351 /* Check if already connected (shouldn't be, but doesn't hurt) */
352 if (*hookptr != NULL)
353 return (EISCONN);
354
355 /* Disable hardware checksums while 'upper' hook is connected */
356 if (hookptr == &priv->upper)
357 priv->ifp->if_hwassist = 0;
358
359 /* OK */
360 *hookptr = hook;
361 return (0);
362}
363
364/*
365 * Hooks are attached, adjust to force queueing.
366 * We don't really care which hook it is.
367 * they should all be queuing for outgoing data.
368 */
369static int
370ng_ether_connect(hook_p hook)
371{
372 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
373 return (0);
374}
375
376/*
377 * Receive an incoming control message.
378 */
379static int
380ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook)
381{
382 const priv_p priv = NG_NODE_PRIVATE(node);
383 struct ng_mesg *resp = NULL;
384 int error = 0;
385 struct ng_mesg *msg;
386
387 NGI_GET_MSG(item, msg);
388 switch (msg->header.typecookie) {
389 case NGM_ETHER_COOKIE:
390 switch (msg->header.cmd) {
391 case NGM_ETHER_GET_IFNAME:
392 NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
393 if (resp == NULL) {
394 error = ENOMEM;
395 break;
396 }
397 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ + 1);
398 break;
399 case NGM_ETHER_GET_IFINDEX:
400 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
401 if (resp == NULL) {
402 error = ENOMEM;
403 break;
404 }
405 *((u_int32_t *)resp->data) = priv->ifp->if_index;
406 break;
407 case NGM_ETHER_GET_ENADDR:
408 NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT);
409 if (resp == NULL) {
410 error = ENOMEM;
411 break;
412 }
413 bcopy((IFP2AC(priv->ifp))->ac_enaddr,
414 resp->data, ETHER_ADDR_LEN);
415 break;
416 case NGM_ETHER_SET_ENADDR:
417 {
418 if (msg->header.arglen != ETHER_ADDR_LEN) {
419 error = EINVAL;
420 break;
421 }
422 error = if_setlladdr(priv->ifp,
423 (u_char *)msg->data, ETHER_ADDR_LEN);
424 break;
425 }
426 case NGM_ETHER_GET_PROMISC:
427 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
428 if (resp == NULL) {
429 error = ENOMEM;
430 break;
431 }
432 *((u_int32_t *)resp->data) = priv->promisc;
433 break;
434 case NGM_ETHER_SET_PROMISC:
435 {
436 u_char want;
437
438 if (msg->header.arglen != sizeof(u_int32_t)) {
439 error = EINVAL;
440 break;
441 }
442 want = !!*((u_int32_t *)msg->data);
443 if (want ^ priv->promisc) {
444 if ((error = ifpromisc(priv->ifp, want)) != 0)
445 break;
446 priv->promisc = want;
447 }
448 break;
449 }
450 case NGM_ETHER_GET_AUTOSRC:
451 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
452 if (resp == NULL) {
453 error = ENOMEM;
454 break;
455 }
456 *((u_int32_t *)resp->data) = priv->autoSrcAddr;
457 break;
458 case NGM_ETHER_SET_AUTOSRC:
459 if (msg->header.arglen != sizeof(u_int32_t)) {
460 error = EINVAL;
461 break;
462 }
463 priv->autoSrcAddr = !!*((u_int32_t *)msg->data);
464 break;
465 default:
466 error = EINVAL;
467 break;
468 }
469 break;
470 default:
471 error = EINVAL;
472 break;
473 }
474 NG_RESPOND_MSG(error, node, item, resp);
475 NG_FREE_MSG(msg);
476 return (error);
477}
478
479/*
480 * Receive data on a hook.
481 */
482static int
483ng_ether_rcvdata(hook_p hook, item_p item)
484{
485 const node_p node = NG_HOOK_NODE(hook);
486 const priv_p priv = NG_NODE_PRIVATE(node);
487 struct mbuf *m;
99
100/* Netgraph node methods */
101static ng_constructor_t ng_ether_constructor;
102static ng_rcvmsg_t ng_ether_rcvmsg;
103static ng_shutdown_t ng_ether_shutdown;
104static ng_newhook_t ng_ether_newhook;
105static ng_connect_t ng_ether_connect;
106static ng_rcvdata_t ng_ether_rcvdata;
107static ng_disconnect_t ng_ether_disconnect;
108static int ng_ether_mod_event(module_t mod, int event, void *data);
109
110/* List of commands and how to convert arguments to/from ASCII */
111static const struct ng_cmdlist ng_ether_cmdlist[] = {
112 {
113 NGM_ETHER_COOKIE,
114 NGM_ETHER_GET_IFNAME,
115 "getifname",
116 NULL,
117 &ng_parse_string_type
118 },
119 {
120 NGM_ETHER_COOKIE,
121 NGM_ETHER_GET_IFINDEX,
122 "getifindex",
123 NULL,
124 &ng_parse_int32_type
125 },
126 {
127 NGM_ETHER_COOKIE,
128 NGM_ETHER_GET_ENADDR,
129 "getenaddr",
130 NULL,
131 &ng_parse_enaddr_type
132 },
133 {
134 NGM_ETHER_COOKIE,
135 NGM_ETHER_SET_ENADDR,
136 "setenaddr",
137 &ng_parse_enaddr_type,
138 NULL
139 },
140 {
141 NGM_ETHER_COOKIE,
142 NGM_ETHER_GET_PROMISC,
143 "getpromisc",
144 NULL,
145 &ng_parse_int32_type
146 },
147 {
148 NGM_ETHER_COOKIE,
149 NGM_ETHER_SET_PROMISC,
150 "setpromisc",
151 &ng_parse_int32_type,
152 NULL
153 },
154 {
155 NGM_ETHER_COOKIE,
156 NGM_ETHER_GET_AUTOSRC,
157 "getautosrc",
158 NULL,
159 &ng_parse_int32_type
160 },
161 {
162 NGM_ETHER_COOKIE,
163 NGM_ETHER_SET_AUTOSRC,
164 "setautosrc",
165 &ng_parse_int32_type,
166 NULL
167 },
168 { 0 }
169};
170
171static struct ng_type ng_ether_typestruct = {
172 .version = NG_ABI_VERSION,
173 .name = NG_ETHER_NODE_TYPE,
174 .mod_event = ng_ether_mod_event,
175 .constructor = ng_ether_constructor,
176 .rcvmsg = ng_ether_rcvmsg,
177 .shutdown = ng_ether_shutdown,
178 .newhook = ng_ether_newhook,
179 .connect = ng_ether_connect,
180 .rcvdata = ng_ether_rcvdata,
181 .disconnect = ng_ether_disconnect,
182 .cmdlist = ng_ether_cmdlist,
183};
184MODULE_VERSION(ng_ether, 1);
185NETGRAPH_INIT(ether, &ng_ether_typestruct);
186
187/******************************************************************
188 ETHERNET FUNCTION HOOKS
189******************************************************************/
190
191/*
192 * Handle a packet that has come in on an interface. We get to
193 * look at it here before any upper layer protocols do.
194 *
195 * NOTE: this function will get called at splimp()
196 */
197static void
198ng_ether_input(struct ifnet *ifp, struct mbuf **mp)
199{
200 const node_p node = IFP2NG(ifp);
201 const priv_p priv = NG_NODE_PRIVATE(node);
202 int error;
203
204 /* If "lower" hook not connected, let packet continue */
205 if (priv->lower == NULL)
206 return;
207 NG_SEND_DATA_ONLY(error, priv->lower, *mp); /* sets *mp = NULL */
208}
209
210/*
211 * Handle a packet that has come in on an interface, and which
212 * does not match any of our known protocols (an ``orphan'').
213 *
214 * NOTE: this function will get called at splimp()
215 */
216static void
217ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m)
218{
219 const node_p node = IFP2NG(ifp);
220 const priv_p priv = NG_NODE_PRIVATE(node);
221 int error;
222
223 /* If "orphan" hook not connected, discard packet */
224 if (priv->orphan == NULL) {
225 m_freem(m);
226 return;
227 }
228 NG_SEND_DATA_ONLY(error, priv->orphan, m);
229}
230
231/*
232 * Handle a packet that is going out on an interface.
233 * The Ethernet header is already attached to the mbuf.
234 */
235static int
236ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
237{
238 const node_p node = IFP2NG(ifp);
239 const priv_p priv = NG_NODE_PRIVATE(node);
240 int error = 0;
241
242 /* If "upper" hook not connected, let packet continue */
243 if (priv->upper == NULL)
244 return (0);
245
246 /* Send it out "upper" hook */
247 NG_SEND_DATA_ONLY(error, priv->upper, *mp);
248 return (error);
249}
250
251/*
252 * A new Ethernet interface has been attached.
253 * Create a new node for it, etc.
254 */
255static void
256ng_ether_attach(struct ifnet *ifp)
257{
258 priv_p priv;
259 node_p node;
260
261 /* Create node */
262 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
263 if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
264 log(LOG_ERR, "%s: can't %s for %s\n",
265 __func__, "create node", ifp->if_xname);
266 return;
267 }
268
269 /* Allocate private data */
270 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
271 if (priv == NULL) {
272 log(LOG_ERR, "%s: can't %s for %s\n",
273 __func__, "allocate memory", ifp->if_xname);
274 NG_NODE_UNREF(node);
275 return;
276 }
277 NG_NODE_SET_PRIVATE(node, priv);
278 priv->ifp = ifp;
279 IFP2NG(ifp) = node;
280 priv->autoSrcAddr = 1;
281 priv->hwassist = ifp->if_hwassist;
282
283 /* Try to give the node the same name as the interface */
284 if (ng_name_node(node, ifp->if_xname) != 0) {
285 log(LOG_WARNING, "%s: can't name node %s\n",
286 __func__, ifp->if_xname);
287 }
288}
289
290/*
291 * An Ethernet interface is being detached.
292 * REALLY Destroy its node.
293 */
294static void
295ng_ether_detach(struct ifnet *ifp)
296{
297 const node_p node = IFP2NG(ifp);
298 const priv_p priv = NG_NODE_PRIVATE(node);
299
300 if (node == NULL) /* no node (why not?), ignore */
301 return;
302 NG_NODE_REALLY_DIE(node); /* Force real removal of node */
303 /*
304 * We can't assume the ifnet is still around when we run shutdown
305 * So zap it now. XXX We HOPE that anything running at this time
306 * handles it (as it should in the non netgraph case).
307 */
308 IFP2NG(ifp) = NULL;
309 priv->ifp = NULL; /* XXX race if interrupted an output packet */
310 ng_rmnode_self(node); /* remove all netgraph parts */
311}
312
313/******************************************************************
314 NETGRAPH NODE METHODS
315******************************************************************/
316
317/*
318 * It is not possible or allowable to create a node of this type.
319 * Nodes get created when the interface is attached (or, when
320 * this node type's KLD is loaded).
321 */
322static int
323ng_ether_constructor(node_p node)
324{
325 return (EINVAL);
326}
327
328/*
329 * Check for attaching a new hook.
330 */
331static int
332ng_ether_newhook(node_p node, hook_p hook, const char *name)
333{
334 const priv_p priv = NG_NODE_PRIVATE(node);
335 hook_p *hookptr;
336
337 /* Divert hook is an alias for lower */
338 if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0)
339 name = NG_ETHER_HOOK_LOWER;
340
341 /* Which hook? */
342 if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0)
343 hookptr = &priv->upper;
344 else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0)
345 hookptr = &priv->lower;
346 else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0)
347 hookptr = &priv->orphan;
348 else
349 return (EINVAL);
350
351 /* Check if already connected (shouldn't be, but doesn't hurt) */
352 if (*hookptr != NULL)
353 return (EISCONN);
354
355 /* Disable hardware checksums while 'upper' hook is connected */
356 if (hookptr == &priv->upper)
357 priv->ifp->if_hwassist = 0;
358
359 /* OK */
360 *hookptr = hook;
361 return (0);
362}
363
364/*
365 * Hooks are attached, adjust to force queueing.
366 * We don't really care which hook it is.
367 * they should all be queuing for outgoing data.
368 */
369static int
370ng_ether_connect(hook_p hook)
371{
372 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
373 return (0);
374}
375
376/*
377 * Receive an incoming control message.
378 */
379static int
380ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook)
381{
382 const priv_p priv = NG_NODE_PRIVATE(node);
383 struct ng_mesg *resp = NULL;
384 int error = 0;
385 struct ng_mesg *msg;
386
387 NGI_GET_MSG(item, msg);
388 switch (msg->header.typecookie) {
389 case NGM_ETHER_COOKIE:
390 switch (msg->header.cmd) {
391 case NGM_ETHER_GET_IFNAME:
392 NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
393 if (resp == NULL) {
394 error = ENOMEM;
395 break;
396 }
397 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ + 1);
398 break;
399 case NGM_ETHER_GET_IFINDEX:
400 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
401 if (resp == NULL) {
402 error = ENOMEM;
403 break;
404 }
405 *((u_int32_t *)resp->data) = priv->ifp->if_index;
406 break;
407 case NGM_ETHER_GET_ENADDR:
408 NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT);
409 if (resp == NULL) {
410 error = ENOMEM;
411 break;
412 }
413 bcopy((IFP2AC(priv->ifp))->ac_enaddr,
414 resp->data, ETHER_ADDR_LEN);
415 break;
416 case NGM_ETHER_SET_ENADDR:
417 {
418 if (msg->header.arglen != ETHER_ADDR_LEN) {
419 error = EINVAL;
420 break;
421 }
422 error = if_setlladdr(priv->ifp,
423 (u_char *)msg->data, ETHER_ADDR_LEN);
424 break;
425 }
426 case NGM_ETHER_GET_PROMISC:
427 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
428 if (resp == NULL) {
429 error = ENOMEM;
430 break;
431 }
432 *((u_int32_t *)resp->data) = priv->promisc;
433 break;
434 case NGM_ETHER_SET_PROMISC:
435 {
436 u_char want;
437
438 if (msg->header.arglen != sizeof(u_int32_t)) {
439 error = EINVAL;
440 break;
441 }
442 want = !!*((u_int32_t *)msg->data);
443 if (want ^ priv->promisc) {
444 if ((error = ifpromisc(priv->ifp, want)) != 0)
445 break;
446 priv->promisc = want;
447 }
448 break;
449 }
450 case NGM_ETHER_GET_AUTOSRC:
451 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
452 if (resp == NULL) {
453 error = ENOMEM;
454 break;
455 }
456 *((u_int32_t *)resp->data) = priv->autoSrcAddr;
457 break;
458 case NGM_ETHER_SET_AUTOSRC:
459 if (msg->header.arglen != sizeof(u_int32_t)) {
460 error = EINVAL;
461 break;
462 }
463 priv->autoSrcAddr = !!*((u_int32_t *)msg->data);
464 break;
465 default:
466 error = EINVAL;
467 break;
468 }
469 break;
470 default:
471 error = EINVAL;
472 break;
473 }
474 NG_RESPOND_MSG(error, node, item, resp);
475 NG_FREE_MSG(msg);
476 return (error);
477}
478
479/*
480 * Receive data on a hook.
481 */
482static int
483ng_ether_rcvdata(hook_p hook, item_p item)
484{
485 const node_p node = NG_HOOK_NODE(hook);
486 const priv_p priv = NG_NODE_PRIVATE(node);
487 struct mbuf *m;
488 meta_p meta;
489
490 NGI_GET_M(item, m);
488
489 NGI_GET_M(item, m);
491 NGI_GET_META(item, meta);
492 NG_FREE_ITEM(item);
490 NG_FREE_ITEM(item);
491
493 if (hook == priv->lower || hook == priv->orphan)
492 if (hook == priv->lower || hook == priv->orphan)
494 return ng_ether_rcv_lower(node, m, meta);
493 return ng_ether_rcv_lower(node, m);
495 if (hook == priv->upper)
494 if (hook == priv->upper)
496 return ng_ether_rcv_upper(node, m, meta);
495 return ng_ether_rcv_upper(node, m);
497 panic("%s: weird hook", __func__);
498#ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */
499 return NULL;
500#endif
501}
502
503/*
504 * Handle an mbuf received on the "lower" or "orphan" hook.
505 */
506static int
496 panic("%s: weird hook", __func__);
497#ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */
498 return NULL;
499#endif
500}
501
502/*
503 * Handle an mbuf received on the "lower" or "orphan" hook.
504 */
505static int
507ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta)
506ng_ether_rcv_lower(node_p node, struct mbuf *m)
508{
509 const priv_p priv = NG_NODE_PRIVATE(node);
510 struct ifnet *const ifp = priv->ifp;
511
507{
508 const priv_p priv = NG_NODE_PRIVATE(node);
509 struct ifnet *const ifp = priv->ifp;
510
512 /* Discard meta info */
513 NG_FREE_META(meta);
514
515 /* Check whether interface is ready for packets */
516 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
517 NG_FREE_M(m);
518 return (ENETDOWN);
519 }
520
521 /* Make sure header is fully pulled up */
522 if (m->m_pkthdr.len < sizeof(struct ether_header)) {
523 NG_FREE_M(m);
524 return (EINVAL);
525 }
526 if (m->m_len < sizeof(struct ether_header)
527 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
528 return (ENOBUFS);
529
530 /* Drop in the MAC address if desired */
531 if (priv->autoSrcAddr) {
532
533 /* Make the mbuf writable if it's not already */
534 if (!M_WRITABLE(m)
535 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
536 return (ENOBUFS);
537
538 /* Overwrite source MAC address */
539 bcopy((IFP2AC(ifp))->ac_enaddr,
540 mtod(m, struct ether_header *)->ether_shost,
541 ETHER_ADDR_LEN);
542 }
543
544 /* Send it on its way */
545 return ether_output_frame(ifp, m);
546}
547
548/*
549 * Handle an mbuf received on the "upper" hook.
550 */
551static int
511 /* Check whether interface is ready for packets */
512 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
513 NG_FREE_M(m);
514 return (ENETDOWN);
515 }
516
517 /* Make sure header is fully pulled up */
518 if (m->m_pkthdr.len < sizeof(struct ether_header)) {
519 NG_FREE_M(m);
520 return (EINVAL);
521 }
522 if (m->m_len < sizeof(struct ether_header)
523 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
524 return (ENOBUFS);
525
526 /* Drop in the MAC address if desired */
527 if (priv->autoSrcAddr) {
528
529 /* Make the mbuf writable if it's not already */
530 if (!M_WRITABLE(m)
531 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
532 return (ENOBUFS);
533
534 /* Overwrite source MAC address */
535 bcopy((IFP2AC(ifp))->ac_enaddr,
536 mtod(m, struct ether_header *)->ether_shost,
537 ETHER_ADDR_LEN);
538 }
539
540 /* Send it on its way */
541 return ether_output_frame(ifp, m);
542}
543
544/*
545 * Handle an mbuf received on the "upper" hook.
546 */
547static int
552ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta)
548ng_ether_rcv_upper(node_p node, struct mbuf *m)
553{
554 const priv_p priv = NG_NODE_PRIVATE(node);
555
549{
550 const priv_p priv = NG_NODE_PRIVATE(node);
551
556 /* Discard meta info */
557 NG_FREE_META(meta);
558
559 m->m_pkthdr.rcvif = priv->ifp;
560
561 /* Route packet back in */
562 ether_demux(priv->ifp, m);
563 return (0);
564}
565
566/*
567 * Shutdown node. This resets the node but does not remove it
568 * unless the REALLY_DIE flag is set.
569 */
570static int
571ng_ether_shutdown(node_p node)
572{
573 const priv_p priv = NG_NODE_PRIVATE(node);
574
575 if (node->nd_flags & NG_REALLY_DIE) {
576 /*
577 * WE came here because the ethernet card is being unloaded,
578 * so stop being persistant.
579 * Actually undo all the things we did on creation.
580 * Assume the ifp has already been freed.
581 */
582 NG_NODE_SET_PRIVATE(node, NULL);
583 FREE(priv, M_NETGRAPH);
584 NG_NODE_UNREF(node); /* free node itself */
585 return (0);
586 }
587 if (priv->promisc) { /* disable promiscuous mode */
588 (void)ifpromisc(priv->ifp, 0);
589 priv->promisc = 0;
590 }
591 priv->autoSrcAddr = 1; /* reset auto-src-addr flag */
592 node->nd_flags &= ~NG_INVALID; /* Signal ng_rmnode we are persisant */
593 return (0);
594}
595
596/*
597 * Hook disconnection.
598 */
599static int
600ng_ether_disconnect(hook_p hook)
601{
602 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
603
604 if (hook == priv->upper) {
605 priv->upper = NULL;
606 if (priv->ifp != NULL) /* restore h/w csum */
607 priv->ifp->if_hwassist = priv->hwassist;
608 } else if (hook == priv->lower)
609 priv->lower = NULL;
610 else if (hook == priv->orphan)
611 priv->orphan = NULL;
612 else
613 panic("%s: weird hook", __func__);
614 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
615 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
616 ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */
617 return (0);
618}
619
620/******************************************************************
621 INITIALIZATION
622******************************************************************/
623
624/*
625 * Handle loading and unloading for this node type.
626 */
627static int
628ng_ether_mod_event(module_t mod, int event, void *data)
629{
630 struct ifnet *ifp;
631 int error = 0;
632 int s;
633
634 s = splnet();
635 switch (event) {
636 case MOD_LOAD:
637
638 /* Register function hooks */
639 if (ng_ether_attach_p != NULL) {
640 error = EEXIST;
641 break;
642 }
643 ng_ether_attach_p = ng_ether_attach;
644 ng_ether_detach_p = ng_ether_detach;
645 ng_ether_output_p = ng_ether_output;
646 ng_ether_input_p = ng_ether_input;
647 ng_ether_input_orphan_p = ng_ether_input_orphan;
648
649 /* Create nodes for any already-existing Ethernet interfaces */
650 IFNET_RLOCK();
651 TAILQ_FOREACH(ifp, &ifnet, if_link) {
652 if (ifp->if_type == IFT_ETHER
653 || ifp->if_type == IFT_L2VLAN)
654 ng_ether_attach(ifp);
655 }
656 IFNET_RUNLOCK();
657 break;
658
659 case MOD_UNLOAD:
660
661 /*
662 * Note that the base code won't try to unload us until
663 * all nodes have been removed, and that can't happen
664 * until all Ethernet interfaces are removed. In any
665 * case, we know there are no nodes left if the action
666 * is MOD_UNLOAD, so there's no need to detach any nodes.
667 */
668
669 /* Unregister function hooks */
670 ng_ether_attach_p = NULL;
671 ng_ether_detach_p = NULL;
672 ng_ether_output_p = NULL;
673 ng_ether_input_p = NULL;
674 ng_ether_input_orphan_p = NULL;
675 break;
676
677 default:
678 error = EOPNOTSUPP;
679 break;
680 }
681 splx(s);
682 return (error);
683}
684
552 m->m_pkthdr.rcvif = priv->ifp;
553
554 /* Route packet back in */
555 ether_demux(priv->ifp, m);
556 return (0);
557}
558
559/*
560 * Shutdown node. This resets the node but does not remove it
561 * unless the REALLY_DIE flag is set.
562 */
563static int
564ng_ether_shutdown(node_p node)
565{
566 const priv_p priv = NG_NODE_PRIVATE(node);
567
568 if (node->nd_flags & NG_REALLY_DIE) {
569 /*
570 * WE came here because the ethernet card is being unloaded,
571 * so stop being persistant.
572 * Actually undo all the things we did on creation.
573 * Assume the ifp has already been freed.
574 */
575 NG_NODE_SET_PRIVATE(node, NULL);
576 FREE(priv, M_NETGRAPH);
577 NG_NODE_UNREF(node); /* free node itself */
578 return (0);
579 }
580 if (priv->promisc) { /* disable promiscuous mode */
581 (void)ifpromisc(priv->ifp, 0);
582 priv->promisc = 0;
583 }
584 priv->autoSrcAddr = 1; /* reset auto-src-addr flag */
585 node->nd_flags &= ~NG_INVALID; /* Signal ng_rmnode we are persisant */
586 return (0);
587}
588
589/*
590 * Hook disconnection.
591 */
592static int
593ng_ether_disconnect(hook_p hook)
594{
595 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
596
597 if (hook == priv->upper) {
598 priv->upper = NULL;
599 if (priv->ifp != NULL) /* restore h/w csum */
600 priv->ifp->if_hwassist = priv->hwassist;
601 } else if (hook == priv->lower)
602 priv->lower = NULL;
603 else if (hook == priv->orphan)
604 priv->orphan = NULL;
605 else
606 panic("%s: weird hook", __func__);
607 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
608 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
609 ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */
610 return (0);
611}
612
613/******************************************************************
614 INITIALIZATION
615******************************************************************/
616
617/*
618 * Handle loading and unloading for this node type.
619 */
620static int
621ng_ether_mod_event(module_t mod, int event, void *data)
622{
623 struct ifnet *ifp;
624 int error = 0;
625 int s;
626
627 s = splnet();
628 switch (event) {
629 case MOD_LOAD:
630
631 /* Register function hooks */
632 if (ng_ether_attach_p != NULL) {
633 error = EEXIST;
634 break;
635 }
636 ng_ether_attach_p = ng_ether_attach;
637 ng_ether_detach_p = ng_ether_detach;
638 ng_ether_output_p = ng_ether_output;
639 ng_ether_input_p = ng_ether_input;
640 ng_ether_input_orphan_p = ng_ether_input_orphan;
641
642 /* Create nodes for any already-existing Ethernet interfaces */
643 IFNET_RLOCK();
644 TAILQ_FOREACH(ifp, &ifnet, if_link) {
645 if (ifp->if_type == IFT_ETHER
646 || ifp->if_type == IFT_L2VLAN)
647 ng_ether_attach(ifp);
648 }
649 IFNET_RUNLOCK();
650 break;
651
652 case MOD_UNLOAD:
653
654 /*
655 * Note that the base code won't try to unload us until
656 * all nodes have been removed, and that can't happen
657 * until all Ethernet interfaces are removed. In any
658 * case, we know there are no nodes left if the action
659 * is MOD_UNLOAD, so there's no need to detach any nodes.
660 */
661
662 /* Unregister function hooks */
663 ng_ether_attach_p = NULL;
664 ng_ether_detach_p = NULL;
665 ng_ether_output_p = NULL;
666 ng_ether_input_p = NULL;
667 ng_ether_input_orphan_p = NULL;
668 break;
669
670 default:
671 error = EOPNOTSUPP;
672 break;
673 }
674 splx(s);
675 return (error);
676}
677