ng_iface.c revision 52419
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: head/sys/netgraph/ng_iface.c 52419 1999-10-21 09:06:11Z julian $
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 */
114struct 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};
124typedef 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. */
132const 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 */
169struct 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};
175typedef struct private *priv_p;
176
177/* Interface methods */
178static void	ng_iface_start(struct ifnet *ifp);
179static int	ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
180static int	ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
181		struct sockaddr *dst, struct rtentry *rt0);
182#if NBPFILTER > 0
183static void	ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af);
184#endif
185#ifdef DEBUG
186static void	ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
187#endif
188
189/* Netgraph methods */
190static int	ng_iface_constructor(node_p *nodep);
191static int	ng_iface_rcvmsg(node_p node, struct ng_mesg *msg,
192		    const char *retaddr, struct ng_mesg **resp);
193static int	ng_iface_rmnode(node_p node);
194static int	ng_iface_newhook(node_p node, hook_p hook, const char *name);
195static int	ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta);
196static int	ng_iface_disconnect(hook_p hook);
197
198/* Helper stuff */
199static iffam_p	get_iffam_from_af(int af);
200static iffam_p	get_iffam_from_hook(priv_p priv, hook_p hook);
201static iffam_p	get_iffam_from_name(const char *name);
202static hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
203
204/* Node type descriptor */
205static 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};
219NETGRAPH_INIT(iface, &typestruct);
220
221static char ng_iface_ifname[] = NG_IFACE_IFACE_NAME;
222static int ng_iface_next_unit;
223
224/************************************************************************
225			HELPER STUFF
226 ************************************************************************/
227
228/*
229 * Get the family descriptor from the family ID
230 */
231static __inline__ iffam_p
232get_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 */
248static __inline__ iffam_p
249get_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
263static __inline__ hook_p *
264get_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 */
272static __inline__ iffam_p
273get_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 */
293static int
294ng_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
360static int
361ng_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
406static void
407ng_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 */
417static void
418ng_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
442static void
443ng_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 */
479static int
480ng_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 */
550static int
551ng_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 */
568static int
569ng_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 */
687static int
688ng_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 */
752static int
753ng_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 */
767static int
768ng_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