152419Sjulian/*
252419Sjulian * ng_iface.c
3139823Simp */
4139823Simp
5139823Simp/*-
652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc.
752419Sjulian * All rights reserved.
852419Sjulian *
952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and
1052419Sjulian * redistribution of this software, in source or object code forms, with or
1152419Sjulian * without modifications are expressly permitted by Whistle Communications;
1252419Sjulian * provided, however, that:
1352419Sjulian * 1. Any and all reproductions of the source or object code must include the
1452419Sjulian *    copyright notice above and the following disclaimer of warranties; and
1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle
1652419Sjulian *    Communications, Inc. trademarks, including the mark "WHISTLE
1752419Sjulian *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1852419Sjulian *    such appears in the above copyright notice or in the software.
1952419Sjulian *
2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3652419Sjulian * OF SUCH DAMAGE.
3752419Sjulian *
3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org>
3952419Sjulian *
4052419Sjulian * $FreeBSD$
4152752Sjulian * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $
4252419Sjulian */
4352419Sjulian
4452419Sjulian/*
4552419Sjulian * This node is also a system networking interface. It has
4652419Sjulian * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
4752419Sjulian * are simply relayed between the interface and the hooks.
4852419Sjulian *
4958015Sarchie * Interfaces are named ng0, ng1, etc.  New nodes take the
5058015Sarchie * first available interface name.
5152419Sjulian *
5252419Sjulian * This node also includes Berkeley packet filter support.
5352419Sjulian */
5452419Sjulian
55111997Sjlemon#include "opt_atalk.h"
56111997Sjlemon#include "opt_inet.h"
57111997Sjlemon#include "opt_inet6.h"
58111997Sjlemon#include "opt_ipx.h"
59111997Sjlemon
6052419Sjulian#include <sys/param.h>
6152419Sjulian#include <sys/systm.h>
6252419Sjulian#include <sys/errno.h>
6352419Sjulian#include <sys/kernel.h>
6452419Sjulian#include <sys/malloc.h>
6552419Sjulian#include <sys/mbuf.h>
6652419Sjulian#include <sys/errno.h>
67196019Srwatson#include <sys/proc.h>
68111888Sjlemon#include <sys/random.h>
6952419Sjulian#include <sys/sockio.h>
7052419Sjulian#include <sys/socket.h>
7152419Sjulian#include <sys/syslog.h>
7258015Sarchie#include <sys/libkern.h>
7352419Sjulian
7452419Sjulian#include <net/if.h>
7552419Sjulian#include <net/if_types.h>
7658015Sarchie#include <net/bpf.h>
77111888Sjlemon#include <net/netisr.h>
78191148Skmacy#include <net/route.h>
79195837Srwatson#include <net/vnet.h>
8052419Sjulian
8153913Sarchie#include <netinet/in.h>
8253913Sarchie
8352419Sjulian#include <netgraph/ng_message.h>
8452419Sjulian#include <netgraph/netgraph.h>
8558015Sarchie#include <netgraph/ng_parse.h>
8652419Sjulian#include <netgraph/ng_iface.h>
8752419Sjulian#include <netgraph/ng_cisco.h>
8852419Sjulian
8970870Sjulian#ifdef NG_SEPARATE_MALLOC
90227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_IFACE, "netgraph_iface", "netgraph iface node");
9170870Sjulian#else
9270870Sjulian#define M_NETGRAPH_IFACE M_NETGRAPH
9370870Sjulian#endif
9470870Sjulian
9552419Sjulian/* This struct describes one address family */
9652419Sjulianstruct iffam {
9758015Sarchie	sa_family_t	family;		/* Address family */
9858015Sarchie	const char	*hookname;	/* Name for hook */
9952419Sjulian};
10052419Sjuliantypedef const struct iffam *iffam_p;
10152419Sjulian
10258015Sarchie/* List of address families supported by our interface */
10352419Sjulianconst static struct iffam gFamilies[] = {
10458015Sarchie	{ AF_INET,	NG_IFACE_HOOK_INET	},
10558015Sarchie	{ AF_INET6,	NG_IFACE_HOOK_INET6	},
10658015Sarchie	{ AF_APPLETALK,	NG_IFACE_HOOK_ATALK	},
10758015Sarchie	{ AF_IPX,	NG_IFACE_HOOK_IPX	},
10858015Sarchie	{ AF_ATM,	NG_IFACE_HOOK_ATM	},
10958015Sarchie	{ AF_NATM,	NG_IFACE_HOOK_NATM	},
11052419Sjulian};
11152419Sjulian#define NUM_FAMILIES		(sizeof(gFamilies) / sizeof(*gFamilies))
11252419Sjulian
11352419Sjulian/* Node private data */
11453393Sarchiestruct ng_iface_private {
11558015Sarchie	struct	ifnet *ifp;		/* Our interface */
11658015Sarchie	int	unit;			/* Interface unit number */
11752419Sjulian	node_p	node;			/* Our netgraph node */
11852419Sjulian	hook_p	hooks[NUM_FAMILIES];	/* Hook for each address family */
11952419Sjulian};
12053393Sarchietypedef struct ng_iface_private *priv_p;
12152419Sjulian
12252419Sjulian/* Interface methods */
12352419Sjulianstatic void	ng_iface_start(struct ifnet *ifp);
12452419Sjulianstatic int	ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
12552419Sjulianstatic int	ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
126249925Sglebius    			const struct sockaddr *dst, struct route *ro);
12758015Sarchiestatic void	ng_iface_bpftap(struct ifnet *ifp,
12858015Sarchie			struct mbuf *m, sa_family_t family);
129151203Sglebiusstatic int	ng_iface_send(struct ifnet *ifp, struct mbuf *m,
130151203Sglebius			sa_family_t sa);
13152419Sjulian#ifdef DEBUG
13252419Sjulianstatic void	ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
13352419Sjulian#endif
13452419Sjulian
13552419Sjulian/* Netgraph methods */
136141341Srustatic int		ng_iface_mod_event(module_t, int, void *);
13752752Sjulianstatic ng_constructor_t	ng_iface_constructor;
13852752Sjulianstatic ng_rcvmsg_t	ng_iface_rcvmsg;
13970700Sjulianstatic ng_shutdown_t	ng_iface_shutdown;
14052752Sjulianstatic ng_newhook_t	ng_iface_newhook;
14152752Sjulianstatic ng_rcvdata_t	ng_iface_rcvdata;
14252752Sjulianstatic ng_disconnect_t	ng_iface_disconnect;
14352419Sjulian
14452419Sjulian/* Helper stuff */
14558015Sarchiestatic iffam_p	get_iffam_from_af(sa_family_t family);
14652419Sjulianstatic iffam_p	get_iffam_from_hook(priv_p priv, hook_p hook);
14752419Sjulianstatic iffam_p	get_iffam_from_name(const char *name);
14852419Sjulianstatic hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
14952419Sjulian
15058015Sarchie/* Parse type for struct ng_cisco_ipaddr */
15197685Sarchiestatic const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[]
15297685Sarchie	= NG_CISCO_IPADDR_TYPE_INFO;
15358015Sarchiestatic const struct ng_parse_type ng_cisco_ipaddr_type = {
15458015Sarchie	&ng_parse_struct_type,
15597685Sarchie	&ng_cisco_ipaddr_type_fields
15658015Sarchie};
15758015Sarchie
15858015Sarchie/* List of commands and how to convert arguments to/from ASCII */
15958015Sarchiestatic const struct ng_cmdlist ng_iface_cmds[] = {
16058015Sarchie	{
16158015Sarchie	  NGM_IFACE_COOKIE,
16258015Sarchie	  NGM_IFACE_GET_IFNAME,
16358015Sarchie	  "getifname",
16458015Sarchie	  NULL,
165141197Sru	  &ng_parse_string_type
16658015Sarchie	},
16758015Sarchie	{
16858015Sarchie	  NGM_IFACE_COOKIE,
16958015Sarchie	  NGM_IFACE_POINT2POINT,
17058015Sarchie	  "point2point",
17158015Sarchie	  NULL,
17258015Sarchie	  NULL
17358015Sarchie	},
17458015Sarchie	{
17558015Sarchie	  NGM_IFACE_COOKIE,
17658015Sarchie	  NGM_IFACE_BROADCAST,
17758015Sarchie	  "broadcast",
17858015Sarchie	  NULL,
17958015Sarchie	  NULL
18058015Sarchie	},
18158015Sarchie	{
18258015Sarchie	  NGM_CISCO_COOKIE,
18358015Sarchie	  NGM_CISCO_GET_IPADDR,
18458015Sarchie	  "getipaddr",
18558015Sarchie	  NULL,
18658015Sarchie	  &ng_cisco_ipaddr_type
18758015Sarchie	},
188126730Sru	{
189126730Sru	  NGM_IFACE_COOKIE,
190126730Sru	  NGM_IFACE_GET_IFINDEX,
191126730Sru	  "getifindex",
192126730Sru	  NULL,
193126730Sru	  &ng_parse_uint32_type
194126730Sru	},
19558015Sarchie	{ 0 }
19658015Sarchie};
19758015Sarchie
19852419Sjulian/* Node type descriptor */
19952419Sjulianstatic struct ng_type typestruct = {
200129823Sjulian	.version =	NG_ABI_VERSION,
201129823Sjulian	.name =		NG_IFACE_NODE_TYPE,
202141341Sru	.mod_event =	ng_iface_mod_event,
203129823Sjulian	.constructor =	ng_iface_constructor,
204129823Sjulian	.rcvmsg =	ng_iface_rcvmsg,
205129823Sjulian	.shutdown =	ng_iface_shutdown,
206129823Sjulian	.newhook =	ng_iface_newhook,
207129823Sjulian	.rcvdata =	ng_iface_rcvdata,
208129823Sjulian	.disconnect =	ng_iface_disconnect,
209129823Sjulian	.cmdlist =	ng_iface_cmds,
21052419Sjulian};
21152419SjulianNETGRAPH_INIT(iface, &typestruct);
21252419Sjulian
213215701Sdimstatic VNET_DEFINE(struct unrhdr *, ng_iface_unit);
214195727Srwatson#define	V_ng_iface_unit			VNET(ng_iface_unit)
21552419Sjulian
21652419Sjulian/************************************************************************
21752419Sjulian			HELPER STUFF
21852419Sjulian ************************************************************************/
21952419Sjulian
22052419Sjulian/*
22152419Sjulian * Get the family descriptor from the family ID
22252419Sjulian */
223131575Sstefanfstatic __inline iffam_p
22458015Sarchieget_iffam_from_af(sa_family_t family)
22552419Sjulian{
22652419Sjulian	iffam_p iffam;
22752419Sjulian	int k;
22852419Sjulian
22952419Sjulian	for (k = 0; k < NUM_FAMILIES; k++) {
23052419Sjulian		iffam = &gFamilies[k];
23158015Sarchie		if (iffam->family == family)
23252419Sjulian			return (iffam);
23352419Sjulian	}
23452419Sjulian	return (NULL);
23552419Sjulian}
23652419Sjulian
23752419Sjulian/*
23852419Sjulian * Get the family descriptor from the hook
23952419Sjulian */
240131575Sstefanfstatic __inline iffam_p
24152419Sjulianget_iffam_from_hook(priv_p priv, hook_p hook)
24252419Sjulian{
24352419Sjulian	int k;
24452419Sjulian
24552419Sjulian	for (k = 0; k < NUM_FAMILIES; k++)
24652419Sjulian		if (priv->hooks[k] == hook)
24752419Sjulian			return (&gFamilies[k]);
24852419Sjulian	return (NULL);
24952419Sjulian}
25052419Sjulian
25152419Sjulian/*
25252419Sjulian * Get the hook from the iffam descriptor
25352419Sjulian */
25452419Sjulian
255131575Sstefanfstatic __inline hook_p *
25652419Sjulianget_hook_from_iffam(priv_p priv, iffam_p iffam)
25752419Sjulian{
25852419Sjulian	return (&priv->hooks[iffam - gFamilies]);
25952419Sjulian}
26052419Sjulian
26152419Sjulian/*
26252419Sjulian * Get the iffam descriptor from the name
26352419Sjulian */
264131575Sstefanfstatic __inline iffam_p
26552419Sjulianget_iffam_from_name(const char *name)
26652419Sjulian{
26752419Sjulian	iffam_p iffam;
26852419Sjulian	int k;
26952419Sjulian
27052419Sjulian	for (k = 0; k < NUM_FAMILIES; k++) {
27152419Sjulian		iffam = &gFamilies[k];
27252419Sjulian		if (!strcmp(iffam->hookname, name))
27352419Sjulian			return (iffam);
27452419Sjulian	}
27552419Sjulian	return (NULL);
27652419Sjulian}
27752419Sjulian
27852419Sjulian/************************************************************************
27952419Sjulian			INTERFACE STUFF
28052419Sjulian ************************************************************************/
28152419Sjulian
28252419Sjulian/*
28352419Sjulian * Process an ioctl for the virtual interface
28452419Sjulian */
28552419Sjulianstatic int
28652419Sjulianng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
28752419Sjulian{
28852419Sjulian	struct ifreq *const ifr = (struct ifreq *) data;
289219781Sglebius	int error = 0;
29052419Sjulian
29152419Sjulian#ifdef DEBUG
29252419Sjulian	ng_iface_print_ioctl(ifp, command, data);
29352419Sjulian#endif
29452419Sjulian	switch (command) {
29552419Sjulian
29652419Sjulian	/* These two are mostly handled at a higher layer */
29752419Sjulian	case SIOCSIFADDR:
298148887Srwatson		ifp->if_flags |= IFF_UP;
299148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
300148887Srwatson		ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
30152419Sjulian		break;
30252419Sjulian	case SIOCGIFADDR:
30352419Sjulian		break;
30452419Sjulian
30552419Sjulian	/* Set flags */
30652419Sjulian	case SIOCSIFFLAGS:
30752419Sjulian		/*
30852419Sjulian		 * If the interface is marked up and stopped, then start it.
30952419Sjulian		 * If it is marked down and running, then stop it.
31052419Sjulian		 */
31152419Sjulian		if (ifr->ifr_flags & IFF_UP) {
312148887Srwatson			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
313148887Srwatson				ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
314148887Srwatson				ifp->if_drv_flags |= IFF_DRV_RUNNING;
31552419Sjulian			}
31652419Sjulian		} else {
317148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
318148887Srwatson				ifp->if_drv_flags &= ~(IFF_DRV_RUNNING |
319148887Srwatson				    IFF_DRV_OACTIVE);
32052419Sjulian		}
32152419Sjulian		break;
32252419Sjulian
32352419Sjulian	/* Set the interface MTU */
32452419Sjulian	case SIOCSIFMTU:
32552419Sjulian		if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
32652419Sjulian		    || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
32752419Sjulian			error = EINVAL;
32852419Sjulian		else
32952419Sjulian			ifp->if_mtu = ifr->ifr_mtu;
33052419Sjulian		break;
33152419Sjulian
33252419Sjulian	/* Stuff that's not supported */
33352419Sjulian	case SIOCADDMULTI:
33452419Sjulian	case SIOCDELMULTI:
33552975Sarchie		error = 0;
33652975Sarchie		break;
33752419Sjulian	case SIOCSIFPHYS:
33852419Sjulian		error = EOPNOTSUPP;
33952419Sjulian		break;
34052419Sjulian
34152419Sjulian	default:
34252419Sjulian		error = EINVAL;
34352419Sjulian		break;
34452419Sjulian	}
34552419Sjulian	return (error);
34652419Sjulian}
34752419Sjulian
34852419Sjulian/*
34952419Sjulian * This routine is called to deliver a packet out the interface.
35052419Sjulian * We simply look at the address family and relay the packet to
35152419Sjulian * the corresponding hook, if it exists and is connected.
35252419Sjulian */
35352419Sjulian
35452419Sjulianstatic int
35552419Sjulianng_iface_output(struct ifnet *ifp, struct mbuf *m,
356249925Sglebius	const struct sockaddr *dst, struct route *ro)
35752419Sjulian{
358187495Smav	struct m_tag *mtag;
359151203Sglebius	uint32_t af;
360151231Sglebius	int error;
36152419Sjulian
36252419Sjulian	/* Check interface flags */
363148887Srwatson	if (!((ifp->if_flags & IFF_UP) &&
364148887Srwatson	    (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
36552419Sjulian		m_freem(m);
36652419Sjulian		return (ENETDOWN);
36752419Sjulian	}
36852419Sjulian
369187495Smav	/* Protect from deadly infinite recursion. */
370195231Smav	mtag = NULL;
371195231Smav	while ((mtag = m_tag_locate(m, MTAG_NGIF, MTAG_NGIF_CALLED, mtag))) {
372187495Smav		if (*(struct ifnet **)(mtag + 1) == ifp) {
373187495Smav			log(LOG_NOTICE, "Loop detected on %s\n", ifp->if_xname);
374187495Smav			m_freem(m);
375187495Smav			return (EDEADLK);
376187495Smav		}
377187495Smav	}
378187495Smav	mtag = m_tag_alloc(MTAG_NGIF, MTAG_NGIF_CALLED, sizeof(struct ifnet *),
379187495Smav	    M_NOWAIT);
380187495Smav	if (mtag == NULL) {
381187495Smav		m_freem(m);
382187495Smav		return (ENOMEM);
383187495Smav	}
384187495Smav	*(struct ifnet **)(mtag + 1) = ifp;
385187495Smav	m_tag_prepend(m, mtag);
386187495Smav
387147611Sdwmalone	/* BPF writes need to be handled specially. */
388249925Sglebius	if (dst->sa_family == AF_UNSPEC)
389147611Sdwmalone		bcopy(dst->sa_data, &af, sizeof(af));
390249925Sglebius	else
391249925Sglebius		af = dst->sa_family;
39258015Sarchie
39352419Sjulian	/* Berkeley packet filter */
394249925Sglebius	ng_iface_bpftap(ifp, m, af);
39552419Sjulian
396151203Sglebius	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
397243882Sglebius		M_PREPEND(m, sizeof(sa_family_t), M_NOWAIT);
398151203Sglebius		if (m == NULL) {
399151231Sglebius			IFQ_LOCK(&ifp->if_snd);
400151231Sglebius			IFQ_INC_DROPS(&ifp->if_snd);
401151231Sglebius			IFQ_UNLOCK(&ifp->if_snd);
402151203Sglebius			ifp->if_oerrors++;
403151203Sglebius			return (ENOBUFS);
404151203Sglebius		}
405249925Sglebius		*(sa_family_t *)m->m_data = af;
406185164Skmacy		error = (ifp->if_transmit)(ifp, m);
407151203Sglebius	} else
408249925Sglebius		error = ng_iface_send(ifp, m, af);
40952419Sjulian
41052419Sjulian	return (error);
41152419Sjulian}
41252419Sjulian
41352419Sjulian/*
414151231Sglebius * Start method is used only when ALTQ is enabled.
41552419Sjulian */
41652419Sjulianstatic void
41752419Sjulianng_iface_start(struct ifnet *ifp)
41852419Sjulian{
419151203Sglebius	struct mbuf *m;
420151203Sglebius	sa_family_t sa;
421151203Sglebius
422151231Sglebius	KASSERT(ALTQ_IS_ENABLED(&ifp->if_snd), ("%s without ALTQ", __func__));
423151203Sglebius
424151231Sglebius	for(;;) {
425151203Sglebius		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
426151203Sglebius		if (m == NULL)
427151203Sglebius			break;
428151203Sglebius		sa = *mtod(m, sa_family_t *);
429151203Sglebius		m_adj(m, sizeof(sa_family_t));
430151203Sglebius		ng_iface_send(ifp, m, sa);
431151203Sglebius	}
43252419Sjulian}
43352419Sjulian
43452419Sjulian/*
43552419Sjulian * Flash a packet by the BPF (requires prepending 4 byte AF header)
43652419Sjulian * Note the phoney mbuf; this is OK because BPF treats it read-only.
43752419Sjulian */
43852419Sjulianstatic void
43958015Sarchieng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family)
44052419Sjulian{
44187599Sobrien	KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__));
442159183Ssam	if (bpf_peers_present(ifp->if_bpf)) {
443123922Ssam		int32_t family4 = (int32_t)family;
444123922Ssam		bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m);
44552419Sjulian	}
44652419Sjulian}
44752419Sjulian
448151203Sglebius/*
449151203Sglebius * This routine does actual delivery of the packet into the
450151203Sglebius * netgraph(4). It is called from ng_iface_start() and
451151231Sglebius * ng_iface_output().
452151203Sglebius */
453151203Sglebiusstatic int
454151203Sglebiusng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa)
455151203Sglebius{
456151203Sglebius	const priv_p priv = (priv_p) ifp->if_softc;
457151203Sglebius	const iffam_p iffam = get_iffam_from_af(sa);
458151231Sglebius	int error;
459151203Sglebius	int len;
460151203Sglebius
461151203Sglebius	/* Check address family to determine hook (if known) */
462151203Sglebius	if (iffam == NULL) {
463151203Sglebius		m_freem(m);
464151203Sglebius		log(LOG_WARNING, "%s: can't handle af%d\n", ifp->if_xname, sa);
465151203Sglebius		return (EAFNOSUPPORT);
466151203Sglebius	}
467151203Sglebius
468151203Sglebius	/* Copy length before the mbuf gets invalidated. */
469151203Sglebius	len = m->m_pkthdr.len;
470151203Sglebius
471194012Szec	/* Send packet. If hook is not connected, mbuf will get freed. */
472194012Szec	NG_OUTBOUND_THREAD_REF();
473151203Sglebius	NG_SEND_DATA_ONLY(error, *get_hook_from_iffam(priv, iffam), m);
474194012Szec	NG_OUTBOUND_THREAD_UNREF();
475151203Sglebius
476151203Sglebius	/* Update stats. */
477151203Sglebius	if (error == 0) {
478151203Sglebius		ifp->if_obytes += len;
479151203Sglebius		ifp->if_opackets++;
480151203Sglebius	}
481151203Sglebius
482151203Sglebius	return (error);
483151203Sglebius}
484151203Sglebius
48552419Sjulian#ifdef DEBUG
48652419Sjulian/*
48752419Sjulian * Display an ioctl to the virtual interface
48852419Sjulian */
48952419Sjulian
49052419Sjulianstatic void
49152419Sjulianng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
49252419Sjulian{
49352419Sjulian	char   *str;
49452419Sjulian
49552419Sjulian	switch (command & IOC_DIRMASK) {
49652419Sjulian	case IOC_VOID:
49752419Sjulian		str = "IO";
49852419Sjulian		break;
49952419Sjulian	case IOC_OUT:
50052419Sjulian		str = "IOR";
50152419Sjulian		break;
50252419Sjulian	case IOC_IN:
50352419Sjulian		str = "IOW";
50452419Sjulian		break;
50552419Sjulian	case IOC_INOUT:
50652419Sjulian		str = "IORW";
50752419Sjulian		break;
50852419Sjulian	default:
50952419Sjulian		str = "IO??";
51052419Sjulian	}
511121816Sbrooks	log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
512121816Sbrooks	       ifp->if_xname,
51352419Sjulian	       str,
51452419Sjulian	       IOCGROUP(command),
51552419Sjulian	       command & 0xff,
51652419Sjulian	       IOCPARM_LEN(command));
51752419Sjulian}
51852419Sjulian#endif /* DEBUG */
51952419Sjulian
52052419Sjulian/************************************************************************
52152419Sjulian			NETGRAPH NODE STUFF
52252419Sjulian ************************************************************************/
52352419Sjulian
52452419Sjulian/*
52552419Sjulian * Constructor for a node
52652419Sjulian */
52752419Sjulianstatic int
52870700Sjulianng_iface_constructor(node_p node)
52952419Sjulian{
53052419Sjulian	struct ifnet *ifp;
53152419Sjulian	priv_p priv;
53252419Sjulian
53352419Sjulian	/* Allocate node and interface private structures */
534220768Sglebius	priv = malloc(sizeof(*priv), M_NETGRAPH_IFACE, M_WAITOK | M_ZERO);
535147256Sbrooks	ifp = if_alloc(IFT_PROPVIRTUAL);
53652419Sjulian	if (ifp == NULL) {
537184205Sdes		free(priv, M_NETGRAPH_IFACE);
53852419Sjulian		return (ENOMEM);
53952419Sjulian	}
54052419Sjulian
54152419Sjulian	/* Link them together */
54252419Sjulian	ifp->if_softc = priv;
54352419Sjulian	priv->ifp = ifp;
54452419Sjulian
54558015Sarchie	/* Get an interface unit number */
546181803Sbz	priv->unit = alloc_unr(V_ng_iface_unit);
54758015Sarchie
54852419Sjulian	/* Link together node and private info */
54970784Sjulian	NG_NODE_SET_PRIVATE(node, priv);
55052419Sjulian	priv->node = node;
55152419Sjulian
55252419Sjulian	/* Initialize interface structure */
553121816Sbrooks	if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit);
55452419Sjulian	ifp->if_output = ng_iface_output;
55552419Sjulian	ifp->if_start = ng_iface_start;
55652419Sjulian	ifp->if_ioctl = ng_iface_ioctl;
55752419Sjulian	ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
55858015Sarchie	ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST);
55952419Sjulian	ifp->if_type = IFT_PROPVIRTUAL;		/* XXX */
56052419Sjulian	ifp->if_addrlen = 0;			/* XXX */
56152419Sjulian	ifp->if_hdrlen = 0;			/* XXX */
56252419Sjulian	ifp->if_baudrate = 64000;		/* XXX */
563207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
564207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
565151203Sglebius	IFQ_SET_READY(&ifp->if_snd);
56652419Sjulian
56752419Sjulian	/* Give this node the same name as the interface (if possible) */
568141197Sru	if (ng_name_node(node, ifp->if_xname) != 0)
569141197Sru		log(LOG_WARNING, "%s: can't acquire netgraph name\n",
570141197Sru		    ifp->if_xname);
57152419Sjulian
57252419Sjulian	/* Attach the interface */
57352419Sjulian	if_attach(ifp);
574147611Sdwmalone	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
57552419Sjulian
57652419Sjulian	/* Done */
57752419Sjulian	return (0);
57852419Sjulian}
57952419Sjulian
58052419Sjulian/*
58152419Sjulian * Give our ok for a hook to be added
58252419Sjulian */
58352419Sjulianstatic int
58452419Sjulianng_iface_newhook(node_p node, hook_p hook, const char *name)
58552419Sjulian{
58652419Sjulian	const iffam_p iffam = get_iffam_from_name(name);
58752419Sjulian	hook_p *hookptr;
58852419Sjulian
58952419Sjulian	if (iffam == NULL)
59052419Sjulian		return (EPFNOSUPPORT);
59170784Sjulian	hookptr = get_hook_from_iffam(NG_NODE_PRIVATE(node), iffam);
59252419Sjulian	if (*hookptr != NULL)
59352419Sjulian		return (EISCONN);
59452419Sjulian	*hookptr = hook;
595175847Smav	NG_HOOK_HI_STACK(hook);
596194012Szec	NG_HOOK_SET_TO_INBOUND(hook);
59752419Sjulian	return (0);
59852419Sjulian}
59952419Sjulian
60052419Sjulian/*
60152419Sjulian * Receive a control message
60252419Sjulian */
60352419Sjulianstatic int
60470700Sjulianng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook)
60552419Sjulian{
60670784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
60752419Sjulian	struct ifnet *const ifp = priv->ifp;
60852419Sjulian	struct ng_mesg *resp = NULL;
60952419Sjulian	int error = 0;
61070700Sjulian	struct ng_mesg *msg;
61152419Sjulian
61270700Sjulian	NGI_GET_MSG(item, msg);
61352419Sjulian	switch (msg->header.typecookie) {
61452419Sjulian	case NGM_IFACE_COOKIE:
61552419Sjulian		switch (msg->header.cmd) {
61652419Sjulian		case NGM_IFACE_GET_IFNAME:
617141197Sru			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
61852419Sjulian			if (resp == NULL) {
61952419Sjulian				error = ENOMEM;
62052419Sjulian				break;
62152419Sjulian			}
622141197Sru			strlcpy(resp->data, ifp->if_xname, IFNAMSIZ);
62352419Sjulian			break;
62452419Sjulian
62558015Sarchie		case NGM_IFACE_POINT2POINT:
62658015Sarchie		case NGM_IFACE_BROADCAST:
62752419Sjulian		    {
62852419Sjulian
62958015Sarchie			/* Deny request if interface is UP */
63058015Sarchie			if ((ifp->if_flags & IFF_UP) != 0)
63158015Sarchie				return (EBUSY);
63252419Sjulian
63358015Sarchie			/* Change flags */
63458015Sarchie			switch (msg->header.cmd) {
63558015Sarchie			case NGM_IFACE_POINT2POINT:
63658015Sarchie				ifp->if_flags |= IFF_POINTOPOINT;
63758015Sarchie				ifp->if_flags &= ~IFF_BROADCAST;
63852419Sjulian				break;
63958015Sarchie			case NGM_IFACE_BROADCAST:
64058015Sarchie				ifp->if_flags &= ~IFF_POINTOPOINT;
64158015Sarchie				ifp->if_flags |= IFF_BROADCAST;
64258015Sarchie				break;
64352419Sjulian			}
64452419Sjulian			break;
64552419Sjulian		    }
64652419Sjulian
647126730Sru		case NGM_IFACE_GET_IFINDEX:
648126730Sru			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
649126730Sru			if (resp == NULL) {
650126730Sru				error = ENOMEM;
651126730Sru				break;
652126730Sru			}
653126730Sru			*((uint32_t *)resp->data) = priv->ifp->if_index;
654126730Sru			break;
655126730Sru
65652419Sjulian		default:
65752419Sjulian			error = EINVAL;
65852419Sjulian			break;
65952419Sjulian		}
66052419Sjulian		break;
66152419Sjulian	case NGM_CISCO_COOKIE:
66252419Sjulian		switch (msg->header.cmd) {
66352419Sjulian		case NGM_CISCO_GET_IPADDR:	/* we understand this too */
66452419Sjulian		    {
66552419Sjulian			struct ifaddr *ifa;
66652419Sjulian
66752419Sjulian			/* Return the first configured IP address */
668195024Srwatson			if_addr_rlock(ifp);
66952419Sjulian			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
67058015Sarchie				struct ng_cisco_ipaddr *ips;
67152419Sjulian
67252419Sjulian				if (ifa->ifa_addr->sa_family != AF_INET)
67352419Sjulian					continue;
67458015Sarchie				NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT);
67552419Sjulian				if (resp == NULL) {
67652419Sjulian					error = ENOMEM;
67752419Sjulian					break;
67852419Sjulian				}
67958015Sarchie				ips = (struct ng_cisco_ipaddr *)resp->data;
68058015Sarchie				ips->ipaddr = ((struct sockaddr_in *)
68152419Sjulian						ifa->ifa_addr)->sin_addr;
68258015Sarchie				ips->netmask = ((struct sockaddr_in *)
68352419Sjulian						ifa->ifa_netmask)->sin_addr;
68452419Sjulian				break;
68552419Sjulian			}
686195024Srwatson			if_addr_runlock(ifp);
68752419Sjulian
68852419Sjulian			/* No IP addresses on this interface? */
68952419Sjulian			if (ifa == NULL)
69052419Sjulian				error = EADDRNOTAVAIL;
69152419Sjulian			break;
69252419Sjulian		    }
69352419Sjulian		default:
69452419Sjulian			error = EINVAL;
69552419Sjulian			break;
69652419Sjulian		}
69752419Sjulian		break;
698138011Sglebius	case NGM_FLOW_COOKIE:
699138011Sglebius		switch (msg->header.cmd) {
700138011Sglebius		case NGM_LINK_IS_UP:
701148887Srwatson			ifp->if_drv_flags |= IFF_DRV_RUNNING;
702138011Sglebius			break;
703138011Sglebius		case NGM_LINK_IS_DOWN:
704148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
705138011Sglebius			break;
706138011Sglebius		default:
707138011Sglebius			break;
708138011Sglebius		}
709138011Sglebius		break;
71052419Sjulian	default:
71152419Sjulian		error = EINVAL;
71252419Sjulian		break;
71352419Sjulian	}
71470700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
71570700Sjulian	NG_FREE_MSG(msg);
71652419Sjulian	return (error);
71752419Sjulian}
71852419Sjulian
71952419Sjulian/*
72052419Sjulian * Recive data from a hook. Pass the packet to the correct input routine.
72152419Sjulian */
72252419Sjulianstatic int
72370700Sjulianng_iface_rcvdata(hook_p hook, item_p item)
72452419Sjulian{
72570784Sjulian	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
72652419Sjulian	const iffam_p iffam = get_iffam_from_hook(priv, hook);
72752419Sjulian	struct ifnet *const ifp = priv->ifp;
72870700Sjulian	struct mbuf *m;
729111888Sjlemon	int isr;
73052419Sjulian
73170700Sjulian	NGI_GET_M(item, m);
73270700Sjulian	NG_FREE_ITEM(item);
73352419Sjulian	/* Sanity checks */
73487599Sobrien	KASSERT(iffam != NULL, ("%s: iffam", __func__));
735113255Sdes	M_ASSERTPKTHDR(m);
73652419Sjulian	if ((ifp->if_flags & IFF_UP) == 0) {
73770700Sjulian		NG_FREE_M(m);
73852419Sjulian		return (ENETDOWN);
73952419Sjulian	}
74052419Sjulian
74152419Sjulian	/* Update interface stats */
74252419Sjulian	ifp->if_ipackets++;
74352419Sjulian	ifp->if_ibytes += m->m_pkthdr.len;
74452419Sjulian
74552419Sjulian	/* Note receiving interface */
74652419Sjulian	m->m_pkthdr.rcvif = ifp;
74752419Sjulian
74852419Sjulian	/* Berkeley packet filter */
74958015Sarchie	ng_iface_bpftap(ifp, m, iffam->family);
75052419Sjulian
75158015Sarchie	/* Send packet */
752111888Sjlemon	switch (iffam->family) {
753111888Sjlemon#ifdef INET
754111888Sjlemon	case AF_INET:
755111888Sjlemon		isr = NETISR_IP;
756111888Sjlemon		break;
757111888Sjlemon#endif
758111888Sjlemon#ifdef INET6
759111888Sjlemon	case AF_INET6:
760111888Sjlemon		isr = NETISR_IPV6;
761111888Sjlemon		break;
762111888Sjlemon#endif
763111888Sjlemon#ifdef IPX
764111888Sjlemon	case AF_IPX:
765111888Sjlemon		isr = NETISR_IPX;
766111888Sjlemon		break;
767111888Sjlemon#endif
768111888Sjlemon#ifdef NETATALK
769111888Sjlemon	case AF_APPLETALK:
770111888Sjlemon		isr = NETISR_ATALK2;
771111888Sjlemon		break;
772111888Sjlemon#endif
773111888Sjlemon	default:
774111888Sjlemon		m_freem(m);
775111888Sjlemon		return (EAFNOSUPPORT);
776111888Sjlemon	}
777111888Sjlemon	if (harvest.point_to_point)
778256381Smarkm		random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG);
779223741Sbz	M_SETFIB(m, ifp->if_fib);
780180372Sgonzo	netisr_dispatch(isr, m);
781111888Sjlemon	return (0);
78252419Sjulian}
78352419Sjulian
78452419Sjulian/*
78558015Sarchie * Shutdown and remove the node and its associated interface.
78652419Sjulian */
78752419Sjulianstatic int
78870700Sjulianng_iface_shutdown(node_p node)
78952419Sjulian{
79070784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
79152419Sjulian
792183550Szec	/*
793183550Szec	 * The ifnet may be in a different vnet than the netgraph node,
794183550Szec	 * hence we have to change the current vnet context here.
795183550Szec	 */
796183550Szec	CURVNET_SET_QUIET(priv->ifp->if_vnet);
79758412Sarchie	bpfdetach(priv->ifp);
79858015Sarchie	if_detach(priv->ifp);
799147256Sbrooks	if_free(priv->ifp);
800183550Szec	CURVNET_RESTORE();
80158015Sarchie	priv->ifp = NULL;
802181803Sbz	free_unr(V_ng_iface_unit, priv->unit);
803184205Sdes	free(priv, M_NETGRAPH_IFACE);
80470784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
80570784Sjulian	NG_NODE_UNREF(node);
80652419Sjulian	return (0);
80752419Sjulian}
80852419Sjulian
80952419Sjulian/*
81058015Sarchie * Hook disconnection. Note that we do *not* shutdown when all
81158015Sarchie * hooks have been disconnected.
81252419Sjulian */
81352419Sjulianstatic int
81452419Sjulianng_iface_disconnect(hook_p hook)
81552419Sjulian{
81670784Sjulian	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
81752419Sjulian	const iffam_p iffam = get_iffam_from_hook(priv, hook);
81852419Sjulian
81952419Sjulian	if (iffam == NULL)
820213794Srpaulo		panic("%s", __func__);
82152419Sjulian	*get_hook_from_iffam(priv, iffam) = NULL;
82252419Sjulian	return (0);
82352419Sjulian}
82452419Sjulian
825141341Sru/*
826141341Sru * Handle loading and unloading for this node type.
827141341Sru */
828141341Srustatic int
829141341Srung_iface_mod_event(module_t mod, int event, void *data)
830141341Sru{
831141341Sru	int error = 0;
832141341Sru
833141341Sru	switch (event) {
834141341Sru	case MOD_LOAD:
835141341Sru	case MOD_UNLOAD:
836141341Sru		break;
837141341Sru	default:
838141341Sru		error = EOPNOTSUPP;
839141341Sru		break;
840141341Sru	}
841141341Sru	return (error);
842141341Sru}
843191510Szec
844195837Srwatsonstatic void
845195837Srwatsonvnet_ng_iface_init(const void *unused)
846191510Szec{
847191510Szec
848191510Szec	V_ng_iface_unit = new_unrhdr(0, 0xffff, NULL);
849191510Szec}
850195837SrwatsonVNET_SYSINIT(vnet_ng_iface_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
851195837Srwatson    vnet_ng_iface_init, NULL);
852191510Szec
853195837Srwatsonstatic void
854195837Srwatsonvnet_ng_iface_uninit(const void *unused)
855191510Szec{
856191510Szec
857191510Szec	delete_unrhdr(V_ng_iface_unit);
858191510Szec}
859195837SrwatsonVNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
860195837Srwatson    vnet_ng_iface_uninit, NULL);
861