]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/ng_iface.c
Remove the Yarrow PRNG algorithm option in accordance with due notice
[FreeBSD/FreeBSD.git] / sys / netgraph / ng_iface.c
1 /*
2  * ng_iface.c
3  */
4
5 /*-
6  * Copyright (c) 1996-1999 Whistle Communications, Inc.
7  * All rights reserved.
8  * 
9  * Subject to the following obligations and disclaimer of warranty, use and
10  * redistribution of this software, in source or object code forms, with or
11  * without modifications are expressly permitted by Whistle Communications;
12  * provided, however, that:
13  * 1. Any and all reproductions of the source or object code must include the
14  *    copyright notice above and the following disclaimer of warranties; and
15  * 2. No rights are granted, in any manner or form, to use Whistle
16  *    Communications, Inc. trademarks, including the mark "WHISTLE
17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18  *    such appears in the above copyright notice or in the software.
19  * 
20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36  * OF SUCH DAMAGE.
37  *
38  * Author: Archie Cobbs <archie@freebsd.org>
39  *
40  * $FreeBSD$
41  * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $
42  */
43
44 /*
45  * This node is also a system networking interface. It has
46  * a hook for each protocol (IP, AppleTalk, etc). Packets
47  * are simply relayed between the interface and the hooks.
48  *
49  * Interfaces are named ng0, ng1, etc.  New nodes take the
50  * first available interface name.
51  *
52  * This node also includes Berkeley packet filter support.
53  */
54
55 #include "opt_inet.h"
56 #include "opt_inet6.h"
57
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/errno.h>
61 #include <sys/kernel.h>
62 #include <sys/lock.h>
63 #include <sys/malloc.h>
64 #include <sys/mbuf.h>
65 #include <sys/errno.h>
66 #include <sys/proc.h>
67 #include <sys/random.h>
68 #include <sys/rmlock.h>
69 #include <sys/sockio.h>
70 #include <sys/socket.h>
71 #include <sys/syslog.h>
72 #include <sys/libkern.h>
73
74 #include <net/if.h>
75 #include <net/if_var.h>
76 #include <net/if_types.h>
77 #include <net/bpf.h>
78 #include <net/netisr.h>
79 #include <net/route.h>
80 #include <net/vnet.h>
81
82 #include <netinet/in.h>
83
84 #include <netgraph/ng_message.h>
85 #include <netgraph/netgraph.h>
86 #include <netgraph/ng_parse.h>
87 #include <netgraph/ng_iface.h>
88
89 #ifdef NG_SEPARATE_MALLOC
90 static MALLOC_DEFINE(M_NETGRAPH_IFACE, "netgraph_iface", "netgraph iface node");
91 #else
92 #define M_NETGRAPH_IFACE M_NETGRAPH
93 #endif
94
95 /* This struct describes one address family */
96 struct iffam {
97         sa_family_t     family;         /* Address family */
98         const char      *hookname;      /* Name for hook */
99 };
100 typedef const struct iffam *iffam_p;
101
102 /* List of address families supported by our interface */
103 const static struct iffam gFamilies[] = {
104         { AF_INET,      NG_IFACE_HOOK_INET      },
105         { AF_INET6,     NG_IFACE_HOOK_INET6     },
106         { AF_ATM,       NG_IFACE_HOOK_ATM       },
107         { AF_NATM,      NG_IFACE_HOOK_NATM      },
108 };
109 #define NUM_FAMILIES            nitems(gFamilies)
110
111 /* Node private data */
112 struct ng_iface_private {
113         struct  ifnet *ifp;             /* Our interface */
114         int     unit;                   /* Interface unit number */
115         node_p  node;                   /* Our netgraph node */
116         hook_p  hooks[NUM_FAMILIES];    /* Hook for each address family */
117         struct rmlock   lock;           /* Protect private data changes */
118 };
119 typedef struct ng_iface_private *priv_p;
120
121 #define PRIV_RLOCK(priv, t)     rm_rlock(&priv->lock, t)
122 #define PRIV_RUNLOCK(priv, t)   rm_runlock(&priv->lock, t)
123 #define PRIV_WLOCK(priv)        rm_wlock(&priv->lock)
124 #define PRIV_WUNLOCK(priv)      rm_wunlock(&priv->lock)
125
126 /* Interface methods */
127 static void     ng_iface_start(struct ifnet *ifp);
128 static int      ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
129 static int      ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
130                         const struct sockaddr *dst, struct route *ro);
131 static void     ng_iface_bpftap(struct ifnet *ifp,
132                         struct mbuf *m, sa_family_t family);
133 static int      ng_iface_send(struct ifnet *ifp, struct mbuf *m,
134                         sa_family_t sa);
135 #ifdef DEBUG
136 static void     ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
137 #endif
138
139 /* Netgraph methods */
140 static int              ng_iface_mod_event(module_t, int, void *);
141 static ng_constructor_t ng_iface_constructor;
142 static ng_rcvmsg_t      ng_iface_rcvmsg;
143 static ng_shutdown_t    ng_iface_shutdown;
144 static ng_newhook_t     ng_iface_newhook;
145 static ng_rcvdata_t     ng_iface_rcvdata;
146 static ng_disconnect_t  ng_iface_disconnect;
147
148 /* Helper stuff */
149 static iffam_p  get_iffam_from_af(sa_family_t family);
150 static iffam_p  get_iffam_from_hook(priv_p priv, hook_p hook);
151 static iffam_p  get_iffam_from_name(const char *name);
152 static hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
153
154 /* List of commands and how to convert arguments to/from ASCII */
155 static const struct ng_cmdlist ng_iface_cmds[] = {
156         {
157           NGM_IFACE_COOKIE,
158           NGM_IFACE_GET_IFNAME,
159           "getifname",
160           NULL,
161           &ng_parse_string_type
162         },
163         {
164           NGM_IFACE_COOKIE,
165           NGM_IFACE_POINT2POINT,
166           "point2point",
167           NULL,
168           NULL
169         },
170         {
171           NGM_IFACE_COOKIE,
172           NGM_IFACE_BROADCAST,
173           "broadcast",
174           NULL,
175           NULL
176         },
177         {
178           NGM_IFACE_COOKIE,
179           NGM_IFACE_GET_IFINDEX,
180           "getifindex",
181           NULL,
182           &ng_parse_uint32_type
183         },
184         { 0 }
185 };
186
187 /* Node type descriptor */
188 static struct ng_type typestruct = {
189         .version =      NG_ABI_VERSION,
190         .name =         NG_IFACE_NODE_TYPE,
191         .mod_event =    ng_iface_mod_event,
192         .constructor =  ng_iface_constructor,
193         .rcvmsg =       ng_iface_rcvmsg,
194         .shutdown =     ng_iface_shutdown,
195         .newhook =      ng_iface_newhook,
196         .rcvdata =      ng_iface_rcvdata,
197         .disconnect =   ng_iface_disconnect,
198         .cmdlist =      ng_iface_cmds,
199 };
200 NETGRAPH_INIT(iface, &typestruct);
201
202 VNET_DEFINE_STATIC(struct unrhdr *, ng_iface_unit);
203 #define V_ng_iface_unit                 VNET(ng_iface_unit)
204
205 /************************************************************************
206                         HELPER STUFF
207  ************************************************************************/
208
209 /*
210  * Get the family descriptor from the family ID
211  */
212 static __inline iffam_p
213 get_iffam_from_af(sa_family_t family)
214 {
215         iffam_p iffam;
216         int k;
217
218         for (k = 0; k < NUM_FAMILIES; k++) {
219                 iffam = &gFamilies[k];
220                 if (iffam->family == family)
221                         return (iffam);
222         }
223         return (NULL);
224 }
225
226 /*
227  * Get the family descriptor from the hook
228  */
229 static __inline iffam_p
230 get_iffam_from_hook(priv_p priv, hook_p hook)
231 {
232         int k;
233
234         for (k = 0; k < NUM_FAMILIES; k++)
235                 if (priv->hooks[k] == hook)
236                         return (&gFamilies[k]);
237         return (NULL);
238 }
239
240 /*
241  * Get the hook from the iffam descriptor
242  */
243
244 static __inline hook_p *
245 get_hook_from_iffam(priv_p priv, iffam_p iffam)
246 {
247         return (&priv->hooks[iffam - gFamilies]);
248 }
249
250 /*
251  * Get the iffam descriptor from the name
252  */
253 static __inline iffam_p
254 get_iffam_from_name(const char *name)
255 {
256         iffam_p iffam;
257         int k;
258
259         for (k = 0; k < NUM_FAMILIES; k++) {
260                 iffam = &gFamilies[k];
261                 if (!strcmp(iffam->hookname, name))
262                         return (iffam);
263         }
264         return (NULL);
265 }
266
267 /************************************************************************
268                         INTERFACE STUFF
269  ************************************************************************/
270
271 /*
272  * Process an ioctl for the virtual interface
273  */
274 static int
275 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
276 {
277         struct ifreq *const ifr = (struct ifreq *) data;
278         int error = 0;
279
280 #ifdef DEBUG
281         ng_iface_print_ioctl(ifp, command, data);
282 #endif
283         switch (command) {
284
285         /* These two are mostly handled at a higher layer */
286         case SIOCSIFADDR:
287                 ifp->if_flags |= IFF_UP;
288                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
289                 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
290                 break;
291         case SIOCGIFADDR:
292                 break;
293
294         /* Set flags */
295         case SIOCSIFFLAGS:
296                 /*
297                  * If the interface is marked up and stopped, then start it.
298                  * If it is marked down and running, then stop it.
299                  */
300                 if (ifr->ifr_flags & IFF_UP) {
301                         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
302                                 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
303                                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
304                         }
305                 } else {
306                         if (ifp->if_drv_flags & IFF_DRV_RUNNING)
307                                 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING |
308                                     IFF_DRV_OACTIVE);
309                 }
310                 break;
311
312         /* Set the interface MTU */
313         case SIOCSIFMTU:
314                 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
315                     || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
316                         error = EINVAL;
317                 else
318                         ifp->if_mtu = ifr->ifr_mtu;
319                 break;
320
321         /* Stuff that's not supported */
322         case SIOCADDMULTI:
323         case SIOCDELMULTI:
324                 error = 0;
325                 break;
326         case SIOCSIFPHYS:
327                 error = EOPNOTSUPP;
328                 break;
329
330         default:
331                 error = EINVAL;
332                 break;
333         }
334         return (error);
335 }
336
337 /*
338  * This routine is called to deliver a packet out the interface.
339  * We simply look at the address family and relay the packet to
340  * the corresponding hook, if it exists and is connected.
341  */
342
343 static int
344 ng_iface_output(struct ifnet *ifp, struct mbuf *m,
345         const struct sockaddr *dst, struct route *ro)
346 {
347         uint32_t af;
348         int error;
349
350         /* Check interface flags */
351         if (!((ifp->if_flags & IFF_UP) &&
352             (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
353                 m_freem(m);
354                 return (ENETDOWN);
355         }
356
357         /* Protect from deadly infinite recursion. */
358         error = if_tunnel_check_nesting(ifp, m, NGM_IFACE_COOKIE, 1);
359         if (error) {
360                 m_freem(m);
361                 return (error);
362         }
363
364         /* BPF writes need to be handled specially. */
365         if (dst->sa_family == AF_UNSPEC)
366                 bcopy(dst->sa_data, &af, sizeof(af));
367         else
368                 af = dst->sa_family;
369
370         /* Berkeley packet filter */
371         ng_iface_bpftap(ifp, m, af);
372
373         if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
374                 M_PREPEND(m, sizeof(sa_family_t), M_NOWAIT);
375                 if (m == NULL) {
376                         if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
377                         return (ENOBUFS);
378                 }
379                 *(sa_family_t *)m->m_data = af;
380                 error = (ifp->if_transmit)(ifp, m);
381         } else
382                 error = ng_iface_send(ifp, m, af);
383
384         return (error);
385 }
386
387 /*
388  * Start method is used only when ALTQ is enabled.
389  */
390 static void
391 ng_iface_start(struct ifnet *ifp)
392 {
393         struct mbuf *m;
394         sa_family_t sa;
395
396         KASSERT(ALTQ_IS_ENABLED(&ifp->if_snd), ("%s without ALTQ", __func__));
397
398         for(;;) {
399                 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
400                 if (m == NULL)
401                         break;
402                 sa = *mtod(m, sa_family_t *);
403                 m_adj(m, sizeof(sa_family_t));
404                 ng_iface_send(ifp, m, sa);
405         }
406 }
407
408 /*
409  * Flash a packet by the BPF (requires prepending 4 byte AF header)
410  * Note the phoney mbuf; this is OK because BPF treats it read-only.
411  */
412 static void
413 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family)
414 {
415         KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__));
416         if (bpf_peers_present(ifp->if_bpf)) {
417                 int32_t family4 = (int32_t)family;
418                 bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m);
419         }
420 }
421
422 /*
423  * This routine does actual delivery of the packet into the
424  * netgraph(4). It is called from ng_iface_start() and
425  * ng_iface_output().
426  */
427 static int
428 ng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa)
429 {
430         struct rm_priotracker priv_tracker;
431         const priv_p priv = (priv_p) ifp->if_softc;
432         const iffam_p iffam = get_iffam_from_af(sa);
433         hook_p hook;
434         int error;
435         int len;
436
437         /* Check address family to determine hook (if known) */
438         if (iffam == NULL) {
439                 m_freem(m);
440                 log(LOG_WARNING, "%s: can't handle af%d\n", ifp->if_xname, sa);
441                 return (EAFNOSUPPORT);
442         }
443
444         /* Copy length before the mbuf gets invalidated. */
445         len = m->m_pkthdr.len;
446
447         PRIV_RLOCK(priv, &priv_tracker);
448         hook = *get_hook_from_iffam(priv, iffam);
449         if (hook == NULL) {
450                 NG_FREE_M(m);
451                 PRIV_RUNLOCK(priv, &priv_tracker);
452                 return ENETDOWN;
453         }
454         NG_HOOK_REF(hook);
455         PRIV_RUNLOCK(priv, &priv_tracker);
456
457         NG_OUTBOUND_THREAD_REF();
458         NG_SEND_DATA_ONLY(error, hook, m);
459         NG_OUTBOUND_THREAD_UNREF();
460         NG_HOOK_UNREF(hook);
461
462         /* Update stats. */
463         if (error == 0) {
464                 if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
465                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
466         }
467
468         return (error);
469 }
470
471 #ifdef DEBUG
472 /*
473  * Display an ioctl to the virtual interface
474  */
475
476 static void
477 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
478 {
479         char   *str;
480
481         switch (command & IOC_DIRMASK) {
482         case IOC_VOID:
483                 str = "IO";
484                 break;
485         case IOC_OUT:
486                 str = "IOR";
487                 break;
488         case IOC_IN:
489                 str = "IOW";
490                 break;
491         case IOC_INOUT:
492                 str = "IORW";
493                 break;
494         default:
495                 str = "IO??";
496         }
497         log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
498                ifp->if_xname,
499                str,
500                IOCGROUP(command),
501                command & 0xff,
502                IOCPARM_LEN(command));
503 }
504 #endif /* DEBUG */
505
506 /************************************************************************
507                         NETGRAPH NODE STUFF
508  ************************************************************************/
509
510 /*
511  * Constructor for a node
512  */
513 static int
514 ng_iface_constructor(node_p node)
515 {
516         struct ifnet *ifp;
517         priv_p priv;
518
519         /* Allocate node and interface private structures */
520         priv = malloc(sizeof(*priv), M_NETGRAPH_IFACE, M_WAITOK | M_ZERO);
521         ifp = if_alloc(IFT_PROPVIRTUAL);
522         if (ifp == NULL) {
523                 free(priv, M_NETGRAPH_IFACE);
524                 return (ENOMEM);
525         }
526
527         rm_init(&priv->lock, "ng_iface private rmlock");
528
529         /* Link them together */
530         ifp->if_softc = priv;
531         priv->ifp = ifp;
532
533         /* Get an interface unit number */
534         priv->unit = alloc_unr(V_ng_iface_unit);
535
536         /* Link together node and private info */
537         NG_NODE_SET_PRIVATE(node, priv);
538         priv->node = node;
539
540         /* Initialize interface structure */
541         if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit);
542         ifp->if_output = ng_iface_output;
543         ifp->if_start = ng_iface_start;
544         ifp->if_ioctl = ng_iface_ioctl;
545         ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
546         ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST);
547         ifp->if_type = IFT_PROPVIRTUAL;         /* XXX */
548         ifp->if_addrlen = 0;                    /* XXX */
549         ifp->if_hdrlen = 0;                     /* XXX */
550         ifp->if_baudrate = 64000;               /* XXX */
551         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
552         ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
553         IFQ_SET_READY(&ifp->if_snd);
554
555         /* Give this node the same name as the interface (if possible) */
556         if (ng_name_node(node, ifp->if_xname) != 0)
557                 log(LOG_WARNING, "%s: can't acquire netgraph name\n",
558                     ifp->if_xname);
559
560         /* Attach the interface */
561         if_attach(ifp);
562         bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
563
564         /* Done */
565         return (0);
566 }
567
568 /*
569  * Give our ok for a hook to be added
570  */
571 static int
572 ng_iface_newhook(node_p node, hook_p hook, const char *name)
573 {
574         const iffam_p iffam = get_iffam_from_name(name);
575         const priv_p priv = NG_NODE_PRIVATE(node);
576         hook_p *hookptr;
577
578         if (iffam == NULL)
579                 return (EPFNOSUPPORT);
580         PRIV_WLOCK(priv);
581         hookptr = get_hook_from_iffam(priv, iffam);
582         if (*hookptr != NULL) {
583                 PRIV_WUNLOCK(priv);
584                 return (EISCONN);
585         }
586         *hookptr = hook;
587         NG_HOOK_HI_STACK(hook);
588         NG_HOOK_SET_TO_INBOUND(hook);
589         PRIV_WUNLOCK(priv);
590         return (0);
591 }
592
593 /*
594  * Receive a control message
595  */
596 static int
597 ng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook)
598 {
599         const priv_p priv = NG_NODE_PRIVATE(node);
600         struct ifnet *const ifp = priv->ifp;
601         struct ng_mesg *resp = NULL;
602         int error = 0;
603         struct ng_mesg *msg;
604
605         NGI_GET_MSG(item, msg);
606         switch (msg->header.typecookie) {
607         case NGM_IFACE_COOKIE:
608                 switch (msg->header.cmd) {
609                 case NGM_IFACE_GET_IFNAME:
610                         NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
611                         if (resp == NULL) {
612                                 error = ENOMEM;
613                                 break;
614                         }
615                         strlcpy(resp->data, ifp->if_xname, IFNAMSIZ);
616                         break;
617
618                 case NGM_IFACE_POINT2POINT:
619                 case NGM_IFACE_BROADCAST:
620                     {
621
622                         /* Deny request if interface is UP */
623                         if ((ifp->if_flags & IFF_UP) != 0)
624                                 return (EBUSY);
625
626                         /* Change flags */
627                         switch (msg->header.cmd) {
628                         case NGM_IFACE_POINT2POINT:
629                                 ifp->if_flags |= IFF_POINTOPOINT;
630                                 ifp->if_flags &= ~IFF_BROADCAST;
631                                 break;
632                         case NGM_IFACE_BROADCAST:
633                                 ifp->if_flags &= ~IFF_POINTOPOINT;
634                                 ifp->if_flags |= IFF_BROADCAST;
635                                 break;
636                         }
637                         break;
638                     }
639
640                 case NGM_IFACE_GET_IFINDEX:
641                         NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
642                         if (resp == NULL) {
643                                 error = ENOMEM;
644                                 break;
645                         }
646                         *((uint32_t *)resp->data) = priv->ifp->if_index;
647                         break;
648
649                 default:
650                         error = EINVAL;
651                         break;
652                 }
653                 break;
654         case NGM_FLOW_COOKIE:
655                 switch (msg->header.cmd) {
656                 case NGM_LINK_IS_UP:
657                         if_link_state_change(ifp, LINK_STATE_UP);
658                         break;
659                 case NGM_LINK_IS_DOWN:
660                         if_link_state_change(ifp, LINK_STATE_DOWN);
661                         break;
662                 default:
663                         break;
664                 }
665                 break;
666         default:
667                 error = EINVAL;
668                 break;
669         }
670         NG_RESPOND_MSG(error, node, item, resp);
671         NG_FREE_MSG(msg);
672         return (error);
673 }
674
675 /*
676  * Recive data from a hook. Pass the packet to the correct input routine.
677  */
678 static int
679 ng_iface_rcvdata(hook_p hook, item_p item)
680 {
681         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
682         const iffam_p iffam = get_iffam_from_hook(priv, hook);
683         struct ifnet *const ifp = priv->ifp;
684         struct mbuf *m;
685         int isr;
686
687         NGI_GET_M(item, m);
688         NG_FREE_ITEM(item);
689         /* Sanity checks */
690         KASSERT(iffam != NULL, ("%s: iffam", __func__));
691         M_ASSERTPKTHDR(m);
692         if ((ifp->if_flags & IFF_UP) == 0) {
693                 NG_FREE_M(m);
694                 return (ENETDOWN);
695         }
696
697         /* Update interface stats */
698         if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
699         if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
700
701         /* Note receiving interface */
702         m->m_pkthdr.rcvif = ifp;
703
704         /* Berkeley packet filter */
705         ng_iface_bpftap(ifp, m, iffam->family);
706
707         /* Send packet */
708         switch (iffam->family) {
709 #ifdef INET
710         case AF_INET:
711                 isr = NETISR_IP;
712                 break;
713 #endif
714 #ifdef INET6
715         case AF_INET6:
716                 isr = NETISR_IPV6;
717                 break;
718 #endif
719         default:
720                 m_freem(m);
721                 return (EAFNOSUPPORT);
722         }
723         random_harvest_queue(m, sizeof(*m), RANDOM_NET_NG);
724         M_SETFIB(m, ifp->if_fib);
725         netisr_dispatch(isr, m);
726         return (0);
727 }
728
729 /*
730  * Shutdown and remove the node and its associated interface.
731  */
732 static int
733 ng_iface_shutdown(node_p node)
734 {
735         const priv_p priv = NG_NODE_PRIVATE(node);
736
737         /*
738          * The ifnet may be in a different vnet than the netgraph node, 
739          * hence we have to change the current vnet context here.
740          */
741         CURVNET_SET_QUIET(priv->ifp->if_vnet);
742         bpfdetach(priv->ifp);
743         if_detach(priv->ifp);
744         if_free(priv->ifp);
745         CURVNET_RESTORE();
746         priv->ifp = NULL;
747         free_unr(V_ng_iface_unit, priv->unit);
748         rm_destroy(&priv->lock);
749         free(priv, M_NETGRAPH_IFACE);
750         NG_NODE_SET_PRIVATE(node, NULL);
751         NG_NODE_UNREF(node);
752         return (0);
753 }
754
755 /*
756  * Hook disconnection. Note that we do *not* shutdown when all
757  * hooks have been disconnected.
758  */
759 static int
760 ng_iface_disconnect(hook_p hook)
761 {
762         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
763         const iffam_p iffam = get_iffam_from_hook(priv, hook);
764
765         if (iffam == NULL)
766                 panic("%s", __func__);
767         PRIV_WLOCK(priv);
768         *get_hook_from_iffam(priv, iffam) = NULL;
769         PRIV_WUNLOCK(priv);
770         return (0);
771 }
772
773 /*
774  * Handle loading and unloading for this node type.
775  */
776 static int
777 ng_iface_mod_event(module_t mod, int event, void *data)
778 {
779         int error = 0;
780
781         switch (event) {
782         case MOD_LOAD:
783         case MOD_UNLOAD:
784                 break;
785         default:
786                 error = EOPNOTSUPP;
787                 break;
788         }
789         return (error);
790 }
791
792 static void
793 vnet_ng_iface_init(const void *unused)
794 {
795
796         V_ng_iface_unit = new_unrhdr(0, 0xffff, NULL);
797 }
798 VNET_SYSINIT(vnet_ng_iface_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
799     vnet_ng_iface_init, NULL);
800
801 static void
802 vnet_ng_iface_uninit(const void *unused)
803 {
804
805         delete_unrhdr(V_ng_iface_unit);
806 }
807 VNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
808     vnet_ng_iface_uninit, NULL);