ng_iface.c revision 129823
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 129823 2004-05-29 00:51:19Z julian $
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	{
190	  NGM_IFACE_COOKIE,
191	  NGM_IFACE_GET_IFINDEX,
192	  "getifindex",
193	  NULL,
194	  &ng_parse_uint32_type
195	},
196	{ 0 }
197};
198
199/* Node type descriptor */
200static struct ng_type typestruct = {
201	.version =	NG_ABI_VERSION,
202	.name =		NG_IFACE_NODE_TYPE,
203	.constructor =	ng_iface_constructor,
204	.rcvmsg =	ng_iface_rcvmsg,
205	.shutdown =	ng_iface_shutdown,
206	.newhook =	ng_iface_newhook,
207	.rcvdata =	ng_iface_rcvdata,
208	.disconnect =	ng_iface_disconnect,
209	.cmdlist =	ng_iface_cmds,
210};
211NETGRAPH_INIT(iface, &typestruct);
212
213/* We keep a bitmap indicating which unit numbers are free.
214   One means the unit number is free, zero means it's taken. */
215static int	*ng_iface_units = NULL;
216static int	ng_iface_units_len = 0;
217static int	ng_units_in_use = 0;
218
219#define UNITS_BITSPERWORD	(sizeof(*ng_iface_units) * NBBY)
220
221/************************************************************************
222			HELPER STUFF
223 ************************************************************************/
224
225/*
226 * Get the family descriptor from the family ID
227 */
228static __inline__ iffam_p
229get_iffam_from_af(sa_family_t family)
230{
231	iffam_p iffam;
232	int k;
233
234	for (k = 0; k < NUM_FAMILIES; k++) {
235		iffam = &gFamilies[k];
236		if (iffam->family == family)
237			return (iffam);
238	}
239	return (NULL);
240}
241
242/*
243 * Get the family descriptor from the hook
244 */
245static __inline__ iffam_p
246get_iffam_from_hook(priv_p priv, hook_p hook)
247{
248	int k;
249
250	for (k = 0; k < NUM_FAMILIES; k++)
251		if (priv->hooks[k] == hook)
252			return (&gFamilies[k]);
253	return (NULL);
254}
255
256/*
257 * Get the hook from the iffam descriptor
258 */
259
260static __inline__ hook_p *
261get_hook_from_iffam(priv_p priv, iffam_p iffam)
262{
263	return (&priv->hooks[iffam - gFamilies]);
264}
265
266/*
267 * Get the iffam descriptor from the name
268 */
269static __inline__ iffam_p
270get_iffam_from_name(const char *name)
271{
272	iffam_p iffam;
273	int k;
274
275	for (k = 0; k < NUM_FAMILIES; k++) {
276		iffam = &gFamilies[k];
277		if (!strcmp(iffam->hookname, name))
278			return (iffam);
279	}
280	return (NULL);
281}
282
283/*
284 * Find the first free unit number for a new interface.
285 * Increase the size of the unit bitmap as necessary.
286 */
287static __inline__ int
288ng_iface_get_unit(int *unit)
289{
290	int index, bit;
291
292	for (index = 0; index < ng_iface_units_len
293	    && ng_iface_units[index] == 0; index++);
294	if (index == ng_iface_units_len) {		/* extend array */
295		int i, *newarray, newlen;
296
297		newlen = (2 * ng_iface_units_len) + 4;
298		MALLOC(newarray, int *, newlen * sizeof(*ng_iface_units),
299		    M_NETGRAPH_IFACE, M_NOWAIT);
300		if (newarray == NULL)
301			return (ENOMEM);
302		bcopy(ng_iface_units, newarray,
303		    ng_iface_units_len * sizeof(*ng_iface_units));
304		for (i = ng_iface_units_len; i < newlen; i++)
305			newarray[i] = ~0;
306		if (ng_iface_units != NULL)
307			FREE(ng_iface_units, M_NETGRAPH_IFACE);
308		ng_iface_units = newarray;
309		ng_iface_units_len = newlen;
310	}
311	bit = ffs(ng_iface_units[index]) - 1;
312	KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1,
313	    ("%s: word=%d bit=%d", __func__, ng_iface_units[index], bit));
314	ng_iface_units[index] &= ~(1 << bit);
315	*unit = (index * UNITS_BITSPERWORD) + bit;
316	ng_units_in_use++;
317	return (0);
318}
319
320/*
321 * Free a no longer needed unit number.
322 */
323static __inline__ void
324ng_iface_free_unit(int unit)
325{
326	int index, bit;
327
328	index = unit / UNITS_BITSPERWORD;
329	bit = unit % UNITS_BITSPERWORD;
330	KASSERT(index < ng_iface_units_len,
331	    ("%s: unit=%d len=%d", __func__, unit, ng_iface_units_len));
332	KASSERT((ng_iface_units[index] & (1 << bit)) == 0,
333	    ("%s: unit=%d is free", __func__, unit));
334	ng_iface_units[index] |= (1 << bit);
335	/*
336	 * XXX We could think about reducing the size of ng_iface_units[]
337	 * XXX here if the last portion is all ones
338	 * XXX At least free it if no more units.
339	 * Needed if we are to eventually be able to unload.
340	 */
341	ng_units_in_use--;
342	if (ng_units_in_use == 0) { /* XXX make SMP safe */
343		FREE(ng_iface_units, M_NETGRAPH_IFACE);
344		ng_iface_units_len = 0;
345		ng_iface_units = NULL;
346	}
347}
348
349/************************************************************************
350			INTERFACE STUFF
351 ************************************************************************/
352
353/*
354 * Process an ioctl for the virtual interface
355 */
356static int
357ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
358{
359	struct ifreq *const ifr = (struct ifreq *) data;
360	int s, error = 0;
361
362#ifdef DEBUG
363	ng_iface_print_ioctl(ifp, command, data);
364#endif
365	s = splimp();
366	switch (command) {
367
368	/* These two are mostly handled at a higher layer */
369	case SIOCSIFADDR:
370		ifp->if_flags |= (IFF_UP | IFF_RUNNING);
371		ifp->if_flags &= ~(IFF_OACTIVE);
372		break;
373	case SIOCGIFADDR:
374		break;
375
376	/* Set flags */
377	case SIOCSIFFLAGS:
378		/*
379		 * If the interface is marked up and stopped, then start it.
380		 * If it is marked down and running, then stop it.
381		 */
382		if (ifr->ifr_flags & IFF_UP) {
383			if (!(ifp->if_flags & IFF_RUNNING)) {
384				ifp->if_flags &= ~(IFF_OACTIVE);
385				ifp->if_flags |= IFF_RUNNING;
386			}
387		} else {
388			if (ifp->if_flags & IFF_RUNNING)
389				ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
390		}
391		break;
392
393	/* Set the interface MTU */
394	case SIOCSIFMTU:
395		if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
396		    || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
397			error = EINVAL;
398		else
399			ifp->if_mtu = ifr->ifr_mtu;
400		break;
401
402	/* Stuff that's not supported */
403	case SIOCADDMULTI:
404	case SIOCDELMULTI:
405		error = 0;
406		break;
407	case SIOCSIFPHYS:
408		error = EOPNOTSUPP;
409		break;
410
411	default:
412		error = EINVAL;
413		break;
414	}
415	(void) splx(s);
416	return (error);
417}
418
419/*
420 * This routine is called to deliver a packet out the interface.
421 * We simply look at the address family and relay the packet to
422 * the corresponding hook, if it exists and is connected.
423 */
424
425static int
426ng_iface_output(struct ifnet *ifp, struct mbuf *m,
427		struct sockaddr *dst, struct rtentry *rt0)
428{
429	const priv_p priv = (priv_p) ifp->if_softc;
430	const iffam_p iffam = get_iffam_from_af(dst->sa_family);
431	meta_p meta = NULL;
432	int len, error = 0;
433
434	/* Check interface flags */
435	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
436		m_freem(m);
437		return (ENETDOWN);
438	}
439
440	/* BPF writes need to be handled specially */
441	if (dst->sa_family == AF_UNSPEC) {
442		if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
443			return (ENOBUFS);
444		dst->sa_family = (sa_family_t)*mtod(m, int32_t *);
445		m->m_data += 4;
446		m->m_len -= 4;
447		m->m_pkthdr.len -= 4;
448	}
449
450	/* Berkeley packet filter */
451	ng_iface_bpftap(ifp, m, dst->sa_family);
452
453	/* Check address family to determine hook (if known) */
454	if (iffam == NULL) {
455		m_freem(m);
456		log(LOG_WARNING, "%s: can't handle af%d\n",
457		       ifp->if_xname, (int)dst->sa_family);
458		return (EAFNOSUPPORT);
459	}
460
461	/* Copy length before the mbuf gets invalidated */
462	len = m->m_pkthdr.len;
463
464	/* Send packet; if hook is not connected, mbuf will get freed. */
465	NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta);
466
467	/* Update stats */
468	if (error == 0) {
469		ifp->if_obytes += len;
470		ifp->if_opackets++;
471	}
472	return (error);
473}
474
475/*
476 * This routine should never be called
477 */
478
479static void
480ng_iface_start(struct ifnet *ifp)
481{
482	if_printf(ifp, "%s called?", __func__);
483}
484
485/*
486 * Flash a packet by the BPF (requires prepending 4 byte AF header)
487 * Note the phoney mbuf; this is OK because BPF treats it read-only.
488 */
489static void
490ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family)
491{
492	KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__));
493	if (ifp->if_bpf != NULL) {
494		int32_t family4 = (int32_t)family;
495		bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m);
496	}
497}
498
499#ifdef DEBUG
500/*
501 * Display an ioctl to the virtual interface
502 */
503
504static void
505ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
506{
507	char   *str;
508
509	switch (command & IOC_DIRMASK) {
510	case IOC_VOID:
511		str = "IO";
512		break;
513	case IOC_OUT:
514		str = "IOR";
515		break;
516	case IOC_IN:
517		str = "IOW";
518		break;
519	case IOC_INOUT:
520		str = "IORW";
521		break;
522	default:
523		str = "IO??";
524	}
525	log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
526	       ifp->if_xname,
527	       str,
528	       IOCGROUP(command),
529	       command & 0xff,
530	       IOCPARM_LEN(command));
531}
532#endif /* DEBUG */
533
534/************************************************************************
535			NETGRAPH NODE STUFF
536 ************************************************************************/
537
538/*
539 * Constructor for a node
540 */
541static int
542ng_iface_constructor(node_p node)
543{
544	char ifname[NG_IFACE_IFACE_NAME_MAX + 1];
545	struct ifnet *ifp;
546	priv_p priv;
547	int error = 0;
548
549	/* Allocate node and interface private structures */
550	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_IFACE, M_NOWAIT|M_ZERO);
551	if (priv == NULL)
552		return (ENOMEM);
553	MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH_IFACE, M_NOWAIT|M_ZERO);
554	if (ifp == NULL) {
555		FREE(priv, M_NETGRAPH_IFACE);
556		return (ENOMEM);
557	}
558
559	/* Link them together */
560	ifp->if_softc = priv;
561	priv->ifp = ifp;
562
563	/* Get an interface unit number */
564	if ((error = ng_iface_get_unit(&priv->unit)) != 0) {
565		FREE(ifp, M_NETGRAPH_IFACE);
566		FREE(priv, M_NETGRAPH_IFACE);
567		return (error);
568	}
569
570	/* Link together node and private info */
571	NG_NODE_SET_PRIVATE(node, priv);
572	priv->node = node;
573
574	/* Initialize interface structure */
575	if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit);
576	ifp->if_output = ng_iface_output;
577	ifp->if_start = ng_iface_start;
578	ifp->if_ioctl = ng_iface_ioctl;
579	ifp->if_watchdog = NULL;
580	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
581	ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
582	ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST);
583	ifp->if_type = IFT_PROPVIRTUAL;		/* XXX */
584	ifp->if_addrlen = 0;			/* XXX */
585	ifp->if_hdrlen = 0;			/* XXX */
586	ifp->if_baudrate = 64000;		/* XXX */
587	TAILQ_INIT(&ifp->if_addrhead);
588
589	/* Give this node the same name as the interface (if possible) */
590	bzero(ifname, sizeof(ifname));
591	strlcpy(ifname, ifp->if_xname, sizeof(ifname));
592	if (ng_name_node(node, ifname) != 0)
593		log(LOG_WARNING, "%s: can't acquire netgraph name\n", ifname);
594
595	/* Attach the interface */
596	if_attach(ifp);
597	bpfattach(ifp, DLT_NULL, sizeof(u_int));
598
599	/* Done */
600	return (0);
601}
602
603/*
604 * Give our ok for a hook to be added
605 */
606static int
607ng_iface_newhook(node_p node, hook_p hook, const char *name)
608{
609	const iffam_p iffam = get_iffam_from_name(name);
610	hook_p *hookptr;
611
612	if (iffam == NULL)
613		return (EPFNOSUPPORT);
614	hookptr = get_hook_from_iffam(NG_NODE_PRIVATE(node), iffam);
615	if (*hookptr != NULL)
616		return (EISCONN);
617	*hookptr = hook;
618	return (0);
619}
620
621/*
622 * Receive a control message
623 */
624static int
625ng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook)
626{
627	const priv_p priv = NG_NODE_PRIVATE(node);
628	struct ifnet *const ifp = priv->ifp;
629	struct ng_mesg *resp = NULL;
630	int error = 0;
631	struct ng_mesg *msg;
632
633	NGI_GET_MSG(item, msg);
634	switch (msg->header.typecookie) {
635	case NGM_IFACE_COOKIE:
636		switch (msg->header.cmd) {
637		case NGM_IFACE_GET_IFNAME:
638		    {
639			struct ng_iface_ifname *arg;
640
641			NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
642			if (resp == NULL) {
643				error = ENOMEM;
644				break;
645			}
646			arg = (struct ng_iface_ifname *)resp->data;
647			strlcpy(arg->ngif_name, ifp->if_xname,
648			    sizeof(arg->ngif_name));
649			break;
650		    }
651
652		case NGM_IFACE_POINT2POINT:
653		case NGM_IFACE_BROADCAST:
654		    {
655
656			/* Deny request if interface is UP */
657			if ((ifp->if_flags & IFF_UP) != 0)
658				return (EBUSY);
659
660			/* Change flags */
661			switch (msg->header.cmd) {
662			case NGM_IFACE_POINT2POINT:
663				ifp->if_flags |= IFF_POINTOPOINT;
664				ifp->if_flags &= ~IFF_BROADCAST;
665				break;
666			case NGM_IFACE_BROADCAST:
667				ifp->if_flags &= ~IFF_POINTOPOINT;
668				ifp->if_flags |= IFF_BROADCAST;
669				break;
670			}
671			break;
672		    }
673
674		case NGM_IFACE_GET_IFINDEX:
675			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
676			if (resp == NULL) {
677				error = ENOMEM;
678				break;
679			}
680			*((uint32_t *)resp->data) = priv->ifp->if_index;
681			break;
682
683		default:
684			error = EINVAL;
685			break;
686		}
687		break;
688	case NGM_CISCO_COOKIE:
689		switch (msg->header.cmd) {
690		case NGM_CISCO_GET_IPADDR:	/* we understand this too */
691		    {
692			struct ifaddr *ifa;
693
694			/* Return the first configured IP address */
695			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
696				struct ng_cisco_ipaddr *ips;
697
698				if (ifa->ifa_addr->sa_family != AF_INET)
699					continue;
700				NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT);
701				if (resp == NULL) {
702					error = ENOMEM;
703					break;
704				}
705				ips = (struct ng_cisco_ipaddr *)resp->data;
706				ips->ipaddr = ((struct sockaddr_in *)
707						ifa->ifa_addr)->sin_addr;
708				ips->netmask = ((struct sockaddr_in *)
709						ifa->ifa_netmask)->sin_addr;
710				break;
711			}
712
713			/* No IP addresses on this interface? */
714			if (ifa == NULL)
715				error = EADDRNOTAVAIL;
716			break;
717		    }
718		default:
719			error = EINVAL;
720			break;
721		}
722		break;
723	default:
724		error = EINVAL;
725		break;
726	}
727	NG_RESPOND_MSG(error, node, item, resp);
728	NG_FREE_MSG(msg);
729	return (error);
730}
731
732/*
733 * Recive data from a hook. Pass the packet to the correct input routine.
734 */
735static int
736ng_iface_rcvdata(hook_p hook, item_p item)
737{
738	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
739	const iffam_p iffam = get_iffam_from_hook(priv, hook);
740	struct ifnet *const ifp = priv->ifp;
741	struct mbuf *m;
742	int isr;
743
744	NGI_GET_M(item, m);
745	NG_FREE_ITEM(item);
746	/* Sanity checks */
747	KASSERT(iffam != NULL, ("%s: iffam", __func__));
748	M_ASSERTPKTHDR(m);
749	if (m == NULL)
750		return (EINVAL);
751	if ((ifp->if_flags & IFF_UP) == 0) {
752		NG_FREE_M(m);
753		return (ENETDOWN);
754	}
755
756	/* Update interface stats */
757	ifp->if_ipackets++;
758	ifp->if_ibytes += m->m_pkthdr.len;
759
760	/* Note receiving interface */
761	m->m_pkthdr.rcvif = ifp;
762
763	/* Berkeley packet filter */
764	ng_iface_bpftap(ifp, m, iffam->family);
765
766	/* Send packet */
767	switch (iffam->family) {
768#ifdef INET
769	case AF_INET:
770		isr = NETISR_IP;
771		break;
772#endif
773#ifdef INET6
774	case AF_INET6:
775		isr = NETISR_IPV6;
776		break;
777#endif
778#ifdef IPX
779	case AF_IPX:
780		isr = NETISR_IPX;
781		break;
782#endif
783#ifdef NETATALK
784	case AF_APPLETALK:
785		isr = NETISR_ATALK2;
786		break;
787#endif
788	default:
789		m_freem(m);
790		return (EAFNOSUPPORT);
791	}
792	/* First chunk of an mbuf contains good junk */
793	if (harvest.point_to_point)
794		random_harvest(m, 16, 3, 0, RANDOM_NET);
795	netisr_dispatch(isr, m);
796	return (0);
797}
798
799/*
800 * Shutdown and remove the node and its associated interface.
801 */
802static int
803ng_iface_shutdown(node_p node)
804{
805	const priv_p priv = NG_NODE_PRIVATE(node);
806
807	bpfdetach(priv->ifp);
808	if_detach(priv->ifp);
809	FREE(priv->ifp, M_NETGRAPH_IFACE);
810	priv->ifp = NULL;
811	ng_iface_free_unit(priv->unit);
812	FREE(priv, M_NETGRAPH_IFACE);
813	NG_NODE_SET_PRIVATE(node, NULL);
814	NG_NODE_UNREF(node);
815	return (0);
816}
817
818/*
819 * Hook disconnection. Note that we do *not* shutdown when all
820 * hooks have been disconnected.
821 */
822static int
823ng_iface_disconnect(hook_p hook)
824{
825	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
826	const iffam_p iffam = get_iffam_from_hook(priv, hook);
827
828	if (iffam == NULL)
829		panic(__func__);
830	*get_hook_from_iffam(priv, iffam) = NULL;
831	return (0);
832}
833
834