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