xref: /freebsd/sys/netgraph/ng_iface.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 
2 /*
3  * ng_iface.c
4  *
5  * Copyright (c) 1996-1999 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  * Author: Archie Cobbs <archie@whistle.com>
38  *
39  * $FreeBSD$
40  * $Whistle: ng_iface.c,v 1.31 1999/02/02 22:27:28 archie Exp $
41  */
42 
43 /*
44  * This node is also a system networking interface. It has
45  * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
46  * are simply relayed between the interface and the hooks.
47  *
48  * Interfaces are named ng0, ng1, .... FreeBSD does not support
49  * the removal of interfaces, so iface nodes are persistent.
50  *
51  * This node also includes Berkeley packet filter support.
52  */
53 
54 #include "opt_inet.h"
55 #include "opt_atalk.h"
56 #include "opt_ipx.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/malloc.h>
63 #include <sys/mbuf.h>
64 #include <sys/conf.h>
65 #include <sys/errno.h>
66 #include <sys/sockio.h>
67 #include <sys/socket.h>
68 #include <sys/syslog.h>
69 
70 #include <net/route.h>
71 #include <net/if.h>
72 #include <net/if_dl.h>
73 #include <net/if_types.h>
74 #include <net/netisr.h>
75 
76 #include <netgraph/ng_message.h>
77 #include <netgraph/netgraph.h>
78 #include <netgraph/ng_iface.h>
79 #include <netgraph/ng_cisco.h>
80 
81 #ifdef INET
82 #include <netinet/in.h>
83 #include <netinet/in_systm.h>
84 #include <netinet/in_var.h>
85 #include <netinet/ip.h>
86 #include <netinet/if_ether.h>
87 #include <netinet/in_var.h>
88 #endif
89 
90 #ifdef NETATALK
91 #include <netatalk/at.h>
92 #include <netatalk/at_var.h>
93 #include <netatalk/at_extern.h>
94 #endif
95 
96 #ifdef IPX
97 #include <netipx/ipx.h>
98 #include <netipx/ipx_if.h>
99 #endif
100 
101 #ifdef NS
102 #include <netns/ns.h>
103 #include <netns/ns_if.h>
104 #endif
105 
106 #include "bpfilter.h"
107 
108 #if NBPFILTER > 0
109 #include <net/bpf.h>
110 #include <net/bpfdesc.h>
111 #endif
112 
113 /* This struct describes one address family */
114 struct iffam {
115 	char   *hookname;	/* Name for hook */
116 	u_char  af;		/* Family number */
117 	u_char  netisr;		/* or NETISR_NONE */
118 	union {
119 		void	*_dummy;			/* avoid warning */
120 		struct	ifqueue *inq;			/* if netisr */
121 		void	(*input)(struct mbuf *m);	/* if direct input */
122 	}       u;
123 };
124 typedef const struct iffam *iffam_p;
125 
126 #define NETISR_NONE	0xff
127 
128 /* List of address families supported by our interface. Each address
129    family has a way to input packets to it, either by calling a function
130    directly (such as ip_input()) or by adding the packet to a queue and
131    setting a NETISR bit. */
132 const static struct iffam gFamilies[] = {
133 #ifdef INET
134 	{
135 		NG_IFACE_HOOK_INET,
136 		AF_INET,
137 		NETISR_NONE,
138 		ip_input
139 	},
140 #endif
141 #ifdef NETATALK
142 	{
143 		NG_IFACE_HOOK_ATALK,
144 		AF_APPLETALK,
145 		NETISR_ATALK,
146 		&atintrq2
147 	},
148 #endif
149 #ifdef IPX
150 	{
151 		NG_IFACE_HOOK_IPX,
152 		AF_IPX,
153 		NETISR_IPX,
154 		&ipxintrq
155 	},
156 #endif
157 #ifdef NS
158 	{
159 		NG_IFACE_HOOK_NS,
160 		AF_NS,
161 		NETISR_NS,
162 		&nsintrq
163 	},
164 #endif
165 };
166 #define NUM_FAMILIES		(sizeof(gFamilies) / sizeof(*gFamilies))
167 
168 /* Node private data */
169 struct private {
170 	struct	ifnet *ifp;		/* This interface */
171 	node_p	node;			/* Our netgraph node */
172 	hook_p	hooks[NUM_FAMILIES];	/* Hook for each address family */
173 	struct	private *next;		/* When hung on the free list */
174 };
175 typedef struct private *priv_p;
176 
177 /* Interface methods */
178 static void	ng_iface_start(struct ifnet *ifp);
179 static int	ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
180 static int	ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
181 		struct sockaddr *dst, struct rtentry *rt0);
182 #if NBPFILTER > 0
183 static void	ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af);
184 #endif
185 #ifdef DEBUG
186 static void	ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
187 #endif
188 
189 /* Netgraph methods */
190 static int	ng_iface_constructor(node_p *nodep);
191 static int	ng_iface_rcvmsg(node_p node, struct ng_mesg *msg,
192 		    const char *retaddr, struct ng_mesg **resp);
193 static int	ng_iface_rmnode(node_p node);
194 static int	ng_iface_newhook(node_p node, hook_p hook, const char *name);
195 static int	ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
196 static int	ng_iface_disconnect(hook_p hook);
197 
198 /* Helper stuff */
199 static iffam_p	get_iffam_from_af(int af);
200 static iffam_p	get_iffam_from_hook(priv_p priv, hook_p hook);
201 static iffam_p	get_iffam_from_name(const char *name);
202 static hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
203 
204 /* Node type descriptor */
205 static struct ng_type typestruct = {
206 	NG_VERSION,
207 	NG_IFACE_NODE_TYPE,
208 	NULL,
209 	ng_iface_constructor,
210 	ng_iface_rcvmsg,
211 	ng_iface_rmnode,
212 	ng_iface_newhook,
213 	NULL,
214 	NULL,
215 	ng_iface_rcvdata,
216 	ng_iface_rcvdata,
217 	ng_iface_disconnect
218 };
219 NETGRAPH_INIT(iface, &typestruct);
220 
221 static char ng_iface_ifname[] = NG_IFACE_IFACE_NAME;
222 static int ng_iface_next_unit;
223 
224 /************************************************************************
225 			HELPER STUFF
226  ************************************************************************/
227 
228 /*
229  * Get the family descriptor from the family ID
230  */
231 static __inline__ iffam_p
232 get_iffam_from_af(int af)
233 {
234 	iffam_p iffam;
235 	int k;
236 
237 	for (k = 0; k < NUM_FAMILIES; k++) {
238 		iffam = &gFamilies[k];
239 		if (iffam->af == af)
240 			return (iffam);
241 	}
242 	return (NULL);
243 }
244 
245 /*
246  * Get the family descriptor from the hook
247  */
248 static __inline__ iffam_p
249 get_iffam_from_hook(priv_p priv, hook_p hook)
250 {
251 	int k;
252 
253 	for (k = 0; k < NUM_FAMILIES; k++)
254 		if (priv->hooks[k] == hook)
255 			return (&gFamilies[k]);
256 	return (NULL);
257 }
258 
259 /*
260  * Get the hook from the iffam descriptor
261  */
262 
263 static __inline__ hook_p *
264 get_hook_from_iffam(priv_p priv, iffam_p iffam)
265 {
266 	return (&priv->hooks[iffam - gFamilies]);
267 }
268 
269 /*
270  * Get the iffam descriptor from the name
271  */
272 static __inline__ iffam_p
273 get_iffam_from_name(const char *name)
274 {
275 	iffam_p iffam;
276 	int k;
277 
278 	for (k = 0; k < NUM_FAMILIES; k++) {
279 		iffam = &gFamilies[k];
280 		if (!strcmp(iffam->hookname, name))
281 			return (iffam);
282 	}
283 	return (NULL);
284 }
285 
286 /************************************************************************
287 			INTERFACE STUFF
288  ************************************************************************/
289 
290 /*
291  * Process an ioctl for the virtual interface
292  */
293 static int
294 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
295 {
296 	struct ifreq *const ifr = (struct ifreq *) data;
297 	int s, error = 0;
298 
299 #ifdef DEBUG
300 	ng_iface_print_ioctl(ifp, command, data);
301 #endif
302 	s = splimp();
303 	switch (command) {
304 
305 	/* These two are mostly handled at a higher layer */
306 	case SIOCSIFADDR:
307 		ifp->if_flags |= (IFF_UP | IFF_RUNNING);
308 		ifp->if_flags &= ~(IFF_OACTIVE);
309 		break;
310 	case SIOCGIFADDR:
311 		break;
312 
313 	/* Set flags */
314 	case SIOCSIFFLAGS:
315 		/*
316 		 * If the interface is marked up and stopped, then start it.
317 		 * If it is marked down and running, then stop it.
318 		 */
319 		if (ifr->ifr_flags & IFF_UP) {
320 			if (!(ifp->if_flags & IFF_RUNNING)) {
321 				ifp->if_flags &= ~(IFF_OACTIVE);
322 				ifp->if_flags |= IFF_RUNNING;
323 			}
324 		} else {
325 			if (ifp->if_flags & IFF_RUNNING)
326 				ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
327 		}
328 		break;
329 
330 	/* Set the interface MTU */
331 	case SIOCSIFMTU:
332 		if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
333 		    || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
334 			error = EINVAL;
335 		else
336 			ifp->if_mtu = ifr->ifr_mtu;
337 		break;
338 
339 	/* Stuff that's not supported */
340 	case SIOCADDMULTI:
341 	case SIOCDELMULTI:
342 	case SIOCSIFPHYS:
343 		error = EOPNOTSUPP;
344 		break;
345 
346 	default:
347 		error = EINVAL;
348 		break;
349 	}
350 	(void) splx(s);
351 	return (error);
352 }
353 
354 /*
355  * This routine is called to deliver a packet out the interface.
356  * We simply look at the address family and relay the packet to
357  * the corresponding hook, if it exists and is connected.
358  */
359 
360 static int
361 ng_iface_output(struct ifnet *ifp, struct mbuf *m,
362 		struct sockaddr *dst, struct rtentry *rt0)
363 {
364 	const priv_p priv = (priv_p) ifp->if_softc;
365 	const iffam_p iffam = get_iffam_from_af(dst->sa_family);
366 	meta_p meta = NULL;
367 	int len, error = 0;
368 
369 	/* Check interface flags */
370 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
371 		m_freem(m);
372 		return (ENETDOWN);
373 	}
374 
375 	/* Berkeley packet filter */
376 #if NBPFILTER > 0
377 	ng_iface_bpftap(ifp, m, dst->sa_family);
378 #endif
379 
380 	/* Check address family to determine hook (if known) */
381 	if (iffam == NULL) {
382 		m_freem(m);
383 		log(LOG_WARNING, "%s%d: can't handle af%d\n",
384 		       ifp->if_name, ifp->if_unit, dst->sa_family);
385 		return (EAFNOSUPPORT);
386 	}
387 
388 	/* Copy length before the mbuf gets invalidated */
389 	len = m->m_pkthdr.len;
390 
391 	/* Send packet; if hook is not connected, mbuf will get freed. */
392 	NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta);
393 
394 	/* Update stats */
395 	if (error == 0) {
396 		ifp->if_obytes += len;
397 		ifp->if_opackets++;
398 	}
399 	return (error);
400 }
401 
402 /*
403  * This routine should never be called
404  */
405 
406 static void
407 ng_iface_start(struct ifnet *ifp)
408 {
409 	printf("%s%d: %s called?", ifp->if_name, ifp->if_unit, __FUNCTION__);
410 }
411 
412 #if NBPFILTER > 0
413 /*
414  * Flash a packet by the BPF (requires prepending 4 byte AF header)
415  * Note the phoney mbuf; this is OK because BPF treats it read-only.
416  */
417 static void
418 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af)
419 {
420 	struct mbuf m2;
421 
422 	if (af == AF_UNSPEC) {
423 		af = *(mtod(m, int *));
424 		m->m_len -= sizeof(int);
425 		m->m_pkthdr.len -= sizeof(int);
426 		m->m_data += sizeof(int);
427 	}
428 	if (!ifp->if_bpf)
429 		return;
430 	m2.m_next = m;
431 	m2.m_len = 4;
432 	m2.m_data = (char *) &af;
433 	bpf_mtap(ifp, &m2);
434 }
435 #endif /* NBPFILTER > 0 */
436 
437 #ifdef DEBUG
438 /*
439  * Display an ioctl to the virtual interface
440  */
441 
442 static void
443 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
444 {
445 	char   *str;
446 
447 	switch (command & IOC_DIRMASK) {
448 	case IOC_VOID:
449 		str = "IO";
450 		break;
451 	case IOC_OUT:
452 		str = "IOR";
453 		break;
454 	case IOC_IN:
455 		str = "IOW";
456 		break;
457 	case IOC_INOUT:
458 		str = "IORW";
459 		break;
460 	default:
461 		str = "IO??";
462 	}
463 	log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n",
464 	       ifp->if_name, ifp->if_unit,
465 	       str,
466 	       IOCGROUP(command),
467 	       command & 0xff,
468 	       IOCPARM_LEN(command));
469 }
470 #endif /* DEBUG */
471 
472 /************************************************************************
473 			NETGRAPH NODE STUFF
474  ************************************************************************/
475 
476 /*
477  * Constructor for a node
478  */
479 static int
480 ng_iface_constructor(node_p *nodep)
481 {
482 	char ifname[NG_IFACE_IFACE_NAME_MAX + 1];
483 	struct ifnet *ifp;
484 	node_p node;
485 	priv_p priv;
486 	int error = 0;
487 
488 	/* Allocate node and interface private structures */
489 	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
490 	if (priv == NULL)
491 		return (ENOMEM);
492 	bzero(priv, sizeof(*priv));
493 	MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH, M_WAITOK);
494 	if (ifp == NULL) {
495 		FREE(priv, M_NETGRAPH);
496 		return (ENOMEM);
497 	}
498 	bzero(ifp, sizeof(*ifp));
499 
500 	/* Link them together */
501 	ifp->if_softc = priv;
502 	priv->ifp = ifp;
503 
504 	/* Call generic node constructor */
505 	if ((error = ng_make_node_common(&typestruct, nodep))) {
506 		FREE(priv, M_NETGRAPH);
507 		FREE(ifp, M_NETGRAPH);
508 		return (error);
509 	}
510 	node = *nodep;
511 
512 	/* Link together node and private info */
513 	node->private = priv;
514 	priv->node = node;
515 
516 	/* Initialize interface structure */
517 	ifp->if_name = ng_iface_ifname;
518 	ifp->if_unit = ng_iface_next_unit++;
519 	ifp->if_output = ng_iface_output;
520 	ifp->if_start = ng_iface_start;
521 	ifp->if_ioctl = ng_iface_ioctl;
522 	ifp->if_watchdog = NULL;
523 	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
524 	ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
525 	ifp->if_flags = (IFF_SIMPLEX | IFF_POINTOPOINT | IFF_NOARP);
526 	ifp->if_type = IFT_PROPVIRTUAL;		/* XXX */
527 	ifp->if_addrlen = 0;			/* XXX */
528 	ifp->if_hdrlen = 0;			/* XXX */
529 	ifp->if_baudrate = 64000;		/* XXX */
530 	TAILQ_INIT(&ifp->if_addrhead);
531 
532 	/* Give this node the same name as the interface (if possible) */
533 	bzero(ifname, sizeof(ifname));
534 	sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
535 	(void) ng_name_node(node, ifname);
536 
537 	/* Attach the interface */
538 	if_attach(ifp);
539 #if NBPFILTER > 0
540 	bpfattach(ifp, DLT_NULL, sizeof(u_int));
541 #endif
542 
543 	/* Done */
544 	return (0);
545 }
546 
547 /*
548  * Give our ok for a hook to be added
549  */
550 static int
551 ng_iface_newhook(node_p node, hook_p hook, const char *name)
552 {
553 	const iffam_p iffam = get_iffam_from_name(name);
554 	hook_p *hookptr;
555 
556 	if (iffam == NULL)
557 		return (EPFNOSUPPORT);
558 	hookptr = get_hook_from_iffam((priv_p) node->private, iffam);
559 	if (*hookptr != NULL)
560 		return (EISCONN);
561 	*hookptr = hook;
562 	return (0);
563 }
564 
565 /*
566  * Receive a control message
567  */
568 static int
569 ng_iface_rcvmsg(node_p node, struct ng_mesg *msg,
570 		const char *retaddr, struct ng_mesg **rptr)
571 {
572 	const priv_p priv = node->private;
573 	struct ifnet *const ifp = priv->ifp;
574 	struct ng_mesg *resp = NULL;
575 	int error = 0;
576 
577 	switch (msg->header.typecookie) {
578 	case NGM_IFACE_COOKIE:
579 		switch (msg->header.cmd) {
580 		case NGM_IFACE_GET_IFNAME:
581 		    {
582 			struct ng_iface_ifname *arg;
583 
584 			NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
585 			if (resp == NULL) {
586 				error = ENOMEM;
587 				break;
588 			}
589 			arg = (struct ng_iface_ifname *) resp->data;
590 			sprintf(arg->ngif_name,
591 			    "%s%d", ifp->if_name, ifp->if_unit);
592 			break;
593 		    }
594 
595 		case NGM_IFACE_GET_IFADDRS:
596 		    {
597 			struct ifaddr *ifa;
598 			caddr_t ptr;
599 			int buflen;
600 
601 #define SA_SIZE(s)	((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len)
602 
603 			/* Determine size of response and allocate it */
604 			buflen = 0;
605 			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
606 				buflen += SA_SIZE(ifa->ifa_addr);
607 			NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT);
608 			if (resp == NULL) {
609 				error = ENOMEM;
610 				break;
611 			}
612 
613 			/* Add addresses */
614 			ptr = resp->data;
615 			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
616 				const int len = SA_SIZE(ifa->ifa_addr);
617 
618 				if (buflen < len) {
619 					log(LOG_ERR, "%s%d: len changed?\n",
620 					    ifp->if_name, ifp->if_unit);
621 					break;
622 				}
623 				bcopy(ifa->ifa_addr, ptr, len);
624 				ptr += len;
625 				buflen -= len;
626 			}
627 			break;
628 #undef SA_SIZE
629 		    }
630 
631 		default:
632 			error = EINVAL;
633 			break;
634 		}
635 		break;
636 	case NGM_CISCO_COOKIE:
637 		switch (msg->header.cmd) {
638 		case NGM_CISCO_GET_IPADDR:	/* we understand this too */
639 		    {
640 			struct ifaddr *ifa;
641 
642 			/* Return the first configured IP address */
643 			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
644 				struct in_addr *ips;
645 
646 				if (ifa->ifa_addr->sa_family != AF_INET)
647 					continue;
648 				NG_MKRESPONSE(resp, msg,
649 				    2 * sizeof(*ips), M_NOWAIT);
650 				if (resp == NULL) {
651 					error = ENOMEM;
652 					break;
653 				}
654 				ips = (struct in_addr *) resp->data;
655 				ips[0] = ((struct sockaddr_in *)
656 						ifa->ifa_addr)->sin_addr;
657 				ips[1] = ((struct sockaddr_in *)
658 						ifa->ifa_netmask)->sin_addr;
659 				break;
660 			}
661 
662 			/* No IP addresses on this interface? */
663 			if (ifa == NULL)
664 				error = EADDRNOTAVAIL;
665 			break;
666 		    }
667 		default:
668 			error = EINVAL;
669 			break;
670 		}
671 		break;
672 	default:
673 		error = EINVAL;
674 		break;
675 	}
676 	if (rptr)
677 		*rptr = resp;
678 	else if (resp)
679 		FREE(resp, M_NETGRAPH);
680 	FREE(msg, M_NETGRAPH);
681 	return (error);
682 }
683 
684 /*
685  * Recive data from a hook. Pass the packet to the correct input routine.
686  */
687 static int
688 ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
689 {
690 	const priv_p priv = hook->node->private;
691 	const iffam_p iffam = get_iffam_from_hook(priv, hook);
692 	struct ifnet *const ifp = priv->ifp;
693 	int s, error = 0;
694 
695 	/* Sanity checks */
696 #ifdef DIAGNOSTIC
697 	if (iffam == NULL)
698 		panic(__FUNCTION__);
699 	if ((m->m_flags & M_PKTHDR) == 0)
700 		panic(__FUNCTION__);
701 #endif
702 	if (m == NULL)
703 		return (EINVAL);
704 	if ((ifp->if_flags & IFF_UP) == 0) {
705 		NG_FREE_DATA(m, meta);
706 		return (ENETDOWN);
707 	}
708 
709 	/* Update interface stats */
710 	ifp->if_ipackets++;
711 	ifp->if_ibytes += m->m_pkthdr.len;
712 
713 	/* Note receiving interface */
714 	m->m_pkthdr.rcvif = ifp;
715 
716 #if NBPFILTER > 0
717 	/* Berkeley packet filter */
718 	ng_iface_bpftap(ifp, m, iffam->af);
719 #endif
720 
721 	/* Ignore any meta-data */
722 	NG_FREE_META(meta);
723 
724 	/* Send packet, either by NETISR or use a direct input function */
725 	switch (iffam->netisr) {
726 	case NETISR_NONE:
727 		(*iffam->u.input)(m);
728 		break;
729 	default:
730 		s = splimp();
731 		schednetisr(iffam->netisr);
732 		if (IF_QFULL(iffam->u.inq)) {
733 			IF_DROP(iffam->u.inq);
734 			m_freem(m);
735 			error = ENOBUFS;
736 		} else
737 			IF_ENQUEUE(iffam->u.inq, m);
738 		splx(s);
739 		break;
740 	}
741 
742 	/* Done */
743 	return (error);
744 }
745 
746 /*
747  * Because the BSD networking code doesn't support the removal of
748  * networking interfaces, iface nodes (once created) are persistent.
749  * So this method breaks all connections and marks the interface
750  * down, but does not remove the node.
751  */
752 static int
753 ng_iface_rmnode(node_p node)
754 {
755 	const priv_p priv = node->private;
756 	struct ifnet *const ifp = priv->ifp;
757 
758 	ng_cutlinks(node);
759 	node->flags &= ~NG_INVALID;
760 	ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_OACTIVE);
761 	return (0);
762 }
763 
764 /*
765  * Hook disconnection
766  */
767 static int
768 ng_iface_disconnect(hook_p hook)
769 {
770 	const priv_p priv = hook->node->private;
771 	const iffam_p iffam = get_iffam_from_hook(priv, hook);
772 
773 	if (iffam == NULL)
774 		panic(__FUNCTION__);
775 	*get_hook_from_iffam(priv, iffam) = NULL;
776 	return (0);
777 }
778 
779