ifnet: Make rest of ifnet accessing MPSAFE
[dragonfly.git] / sys / netgraph7 / ether / ng_ether.c
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: src/sys/netgraph/ng_ether.c,v 1.62 2007/03/20 00:36:10 bms Exp $
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/if.h>
59 #include <net/if_dl.h>
60 #include <net/if_types.h>
61 #include <net/if_arp.h>
62 #include <net/if_var.h>
63 #include <net/ethernet.h>
64 #include <net/bridge/if_bridgevar.h>
65
66 #include <netgraph7/ng_message.h>
67 #include <netgraph7/netgraph.h>
68 #include <netgraph7/ng_parse.h>
69 #include "ng_ether.h"
70
71 #define IFP2AC(ifp)     ((struct arpcom *)ifp)
72 #define IFP2NG(ifp)     (IFP2AC((ifp))->ac_netgraph)
73
74 /* Per-node private data */
75 struct 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 };
85 typedef struct private *priv_p;
86
87 /* Functional hooks called from if_ethersubr.c */
88 static void     ng_ether_input(struct ifnet *ifp, struct mbuf **mp);
89 static void     ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m);
90 static int      ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
91 static void     ng_ether_attach(struct ifnet *ifp);
92 static void     ng_ether_detach(struct ifnet *ifp); 
93 #if 0
94 static void     ng_ether_link_state(struct ifnet *ifp, int state); 
95 #endif
96
97 /* Other functions */
98 static int      ng_ether_rcv_lower(node_p node, struct mbuf *m);
99 static int      ng_ether_rcv_upper(node_p node, struct mbuf *m);
100
101 /* Netgraph node methods */
102 static ng_constructor_t ng_ether_constructor;
103 static ng_rcvmsg_t      ng_ether_rcvmsg;
104 static ng_shutdown_t    ng_ether_shutdown;
105 static ng_newhook_t     ng_ether_newhook;
106 static ng_rcvdata_t     ng_ether_rcvdata;
107 static ng_disconnect_t  ng_ether_disconnect;
108 static 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 */
111 static 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         {
169           NGM_ETHER_COOKIE,
170           NGM_ETHER_ADD_MULTI,
171           "addmulti",
172           &ng_parse_enaddr_type,
173           NULL
174         },
175         {
176           NGM_ETHER_COOKIE,
177           NGM_ETHER_DEL_MULTI,
178           "delmulti",
179           &ng_parse_enaddr_type,
180           NULL
181         },
182         {
183           NGM_ETHER_COOKIE,
184           NGM_ETHER_DETACH,
185           "detach",
186           NULL,
187           NULL
188         },
189         { 0 }
190 };
191
192 static struct ng_type ng_ether_typestruct = {
193         .version =      NG_ABI_VERSION,
194         .name =         NG_ETHER_NODE_TYPE,
195         .mod_event =    ng_ether_mod_event,
196         .constructor =  ng_ether_constructor,
197         .rcvmsg =       ng_ether_rcvmsg,
198         .shutdown =     ng_ether_shutdown,
199         .newhook =      ng_ether_newhook,
200         .rcvdata =      ng_ether_rcvdata,
201         .disconnect =   ng_ether_disconnect,
202         .cmdlist =      ng_ether_cmdlist,
203 };
204 NETGRAPH_INIT(ether, &ng_ether_typestruct);
205
206 /******************************************************************
207                     ETHERNET FUNCTION HOOKS
208 ******************************************************************/
209
210 /*
211  * Handle a packet that has come in on an interface. We get to
212  * look at it here before any upper layer protocols do.
213  *
214  * NOTE: this function will get called at splimp()
215  */
216 static void
217 ng_ether_input(struct ifnet *ifp, struct mbuf **mp)
218 {
219         const node_p node = IFP2NG(ifp);
220         const priv_p priv = NG_NODE_PRIVATE(node);
221         int error;
222
223         /* If "lower" hook not connected, let packet continue */
224         if (priv->lower == NULL)
225                 return;
226         NG_SEND_DATA_ONLY(error, priv->lower, *mp);     /* sets *mp = NULL */
227 }
228
229 /*
230  * Handle a packet that has come in on an interface, and which
231  * does not match any of our known protocols (an ``orphan'').
232  *
233  * NOTE: this function will get called at splimp()
234  */
235 static void
236 ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m)
237 {
238         const node_p node = IFP2NG(ifp);
239         const priv_p priv = NG_NODE_PRIVATE(node);
240         int error;
241
242         /* If "orphan" hook not connected, discard packet */
243         if (priv->orphan == NULL) {
244                 m_freem(m);
245                 return;
246         }
247         NG_SEND_DATA_ONLY(error, priv->orphan, m);
248 }
249
250 /*
251  * Handle a packet that is going out on an interface.
252  * The Ethernet header is already attached to the mbuf.
253  */
254 static int
255 ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
256 {
257         const node_p node = IFP2NG(ifp);
258         const priv_p priv = NG_NODE_PRIVATE(node);
259         int error = 0;
260
261         /* If "upper" hook not connected, let packet continue */
262         if (priv->upper == NULL)
263                 return (0);
264
265         /* Send it out "upper" hook */
266         NG_SEND_DATA_ONLY(error, priv->upper, *mp);
267         return (error);
268 }
269
270 /*
271  * A new Ethernet interface has been attached.
272  * Create a new node for it, etc.
273  */
274 static void
275 ng_ether_attach(struct ifnet *ifp)
276 {
277         priv_p priv;
278         node_p node;
279
280         /* Create node */
281         KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__));
282         if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
283                 log(LOG_ERR, "%s: can't %s for %s\n",
284                     __func__, "create node", ifp->if_xname);
285                 return;
286         }
287
288         /* Allocate private data */
289         priv = kmalloc(sizeof(*priv), M_NETGRAPH,
290                        M_WAITOK | M_NULLOK | M_ZERO);
291         if (priv == NULL) {
292                 log(LOG_ERR, "%s: can't %s for %s\n",
293                     __func__, "allocate memory", ifp->if_xname);
294                 NG_NODE_UNREF(node);
295                 return;
296         }
297         NG_NODE_SET_PRIVATE(node, priv);
298         priv->ifp = ifp;
299         IFP2NG(ifp) = node;
300         priv->hwassist = ifp->if_hwassist;
301
302         /* Try to give the node the same name as the interface */
303         if (ng_name_node(node, ifp->if_xname) != 0) {
304                 log(LOG_WARNING, "%s: can't name node %s\n",
305                     __func__, ifp->if_xname);
306         }
307 }
308
309 /*
310  * An Ethernet interface is being detached.
311  * REALLY Destroy its node.
312  */
313 static void
314 ng_ether_detach(struct ifnet *ifp)
315 {
316         const node_p node = IFP2NG(ifp);
317         const priv_p priv = NG_NODE_PRIVATE(node);
318
319         NG_NODE_REALLY_DIE(node);       /* Force real removal of node */
320         /*
321          * We can't assume the ifnet is still around when we run shutdown
322          * So zap it now. XXX We HOPE that anything running at this time
323          * handles it (as it should in the non netgraph case).
324          */
325         IFP2NG(ifp) = NULL;
326         priv->ifp = NULL;       /* XXX race if interrupted an output packet */
327         ng_rmnode_self(node);           /* remove all netgraph parts */
328 }
329
330 #if 0
331 /*
332  * Notify graph about link event.
333  * if_link_state_change() has already checked that the state has changed.
334  */
335 static void
336 ng_ether_link_state(struct ifnet *ifp, int state)
337 {
338         const node_p node = IFP2NG(ifp);
339         const priv_p priv = NG_NODE_PRIVATE(node);
340         struct ng_mesg *msg;
341         int cmd, dummy_error = 0;
342
343         if (priv->lower == NULL)
344                 return;
345
346         if (state == LINK_STATE_UP)
347                 cmd = NGM_LINK_IS_UP;
348         else if (state == LINK_STATE_DOWN)
349                 cmd = NGM_LINK_IS_DOWN;
350         else
351                 return;
352
353         NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_WAITOK | M_NULLOK);
354         if (msg != NULL)
355                 NG_SEND_MSG_HOOK(dummy_error, node, msg, priv->lower, 0);
356 }
357 #endif
358 /******************************************************************
359                     NETGRAPH NODE METHODS
360 ******************************************************************/
361
362 /*
363  * It is not possible or allowable to create a node of this type.
364  * Nodes get created when the interface is attached (or, when
365  * this node type's KLD is loaded).
366  */
367 static int
368 ng_ether_constructor(node_p node)
369 {
370         return (EINVAL);
371 }
372
373 /*
374  * Check for attaching a new hook.
375  */
376 static  int
377 ng_ether_newhook(node_p node, hook_p hook, const char *name)
378 {
379         const priv_p priv = NG_NODE_PRIVATE(node);
380         hook_p *hookptr;
381
382         /* Divert hook is an alias for lower */
383         if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0)
384                 name = NG_ETHER_HOOK_LOWER;
385
386         /* Which hook? */
387         if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0)
388                 hookptr = &priv->upper;
389         else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0)
390                 hookptr = &priv->lower;
391         else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0)
392                 hookptr = &priv->orphan;
393         else
394                 return (EINVAL);
395
396         /* Check if already connected (shouldn't be, but doesn't hurt) */
397         if (*hookptr != NULL)
398                 return (EISCONN);
399
400         /* Disable hardware checksums while 'upper' hook is connected */
401         if (hookptr == &priv->upper)
402                 priv->ifp->if_hwassist = 0;
403
404         /* OK */
405         *hookptr = hook;
406         return (0);
407 }
408
409 /*
410  * Receive an incoming control message.
411  */
412 static int
413 ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook)
414 {
415         const priv_p priv = NG_NODE_PRIVATE(node);
416         struct ng_mesg *resp = NULL;
417         int error = 0;
418         struct ng_mesg *msg;
419
420         NGI_GET_MSG(item, msg);
421         switch (msg->header.typecookie) {
422         case NGM_ETHER_COOKIE:
423                 switch (msg->header.cmd) {
424                 case NGM_ETHER_GET_IFNAME:
425                         NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_WAITOK | M_NULLOK);
426                         if (resp == NULL) {
427                                 error = ENOMEM;
428                                 break;
429                         }
430                         strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ);
431                         break;
432                 case NGM_ETHER_GET_IFINDEX:
433                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
434                         if (resp == NULL) {
435                                 error = ENOMEM;
436                                 break;
437                         }
438                         *((u_int32_t *)resp->data) = priv->ifp->if_index;
439                         break;
440                 case NGM_ETHER_GET_ENADDR:
441                         NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_WAITOK | M_NULLOK);
442                         if (resp == NULL) {
443                                 error = ENOMEM;
444                                 break;
445                         }
446                         bcopy(IF_LLADDR(priv->ifp),
447                             resp->data, ETHER_ADDR_LEN);
448                         break;
449                 case NGM_ETHER_SET_ENADDR:
450                     {
451                         if (msg->header.arglen != ETHER_ADDR_LEN) {
452                                 error = EINVAL;
453                                 break;
454                         }
455                         error = if_setlladdr(priv->ifp,
456                             (u_char *)msg->data, ETHER_ADDR_LEN);
457                         break;
458                     }
459                 case NGM_ETHER_GET_PROMISC:
460                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
461                         if (resp == NULL) {
462                                 error = ENOMEM;
463                                 break;
464                         }
465                         *((u_int32_t *)resp->data) = priv->promisc;
466                         break;
467                 case NGM_ETHER_SET_PROMISC:
468                     {
469                         u_char want;
470
471                         if (msg->header.arglen != sizeof(u_int32_t)) {
472                                 error = EINVAL;
473                                 break;
474                         }
475                         want = !!*((u_int32_t *)msg->data);
476                         if (want ^ priv->promisc) {
477                                 if ((error = ifpromisc(priv->ifp, want)) != 0)
478                                         break;
479                                 priv->promisc = want;
480                         }
481                         break;
482                     }
483                 case NGM_ETHER_GET_AUTOSRC:
484                         NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_WAITOK | M_NULLOK);
485                         if (resp == NULL) {
486                                 error = ENOMEM;
487                                 break;
488                         }
489                         *((u_int32_t *)resp->data) = priv->autoSrcAddr;
490                         break;
491                 case NGM_ETHER_SET_AUTOSRC:
492                         if (msg->header.arglen != sizeof(u_int32_t)) {
493                                 error = EINVAL;
494                                 break;
495                         }
496                         priv->autoSrcAddr = !!*((u_int32_t *)msg->data);
497                         break;
498 #if 0
499                 case NGM_ETHER_ADD_MULTI:
500                     {
501                         struct sockaddr_dl sa_dl;
502                         struct ifmultiaddr *ifma;
503
504                         if (msg->header.arglen != ETHER_ADDR_LEN) {
505                                 error = EINVAL;
506                                 break;
507                         }
508                         bzero(&sa_dl, sizeof(struct sockaddr_dl));
509                         sa_dl.sdl_len = sizeof(struct sockaddr_dl);
510                         sa_dl.sdl_family = AF_LINK;
511                         sa_dl.sdl_alen = ETHER_ADDR_LEN;
512                         bcopy((void *)msg->data, LLADDR(&sa_dl),
513                             ETHER_ADDR_LEN);
514                         /*
515                          * Netgraph is only permitted to join groups once
516                          * via the if_addmulti() KPI, because it cannot hold
517                          * struct ifmultiaddr * between calls. It may also
518                          * lose a race while we check if the membership
519                          * already exists.
520                          */
521                         IF_ADDR_LOCK(priv->ifp);
522                         ifma = if_findmulti(priv->ifp,
523                             (struct sockaddr *)&sa_dl);
524                         IF_ADDR_UNLOCK(priv->ifp);
525                         if (ifma != NULL) {
526                                 error = EADDRINUSE;
527                         } else {
528                                 error = if_addmulti(priv->ifp,
529                                     (struct sockaddr *)&sa_dl, &ifma);
530                         }
531                         break;
532                     }
533 #endif
534                 case NGM_ETHER_DEL_MULTI:
535                     {
536                         struct sockaddr_dl sa_dl;
537
538                         if (msg->header.arglen != ETHER_ADDR_LEN) {
539                                 error = EINVAL;
540                                 break;
541                         }
542                         bzero(&sa_dl, sizeof(struct sockaddr_dl));
543                         sa_dl.sdl_len = sizeof(struct sockaddr_dl);
544                         sa_dl.sdl_family = AF_LINK;
545                         sa_dl.sdl_alen = ETHER_ADDR_LEN;
546                         bcopy((void *)msg->data, LLADDR(&sa_dl),
547                             ETHER_ADDR_LEN);
548                         error = if_delmulti(priv->ifp,
549                             (struct sockaddr *)&sa_dl);
550                         break;
551                     }
552                 case NGM_ETHER_DETACH:
553                         ng_ether_detach(priv->ifp);
554                         break;
555                 default:
556                         error = EINVAL;
557                         break;
558                 }
559                 break;
560         default:
561                 error = EINVAL;
562                 break;
563         }
564         NG_RESPOND_MSG(error, node, item, resp);
565         NG_FREE_MSG(msg);
566         return (error);
567 }
568
569 /*
570  * Receive data on a hook.
571  */
572 static int
573 ng_ether_rcvdata(hook_p hook, item_p item)
574 {
575         const node_p node = NG_HOOK_NODE(hook);
576         const priv_p priv = NG_NODE_PRIVATE(node);
577         struct mbuf *m;
578
579         NGI_GET_M(item, m);
580         NG_FREE_ITEM(item);
581
582         if (hook == priv->lower || hook == priv->orphan)
583                 return ng_ether_rcv_lower(node, m);
584         if (hook == priv->upper)
585                 return ng_ether_rcv_upper(node, m);
586         panic("%s: weird hook", __func__);
587 #ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */
588         return (0);
589 #endif
590 }
591
592 /*
593  * Handle an mbuf received on the "lower" or "orphan" hook.
594  */
595 static int
596 ng_ether_rcv_lower(node_p node, struct mbuf *m)
597 {
598         const priv_p priv = NG_NODE_PRIVATE(node);
599         struct ifnet *const ifp = priv->ifp;
600
601         /* Check whether interface is ready for packets */
602         if (!((ifp->if_flags & IFF_UP) &&
603             (ifp->if_flags & IFF_RUNNING))) {
604                 NG_FREE_M(m);
605                 return (ENETDOWN);
606         }
607
608         /* Make sure header is fully pulled up */
609         if (m->m_pkthdr.len < sizeof(struct ether_header)) {
610                 NG_FREE_M(m);
611                 return (EINVAL);
612         }
613         if (m->m_len < sizeof(struct ether_header)
614             && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
615                 return (ENOBUFS);
616
617         /* Drop in the MAC address if desired */
618         if (priv->autoSrcAddr) {
619
620                 /* Make the mbuf writable if it's not already */
621                 if (!M_WRITABLE(m)
622                     && (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
623                         return (ENOBUFS);
624
625                 /* Overwrite source MAC address */
626                 bcopy(IF_LLADDR(ifp),
627                     mtod(m, struct ether_header *)->ether_shost,
628                     ETHER_ADDR_LEN);
629         }
630
631         /* Send it on its way */
632         return ether_output_frame(ifp, m);
633 }
634
635 /*
636  * Handle an mbuf received on the "upper" hook.
637  */
638 extern  struct mbuf *bridge_input_p(struct ifnet *, struct mbuf *);
639 static int
640 ng_ether_rcv_upper(node_p node, struct mbuf *m)
641 {
642         const priv_p priv = NG_NODE_PRIVATE(node);
643         struct ifnet *ifp = priv->ifp;
644
645         /* Check length and pull off header */
646         if (m->m_pkthdr.len < sizeof(struct ether_header)) {
647                 NG_FREE_M(m);
648                 return (EINVAL);
649         }
650         if (m->m_len < sizeof(struct ether_header) &&
651             (m = m_pullup(m, sizeof(struct ether_header))) == NULL)
652                 return (ENOBUFS);
653
654         m->m_pkthdr.rcvif = ifp;
655
656         /* Pass the packet to the bridge, it may come back to us */
657         if (ifp->if_bridge) {
658                 bridge_input_p(ifp, m);
659                 if (m == NULL)
660                         return (0);
661         }
662
663         /* Route packet back in */
664         ether_demux_oncpu(ifp, m);
665         return (0);
666 }
667
668 /*
669  * Shutdown node. This resets the node but does not remove it
670  * unless the REALLY_DIE flag is set.
671  */
672 static int
673 ng_ether_shutdown(node_p node)
674 {
675         const priv_p priv = NG_NODE_PRIVATE(node);
676
677         if (node->nd_flags & NGF_REALLY_DIE) {
678                 /*
679                  * WE came here because the ethernet card is being unloaded,
680                  * so stop being persistant.
681                  * Actually undo all the things we did on creation.
682                  * Assume the ifp has already been freed.
683                  */
684                 NG_NODE_SET_PRIVATE(node, NULL);
685                 kfree(priv, M_NETGRAPH);
686                 NG_NODE_UNREF(node);    /* free node itself */
687                 return (0);
688         }
689         if (priv->promisc) {            /* disable promiscuous mode */
690                 (void)ifpromisc(priv->ifp, 0);
691                 priv->promisc = 0;
692         }
693         priv->autoSrcAddr = 1;          /* reset auto-src-addr flag */
694         NG_NODE_REVIVE(node);           /* Signal ng_rmnode we are persisant */
695
696         return (0);
697 }
698
699 /*
700  * Hook disconnection.
701  */
702 static int
703 ng_ether_disconnect(hook_p hook)
704 {
705         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
706
707         if (hook == priv->upper) {
708                 priv->upper = NULL;
709                 if (priv->ifp != NULL)          /* restore h/w csum */
710                         priv->ifp->if_hwassist = priv->hwassist;
711         } else if (hook == priv->lower)
712                 priv->lower = NULL;
713         else if (hook == priv->orphan)
714                 priv->orphan = NULL;
715         else
716                 panic("%s: weird hook", __func__);
717         if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
718         && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))))
719                 ng_rmnode_self(NG_HOOK_NODE(hook));     /* reset node */
720         return (0);
721 }
722
723 /******************************************************************
724                         INITIALIZATION
725 ******************************************************************/
726
727 /*
728  * Handle loading and unloading for this node type.
729  */
730 static int
731 ng_ether_mod_event(module_t mod, int event, void *data)
732 {
733         struct ifnet *ifp;
734         int error = 0;
735
736         crit_enter();
737         switch (event) {
738         case MOD_LOAD:
739
740                 /* Register function hooks */
741                 if (ng_ether_attach_p != NULL) {
742                         error = EEXIST;
743                         break;
744                 }
745                 ng_ether_attach_p = ng_ether_attach;
746                 ng_ether_detach_p = ng_ether_detach;
747                 ng_ether_output_p = ng_ether_output;
748                 ng_ether_input_p = ng_ether_input;
749                 ng_ether_input_orphan_p = ng_ether_input_orphan;
750 #if 0
751                 ng_ether_link_state_p = ng_ether_link_state;
752 #endif
753
754                 /* Create nodes for any already-existing Ethernet interfaces */
755                 ifnet_lock();
756                 TAILQ_FOREACH(ifp, &ifnetlist, if_link) {
757                         if (ifp->if_type == IFT_ETHER
758                             || ifp->if_type == IFT_L2VLAN)
759                                 ng_ether_attach(ifp);
760                 }
761                 ifnet_unlock();
762                 break;
763
764         case MOD_UNLOAD:
765
766                 /*
767                  * Note that the base code won't try to unload us until
768                  * all nodes have been removed, and that can't happen
769                  * until all Ethernet interfaces are removed. In any
770                  * case, we know there are no nodes left if the action
771                  * is MOD_UNLOAD, so there's no need to detach any nodes.
772                  */
773
774                 /* Unregister function hooks */
775                 ng_ether_attach_p = NULL;
776                 ng_ether_detach_p = NULL;
777                 ng_ether_output_p = NULL;
778                 ng_ether_input_p = NULL;
779                 ng_ether_input_orphan_p = NULL;
780 #if 0
781                 ng_ether_link_state_p = NULL;
782 #endif
783                 break;
784
785         default:
786                 error = EOPNOTSUPP;
787                 break;
788         }
789         crit_exit();
790         return (error);
791 }
792