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