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: stable/10/sys/netgraph/ng_iface.c 324176 2017-10-01 19:40:29Z eugen $
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>
64324176Seugen#include <sys/lock.h>
6552419Sjulian#include <sys/malloc.h>
6652419Sjulian#include <sys/mbuf.h>
6752419Sjulian#include <sys/errno.h>
68196019Srwatson#include <sys/proc.h>
69111888Sjlemon#include <sys/random.h>
70324176Seugen#include <sys/rmlock.h>
7152419Sjulian#include <sys/sockio.h>
7252419Sjulian#include <sys/socket.h>
7352419Sjulian#include <sys/syslog.h>
7458015Sarchie#include <sys/libkern.h>
7552419Sjulian
7652419Sjulian#include <net/if.h>
7752419Sjulian#include <net/if_types.h>
7858015Sarchie#include <net/bpf.h>
79111888Sjlemon#include <net/netisr.h>
80191148Skmacy#include <net/route.h>
81195837Srwatson#include <net/vnet.h>
8252419Sjulian
8353913Sarchie#include <netinet/in.h>
8453913Sarchie
8552419Sjulian#include <netgraph/ng_message.h>
8652419Sjulian#include <netgraph/netgraph.h>
8758015Sarchie#include <netgraph/ng_parse.h>
8852419Sjulian#include <netgraph/ng_iface.h>
8952419Sjulian#include <netgraph/ng_cisco.h>
9052419Sjulian
9170870Sjulian#ifdef NG_SEPARATE_MALLOC
92227293Sedstatic MALLOC_DEFINE(M_NETGRAPH_IFACE, "netgraph_iface", "netgraph iface node");
9370870Sjulian#else
9470870Sjulian#define M_NETGRAPH_IFACE M_NETGRAPH
9570870Sjulian#endif
9670870Sjulian
9752419Sjulian/* This struct describes one address family */
9852419Sjulianstruct iffam {
9958015Sarchie	sa_family_t	family;		/* Address family */
10058015Sarchie	const char	*hookname;	/* Name for hook */
10152419Sjulian};
10252419Sjuliantypedef const struct iffam *iffam_p;
10352419Sjulian
10458015Sarchie/* List of address families supported by our interface */
10552419Sjulianconst static struct iffam gFamilies[] = {
10658015Sarchie	{ AF_INET,	NG_IFACE_HOOK_INET	},
10758015Sarchie	{ AF_INET6,	NG_IFACE_HOOK_INET6	},
10858015Sarchie	{ AF_APPLETALK,	NG_IFACE_HOOK_ATALK	},
10958015Sarchie	{ AF_IPX,	NG_IFACE_HOOK_IPX	},
11058015Sarchie	{ AF_ATM,	NG_IFACE_HOOK_ATM	},
11158015Sarchie	{ AF_NATM,	NG_IFACE_HOOK_NATM	},
11252419Sjulian};
11352419Sjulian#define NUM_FAMILIES		(sizeof(gFamilies) / sizeof(*gFamilies))
11452419Sjulian
11552419Sjulian/* Node private data */
11653393Sarchiestruct ng_iface_private {
11758015Sarchie	struct	ifnet *ifp;		/* Our interface */
11858015Sarchie	int	unit;			/* Interface unit number */
11952419Sjulian	node_p	node;			/* Our netgraph node */
12052419Sjulian	hook_p	hooks[NUM_FAMILIES];	/* Hook for each address family */
121324176Seugen	struct rmlock	lock;		/* Protect private data changes */
12252419Sjulian};
12353393Sarchietypedef struct ng_iface_private *priv_p;
12452419Sjulian
125324176Seugen#define	PRIV_RLOCK(priv, t)	rm_rlock(&priv->lock, t)
126324176Seugen#define	PRIV_RUNLOCK(priv, t)	rm_runlock(&priv->lock, t)
127324176Seugen#define	PRIV_WLOCK(priv)	rm_wlock(&priv->lock)
128324176Seugen#define	PRIV_WUNLOCK(priv)	rm_wunlock(&priv->lock)
129324176Seugen
13052419Sjulian/* Interface methods */
13152419Sjulianstatic void	ng_iface_start(struct ifnet *ifp);
13252419Sjulianstatic int	ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
13352419Sjulianstatic int	ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
134249925Sglebius    			const struct sockaddr *dst, struct route *ro);
13558015Sarchiestatic void	ng_iface_bpftap(struct ifnet *ifp,
13658015Sarchie			struct mbuf *m, sa_family_t family);
137151203Sglebiusstatic int	ng_iface_send(struct ifnet *ifp, struct mbuf *m,
138151203Sglebius			sa_family_t sa);
13952419Sjulian#ifdef DEBUG
14052419Sjulianstatic void	ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
14152419Sjulian#endif
14252419Sjulian
14352419Sjulian/* Netgraph methods */
144141341Srustatic int		ng_iface_mod_event(module_t, int, void *);
14552752Sjulianstatic ng_constructor_t	ng_iface_constructor;
14652752Sjulianstatic ng_rcvmsg_t	ng_iface_rcvmsg;
14770700Sjulianstatic ng_shutdown_t	ng_iface_shutdown;
14852752Sjulianstatic ng_newhook_t	ng_iface_newhook;
14952752Sjulianstatic ng_rcvdata_t	ng_iface_rcvdata;
15052752Sjulianstatic ng_disconnect_t	ng_iface_disconnect;
15152419Sjulian
15252419Sjulian/* Helper stuff */
15358015Sarchiestatic iffam_p	get_iffam_from_af(sa_family_t family);
15452419Sjulianstatic iffam_p	get_iffam_from_hook(priv_p priv, hook_p hook);
15552419Sjulianstatic iffam_p	get_iffam_from_name(const char *name);
15652419Sjulianstatic hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
15752419Sjulian
15858015Sarchie/* Parse type for struct ng_cisco_ipaddr */
15997685Sarchiestatic const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[]
16097685Sarchie	= NG_CISCO_IPADDR_TYPE_INFO;
16158015Sarchiestatic const struct ng_parse_type ng_cisco_ipaddr_type = {
16258015Sarchie	&ng_parse_struct_type,
16397685Sarchie	&ng_cisco_ipaddr_type_fields
16458015Sarchie};
16558015Sarchie
16658015Sarchie/* List of commands and how to convert arguments to/from ASCII */
16758015Sarchiestatic const struct ng_cmdlist ng_iface_cmds[] = {
16858015Sarchie	{
16958015Sarchie	  NGM_IFACE_COOKIE,
17058015Sarchie	  NGM_IFACE_GET_IFNAME,
17158015Sarchie	  "getifname",
17258015Sarchie	  NULL,
173141197Sru	  &ng_parse_string_type
17458015Sarchie	},
17558015Sarchie	{
17658015Sarchie	  NGM_IFACE_COOKIE,
17758015Sarchie	  NGM_IFACE_POINT2POINT,
17858015Sarchie	  "point2point",
17958015Sarchie	  NULL,
18058015Sarchie	  NULL
18158015Sarchie	},
18258015Sarchie	{
18358015Sarchie	  NGM_IFACE_COOKIE,
18458015Sarchie	  NGM_IFACE_BROADCAST,
18558015Sarchie	  "broadcast",
18658015Sarchie	  NULL,
18758015Sarchie	  NULL
18858015Sarchie	},
18958015Sarchie	{
19058015Sarchie	  NGM_CISCO_COOKIE,
19158015Sarchie	  NGM_CISCO_GET_IPADDR,
19258015Sarchie	  "getipaddr",
19358015Sarchie	  NULL,
19458015Sarchie	  &ng_cisco_ipaddr_type
19558015Sarchie	},
196126730Sru	{
197126730Sru	  NGM_IFACE_COOKIE,
198126730Sru	  NGM_IFACE_GET_IFINDEX,
199126730Sru	  "getifindex",
200126730Sru	  NULL,
201126730Sru	  &ng_parse_uint32_type
202126730Sru	},
20358015Sarchie	{ 0 }
20458015Sarchie};
20558015Sarchie
20652419Sjulian/* Node type descriptor */
20752419Sjulianstatic struct ng_type typestruct = {
208129823Sjulian	.version =	NG_ABI_VERSION,
209129823Sjulian	.name =		NG_IFACE_NODE_TYPE,
210141341Sru	.mod_event =	ng_iface_mod_event,
211129823Sjulian	.constructor =	ng_iface_constructor,
212129823Sjulian	.rcvmsg =	ng_iface_rcvmsg,
213129823Sjulian	.shutdown =	ng_iface_shutdown,
214129823Sjulian	.newhook =	ng_iface_newhook,
215129823Sjulian	.rcvdata =	ng_iface_rcvdata,
216129823Sjulian	.disconnect =	ng_iface_disconnect,
217129823Sjulian	.cmdlist =	ng_iface_cmds,
21852419Sjulian};
21952419SjulianNETGRAPH_INIT(iface, &typestruct);
22052419Sjulian
221215701Sdimstatic VNET_DEFINE(struct unrhdr *, ng_iface_unit);
222195727Srwatson#define	V_ng_iface_unit			VNET(ng_iface_unit)
22352419Sjulian
22452419Sjulian/************************************************************************
22552419Sjulian			HELPER STUFF
22652419Sjulian ************************************************************************/
22752419Sjulian
22852419Sjulian/*
22952419Sjulian * Get the family descriptor from the family ID
23052419Sjulian */
231131575Sstefanfstatic __inline iffam_p
23258015Sarchieget_iffam_from_af(sa_family_t family)
23352419Sjulian{
23452419Sjulian	iffam_p iffam;
23552419Sjulian	int k;
23652419Sjulian
23752419Sjulian	for (k = 0; k < NUM_FAMILIES; k++) {
23852419Sjulian		iffam = &gFamilies[k];
23958015Sarchie		if (iffam->family == family)
24052419Sjulian			return (iffam);
24152419Sjulian	}
24252419Sjulian	return (NULL);
24352419Sjulian}
24452419Sjulian
24552419Sjulian/*
24652419Sjulian * Get the family descriptor from the hook
24752419Sjulian */
248131575Sstefanfstatic __inline iffam_p
24952419Sjulianget_iffam_from_hook(priv_p priv, hook_p hook)
25052419Sjulian{
25152419Sjulian	int k;
25252419Sjulian
25352419Sjulian	for (k = 0; k < NUM_FAMILIES; k++)
25452419Sjulian		if (priv->hooks[k] == hook)
25552419Sjulian			return (&gFamilies[k]);
25652419Sjulian	return (NULL);
25752419Sjulian}
25852419Sjulian
25952419Sjulian/*
26052419Sjulian * Get the hook from the iffam descriptor
26152419Sjulian */
26252419Sjulian
263131575Sstefanfstatic __inline hook_p *
26452419Sjulianget_hook_from_iffam(priv_p priv, iffam_p iffam)
26552419Sjulian{
26652419Sjulian	return (&priv->hooks[iffam - gFamilies]);
26752419Sjulian}
26852419Sjulian
26952419Sjulian/*
27052419Sjulian * Get the iffam descriptor from the name
27152419Sjulian */
272131575Sstefanfstatic __inline iffam_p
27352419Sjulianget_iffam_from_name(const char *name)
27452419Sjulian{
27552419Sjulian	iffam_p iffam;
27652419Sjulian	int k;
27752419Sjulian
27852419Sjulian	for (k = 0; k < NUM_FAMILIES; k++) {
27952419Sjulian		iffam = &gFamilies[k];
28052419Sjulian		if (!strcmp(iffam->hookname, name))
28152419Sjulian			return (iffam);
28252419Sjulian	}
28352419Sjulian	return (NULL);
28452419Sjulian}
28552419Sjulian
28652419Sjulian/************************************************************************
28752419Sjulian			INTERFACE STUFF
28852419Sjulian ************************************************************************/
28952419Sjulian
29052419Sjulian/*
29152419Sjulian * Process an ioctl for the virtual interface
29252419Sjulian */
29352419Sjulianstatic int
29452419Sjulianng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
29552419Sjulian{
29652419Sjulian	struct ifreq *const ifr = (struct ifreq *) data;
297219781Sglebius	int error = 0;
29852419Sjulian
29952419Sjulian#ifdef DEBUG
30052419Sjulian	ng_iface_print_ioctl(ifp, command, data);
30152419Sjulian#endif
30252419Sjulian	switch (command) {
30352419Sjulian
30452419Sjulian	/* These two are mostly handled at a higher layer */
30552419Sjulian	case SIOCSIFADDR:
306148887Srwatson		ifp->if_flags |= IFF_UP;
307148887Srwatson		ifp->if_drv_flags |= IFF_DRV_RUNNING;
308148887Srwatson		ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
30952419Sjulian		break;
31052419Sjulian	case SIOCGIFADDR:
31152419Sjulian		break;
31252419Sjulian
31352419Sjulian	/* Set flags */
31452419Sjulian	case SIOCSIFFLAGS:
31552419Sjulian		/*
31652419Sjulian		 * If the interface is marked up and stopped, then start it.
31752419Sjulian		 * If it is marked down and running, then stop it.
31852419Sjulian		 */
31952419Sjulian		if (ifr->ifr_flags & IFF_UP) {
320148887Srwatson			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
321148887Srwatson				ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
322148887Srwatson				ifp->if_drv_flags |= IFF_DRV_RUNNING;
32352419Sjulian			}
32452419Sjulian		} else {
325148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
326148887Srwatson				ifp->if_drv_flags &= ~(IFF_DRV_RUNNING |
327148887Srwatson				    IFF_DRV_OACTIVE);
32852419Sjulian		}
32952419Sjulian		break;
33052419Sjulian
33152419Sjulian	/* Set the interface MTU */
33252419Sjulian	case SIOCSIFMTU:
33352419Sjulian		if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
33452419Sjulian		    || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
33552419Sjulian			error = EINVAL;
33652419Sjulian		else
33752419Sjulian			ifp->if_mtu = ifr->ifr_mtu;
33852419Sjulian		break;
33952419Sjulian
34052419Sjulian	/* Stuff that's not supported */
34152419Sjulian	case SIOCADDMULTI:
34252419Sjulian	case SIOCDELMULTI:
34352975Sarchie		error = 0;
34452975Sarchie		break;
34552419Sjulian	case SIOCSIFPHYS:
34652419Sjulian		error = EOPNOTSUPP;
34752419Sjulian		break;
34852419Sjulian
34952419Sjulian	default:
35052419Sjulian		error = EINVAL;
35152419Sjulian		break;
35252419Sjulian	}
35352419Sjulian	return (error);
35452419Sjulian}
35552419Sjulian
35652419Sjulian/*
35752419Sjulian * This routine is called to deliver a packet out the interface.
35852419Sjulian * We simply look at the address family and relay the packet to
35952419Sjulian * the corresponding hook, if it exists and is connected.
36052419Sjulian */
36152419Sjulian
36252419Sjulianstatic int
36352419Sjulianng_iface_output(struct ifnet *ifp, struct mbuf *m,
364249925Sglebius	const struct sockaddr *dst, struct route *ro)
36552419Sjulian{
366187495Smav	struct m_tag *mtag;
367151203Sglebius	uint32_t af;
368151231Sglebius	int error;
36952419Sjulian
37052419Sjulian	/* Check interface flags */
371148887Srwatson	if (!((ifp->if_flags & IFF_UP) &&
372148887Srwatson	    (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
37352419Sjulian		m_freem(m);
37452419Sjulian		return (ENETDOWN);
37552419Sjulian	}
37652419Sjulian
377187495Smav	/* Protect from deadly infinite recursion. */
378195231Smav	mtag = NULL;
379195231Smav	while ((mtag = m_tag_locate(m, MTAG_NGIF, MTAG_NGIF_CALLED, mtag))) {
380187495Smav		if (*(struct ifnet **)(mtag + 1) == ifp) {
381187495Smav			log(LOG_NOTICE, "Loop detected on %s\n", ifp->if_xname);
382187495Smav			m_freem(m);
383187495Smav			return (EDEADLK);
384187495Smav		}
385187495Smav	}
386187495Smav	mtag = m_tag_alloc(MTAG_NGIF, MTAG_NGIF_CALLED, sizeof(struct ifnet *),
387187495Smav	    M_NOWAIT);
388187495Smav	if (mtag == NULL) {
389187495Smav		m_freem(m);
390187495Smav		return (ENOMEM);
391187495Smav	}
392187495Smav	*(struct ifnet **)(mtag + 1) = ifp;
393187495Smav	m_tag_prepend(m, mtag);
394187495Smav
395147611Sdwmalone	/* BPF writes need to be handled specially. */
396249925Sglebius	if (dst->sa_family == AF_UNSPEC)
397147611Sdwmalone		bcopy(dst->sa_data, &af, sizeof(af));
398249925Sglebius	else
399249925Sglebius		af = dst->sa_family;
40058015Sarchie
40152419Sjulian	/* Berkeley packet filter */
402249925Sglebius	ng_iface_bpftap(ifp, m, af);
40352419Sjulian
404151203Sglebius	if (ALTQ_IS_ENABLED(&ifp->if_snd)) {
405243882Sglebius		M_PREPEND(m, sizeof(sa_family_t), M_NOWAIT);
406151203Sglebius		if (m == NULL) {
407151231Sglebius			IFQ_LOCK(&ifp->if_snd);
408151231Sglebius			IFQ_INC_DROPS(&ifp->if_snd);
409151231Sglebius			IFQ_UNLOCK(&ifp->if_snd);
410151203Sglebius			ifp->if_oerrors++;
411151203Sglebius			return (ENOBUFS);
412151203Sglebius		}
413249925Sglebius		*(sa_family_t *)m->m_data = af;
414185164Skmacy		error = (ifp->if_transmit)(ifp, m);
415151203Sglebius	} else
416249925Sglebius		error = ng_iface_send(ifp, m, af);
41752419Sjulian
41852419Sjulian	return (error);
41952419Sjulian}
42052419Sjulian
42152419Sjulian/*
422151231Sglebius * Start method is used only when ALTQ is enabled.
42352419Sjulian */
42452419Sjulianstatic void
42552419Sjulianng_iface_start(struct ifnet *ifp)
42652419Sjulian{
427151203Sglebius	struct mbuf *m;
428151203Sglebius	sa_family_t sa;
429151203Sglebius
430151231Sglebius	KASSERT(ALTQ_IS_ENABLED(&ifp->if_snd), ("%s without ALTQ", __func__));
431151203Sglebius
432151231Sglebius	for(;;) {
433151203Sglebius		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
434151203Sglebius		if (m == NULL)
435151203Sglebius			break;
436151203Sglebius		sa = *mtod(m, sa_family_t *);
437151203Sglebius		m_adj(m, sizeof(sa_family_t));
438151203Sglebius		ng_iface_send(ifp, m, sa);
439151203Sglebius	}
44052419Sjulian}
44152419Sjulian
44252419Sjulian/*
44352419Sjulian * Flash a packet by the BPF (requires prepending 4 byte AF header)
44452419Sjulian * Note the phoney mbuf; this is OK because BPF treats it read-only.
44552419Sjulian */
44652419Sjulianstatic void
44758015Sarchieng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family)
44852419Sjulian{
44987599Sobrien	KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__));
450159183Ssam	if (bpf_peers_present(ifp->if_bpf)) {
451123922Ssam		int32_t family4 = (int32_t)family;
452123922Ssam		bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m);
45352419Sjulian	}
45452419Sjulian}
45552419Sjulian
456151203Sglebius/*
457151203Sglebius * This routine does actual delivery of the packet into the
458151203Sglebius * netgraph(4). It is called from ng_iface_start() and
459151231Sglebius * ng_iface_output().
460151203Sglebius */
461151203Sglebiusstatic int
462151203Sglebiusng_iface_send(struct ifnet *ifp, struct mbuf *m, sa_family_t sa)
463151203Sglebius{
464324176Seugen	struct rm_priotracker priv_tracker;
465151203Sglebius	const priv_p priv = (priv_p) ifp->if_softc;
466151203Sglebius	const iffam_p iffam = get_iffam_from_af(sa);
467324176Seugen	hook_p hook;
468151231Sglebius	int error;
469151203Sglebius	int len;
470151203Sglebius
471151203Sglebius	/* Check address family to determine hook (if known) */
472151203Sglebius	if (iffam == NULL) {
473151203Sglebius		m_freem(m);
474151203Sglebius		log(LOG_WARNING, "%s: can't handle af%d\n", ifp->if_xname, sa);
475151203Sglebius		return (EAFNOSUPPORT);
476151203Sglebius	}
477151203Sglebius
478151203Sglebius	/* Copy length before the mbuf gets invalidated. */
479151203Sglebius	len = m->m_pkthdr.len;
480151203Sglebius
481324176Seugen	PRIV_RLOCK(priv, &priv_tracker);
482324176Seugen	hook = *get_hook_from_iffam(priv, iffam);
483324176Seugen	if (hook == NULL) {
484324176Seugen		NG_FREE_M(m);
485324176Seugen		PRIV_RUNLOCK(priv, &priv_tracker);
486324176Seugen		return ENETDOWN;
487324176Seugen	}
488324176Seugen	NG_HOOK_REF(hook);
489324176Seugen	PRIV_RUNLOCK(priv, &priv_tracker);
490324176Seugen
491194012Szec	NG_OUTBOUND_THREAD_REF();
492324176Seugen	NG_SEND_DATA_ONLY(error, hook, m);
493194012Szec	NG_OUTBOUND_THREAD_UNREF();
494324176Seugen	NG_HOOK_UNREF(hook);
495151203Sglebius
496151203Sglebius	/* Update stats. */
497151203Sglebius	if (error == 0) {
498151203Sglebius		ifp->if_obytes += len;
499151203Sglebius		ifp->if_opackets++;
500151203Sglebius	}
501151203Sglebius
502151203Sglebius	return (error);
503151203Sglebius}
504151203Sglebius
50552419Sjulian#ifdef DEBUG
50652419Sjulian/*
50752419Sjulian * Display an ioctl to the virtual interface
50852419Sjulian */
50952419Sjulian
51052419Sjulianstatic void
51152419Sjulianng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
51252419Sjulian{
51352419Sjulian	char   *str;
51452419Sjulian
51552419Sjulian	switch (command & IOC_DIRMASK) {
51652419Sjulian	case IOC_VOID:
51752419Sjulian		str = "IO";
51852419Sjulian		break;
51952419Sjulian	case IOC_OUT:
52052419Sjulian		str = "IOR";
52152419Sjulian		break;
52252419Sjulian	case IOC_IN:
52352419Sjulian		str = "IOW";
52452419Sjulian		break;
52552419Sjulian	case IOC_INOUT:
52652419Sjulian		str = "IORW";
52752419Sjulian		break;
52852419Sjulian	default:
52952419Sjulian		str = "IO??";
53052419Sjulian	}
531121816Sbrooks	log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
532121816Sbrooks	       ifp->if_xname,
53352419Sjulian	       str,
53452419Sjulian	       IOCGROUP(command),
53552419Sjulian	       command & 0xff,
53652419Sjulian	       IOCPARM_LEN(command));
53752419Sjulian}
53852419Sjulian#endif /* DEBUG */
53952419Sjulian
54052419Sjulian/************************************************************************
54152419Sjulian			NETGRAPH NODE STUFF
54252419Sjulian ************************************************************************/
54352419Sjulian
54452419Sjulian/*
54552419Sjulian * Constructor for a node
54652419Sjulian */
54752419Sjulianstatic int
54870700Sjulianng_iface_constructor(node_p node)
54952419Sjulian{
55052419Sjulian	struct ifnet *ifp;
55152419Sjulian	priv_p priv;
55252419Sjulian
55352419Sjulian	/* Allocate node and interface private structures */
554220768Sglebius	priv = malloc(sizeof(*priv), M_NETGRAPH_IFACE, M_WAITOK | M_ZERO);
555147256Sbrooks	ifp = if_alloc(IFT_PROPVIRTUAL);
55652419Sjulian	if (ifp == NULL) {
557184205Sdes		free(priv, M_NETGRAPH_IFACE);
55852419Sjulian		return (ENOMEM);
55952419Sjulian	}
56052419Sjulian
561324176Seugen	rm_init(&priv->lock, "ng_iface private rmlock");
562324176Seugen
56352419Sjulian	/* Link them together */
56452419Sjulian	ifp->if_softc = priv;
56552419Sjulian	priv->ifp = ifp;
56652419Sjulian
56758015Sarchie	/* Get an interface unit number */
568181803Sbz	priv->unit = alloc_unr(V_ng_iface_unit);
56958015Sarchie
57052419Sjulian	/* Link together node and private info */
57170784Sjulian	NG_NODE_SET_PRIVATE(node, priv);
57252419Sjulian	priv->node = node;
57352419Sjulian
57452419Sjulian	/* Initialize interface structure */
575121816Sbrooks	if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit);
57652419Sjulian	ifp->if_output = ng_iface_output;
57752419Sjulian	ifp->if_start = ng_iface_start;
57852419Sjulian	ifp->if_ioctl = ng_iface_ioctl;
57952419Sjulian	ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
58058015Sarchie	ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST);
58152419Sjulian	ifp->if_type = IFT_PROPVIRTUAL;		/* XXX */
58252419Sjulian	ifp->if_addrlen = 0;			/* XXX */
58352419Sjulian	ifp->if_hdrlen = 0;			/* XXX */
58452419Sjulian	ifp->if_baudrate = 64000;		/* XXX */
585207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
586207554Ssobomax	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
587151203Sglebius	IFQ_SET_READY(&ifp->if_snd);
58852419Sjulian
58952419Sjulian	/* Give this node the same name as the interface (if possible) */
590141197Sru	if (ng_name_node(node, ifp->if_xname) != 0)
591141197Sru		log(LOG_WARNING, "%s: can't acquire netgraph name\n",
592141197Sru		    ifp->if_xname);
59352419Sjulian
59452419Sjulian	/* Attach the interface */
59552419Sjulian	if_attach(ifp);
596147611Sdwmalone	bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
59752419Sjulian
59852419Sjulian	/* Done */
59952419Sjulian	return (0);
60052419Sjulian}
60152419Sjulian
60252419Sjulian/*
60352419Sjulian * Give our ok for a hook to be added
60452419Sjulian */
60552419Sjulianstatic int
60652419Sjulianng_iface_newhook(node_p node, hook_p hook, const char *name)
60752419Sjulian{
60852419Sjulian	const iffam_p iffam = get_iffam_from_name(name);
609324176Seugen	const priv_p priv = NG_NODE_PRIVATE(node);
61052419Sjulian	hook_p *hookptr;
61152419Sjulian
61252419Sjulian	if (iffam == NULL)
61352419Sjulian		return (EPFNOSUPPORT);
614324176Seugen	PRIV_WLOCK(priv);
615324176Seugen	hookptr = get_hook_from_iffam(priv, iffam);
616324176Seugen	if (*hookptr != NULL) {
617324176Seugen		PRIV_WUNLOCK(priv);
61852419Sjulian		return (EISCONN);
619324176Seugen	}
62052419Sjulian	*hookptr = hook;
621175847Smav	NG_HOOK_HI_STACK(hook);
622194012Szec	NG_HOOK_SET_TO_INBOUND(hook);
623324176Seugen	PRIV_WUNLOCK(priv);
62452419Sjulian	return (0);
62552419Sjulian}
62652419Sjulian
62752419Sjulian/*
62852419Sjulian * Receive a control message
62952419Sjulian */
63052419Sjulianstatic int
63170700Sjulianng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook)
63252419Sjulian{
63370784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
63452419Sjulian	struct ifnet *const ifp = priv->ifp;
63552419Sjulian	struct ng_mesg *resp = NULL;
63652419Sjulian	int error = 0;
63770700Sjulian	struct ng_mesg *msg;
63852419Sjulian
63970700Sjulian	NGI_GET_MSG(item, msg);
64052419Sjulian	switch (msg->header.typecookie) {
64152419Sjulian	case NGM_IFACE_COOKIE:
64252419Sjulian		switch (msg->header.cmd) {
64352419Sjulian		case NGM_IFACE_GET_IFNAME:
644141197Sru			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
64552419Sjulian			if (resp == NULL) {
64652419Sjulian				error = ENOMEM;
64752419Sjulian				break;
64852419Sjulian			}
649141197Sru			strlcpy(resp->data, ifp->if_xname, IFNAMSIZ);
65052419Sjulian			break;
65152419Sjulian
65258015Sarchie		case NGM_IFACE_POINT2POINT:
65358015Sarchie		case NGM_IFACE_BROADCAST:
65452419Sjulian		    {
65552419Sjulian
65658015Sarchie			/* Deny request if interface is UP */
65758015Sarchie			if ((ifp->if_flags & IFF_UP) != 0)
65858015Sarchie				return (EBUSY);
65952419Sjulian
66058015Sarchie			/* Change flags */
66158015Sarchie			switch (msg->header.cmd) {
66258015Sarchie			case NGM_IFACE_POINT2POINT:
66358015Sarchie				ifp->if_flags |= IFF_POINTOPOINT;
66458015Sarchie				ifp->if_flags &= ~IFF_BROADCAST;
66552419Sjulian				break;
66658015Sarchie			case NGM_IFACE_BROADCAST:
66758015Sarchie				ifp->if_flags &= ~IFF_POINTOPOINT;
66858015Sarchie				ifp->if_flags |= IFF_BROADCAST;
66958015Sarchie				break;
67052419Sjulian			}
67152419Sjulian			break;
67252419Sjulian		    }
67352419Sjulian
674126730Sru		case NGM_IFACE_GET_IFINDEX:
675126730Sru			NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
676126730Sru			if (resp == NULL) {
677126730Sru				error = ENOMEM;
678126730Sru				break;
679126730Sru			}
680126730Sru			*((uint32_t *)resp->data) = priv->ifp->if_index;
681126730Sru			break;
682126730Sru
68352419Sjulian		default:
68452419Sjulian			error = EINVAL;
68552419Sjulian			break;
68652419Sjulian		}
68752419Sjulian		break;
68852419Sjulian	case NGM_CISCO_COOKIE:
68952419Sjulian		switch (msg->header.cmd) {
69052419Sjulian		case NGM_CISCO_GET_IPADDR:	/* we understand this too */
69152419Sjulian		    {
69252419Sjulian			struct ifaddr *ifa;
69352419Sjulian
69452419Sjulian			/* Return the first configured IP address */
695195024Srwatson			if_addr_rlock(ifp);
69652419Sjulian			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
69758015Sarchie				struct ng_cisco_ipaddr *ips;
69852419Sjulian
69952419Sjulian				if (ifa->ifa_addr->sa_family != AF_INET)
70052419Sjulian					continue;
70158015Sarchie				NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT);
70252419Sjulian				if (resp == NULL) {
70352419Sjulian					error = ENOMEM;
70452419Sjulian					break;
70552419Sjulian				}
70658015Sarchie				ips = (struct ng_cisco_ipaddr *)resp->data;
70758015Sarchie				ips->ipaddr = ((struct sockaddr_in *)
70852419Sjulian						ifa->ifa_addr)->sin_addr;
70958015Sarchie				ips->netmask = ((struct sockaddr_in *)
71052419Sjulian						ifa->ifa_netmask)->sin_addr;
71152419Sjulian				break;
71252419Sjulian			}
713195024Srwatson			if_addr_runlock(ifp);
71452419Sjulian
71552419Sjulian			/* No IP addresses on this interface? */
71652419Sjulian			if (ifa == NULL)
71752419Sjulian				error = EADDRNOTAVAIL;
71852419Sjulian			break;
71952419Sjulian		    }
72052419Sjulian		default:
72152419Sjulian			error = EINVAL;
72252419Sjulian			break;
72352419Sjulian		}
72452419Sjulian		break;
725138011Sglebius	case NGM_FLOW_COOKIE:
726138011Sglebius		switch (msg->header.cmd) {
727138011Sglebius		case NGM_LINK_IS_UP:
728148887Srwatson			ifp->if_drv_flags |= IFF_DRV_RUNNING;
729138011Sglebius			break;
730138011Sglebius		case NGM_LINK_IS_DOWN:
731148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
732138011Sglebius			break;
733138011Sglebius		default:
734138011Sglebius			break;
735138011Sglebius		}
736138011Sglebius		break;
73752419Sjulian	default:
73852419Sjulian		error = EINVAL;
73952419Sjulian		break;
74052419Sjulian	}
74170700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
74270700Sjulian	NG_FREE_MSG(msg);
74352419Sjulian	return (error);
74452419Sjulian}
74552419Sjulian
74652419Sjulian/*
74752419Sjulian * Recive data from a hook. Pass the packet to the correct input routine.
74852419Sjulian */
74952419Sjulianstatic int
75070700Sjulianng_iface_rcvdata(hook_p hook, item_p item)
75152419Sjulian{
75270784Sjulian	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
75352419Sjulian	const iffam_p iffam = get_iffam_from_hook(priv, hook);
75452419Sjulian	struct ifnet *const ifp = priv->ifp;
75570700Sjulian	struct mbuf *m;
756111888Sjlemon	int isr;
75752419Sjulian
75870700Sjulian	NGI_GET_M(item, m);
75970700Sjulian	NG_FREE_ITEM(item);
76052419Sjulian	/* Sanity checks */
76187599Sobrien	KASSERT(iffam != NULL, ("%s: iffam", __func__));
762113255Sdes	M_ASSERTPKTHDR(m);
76352419Sjulian	if ((ifp->if_flags & IFF_UP) == 0) {
76470700Sjulian		NG_FREE_M(m);
76552419Sjulian		return (ENETDOWN);
76652419Sjulian	}
76752419Sjulian
76852419Sjulian	/* Update interface stats */
76952419Sjulian	ifp->if_ipackets++;
77052419Sjulian	ifp->if_ibytes += m->m_pkthdr.len;
77152419Sjulian
77252419Sjulian	/* Note receiving interface */
77352419Sjulian	m->m_pkthdr.rcvif = ifp;
77452419Sjulian
77552419Sjulian	/* Berkeley packet filter */
77658015Sarchie	ng_iface_bpftap(ifp, m, iffam->family);
77752419Sjulian
77858015Sarchie	/* Send packet */
779111888Sjlemon	switch (iffam->family) {
780111888Sjlemon#ifdef INET
781111888Sjlemon	case AF_INET:
782111888Sjlemon		isr = NETISR_IP;
783111888Sjlemon		break;
784111888Sjlemon#endif
785111888Sjlemon#ifdef INET6
786111888Sjlemon	case AF_INET6:
787111888Sjlemon		isr = NETISR_IPV6;
788111888Sjlemon		break;
789111888Sjlemon#endif
790111888Sjlemon#ifdef IPX
791111888Sjlemon	case AF_IPX:
792111888Sjlemon		isr = NETISR_IPX;
793111888Sjlemon		break;
794111888Sjlemon#endif
795111888Sjlemon#ifdef NETATALK
796111888Sjlemon	case AF_APPLETALK:
797111888Sjlemon		isr = NETISR_ATALK2;
798111888Sjlemon		break;
799111888Sjlemon#endif
800111888Sjlemon	default:
801111888Sjlemon		m_freem(m);
802111888Sjlemon		return (EAFNOSUPPORT);
803111888Sjlemon	}
804111888Sjlemon	if (harvest.point_to_point)
805256381Smarkm		random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG);
806223741Sbz	M_SETFIB(m, ifp->if_fib);
807180372Sgonzo	netisr_dispatch(isr, m);
808111888Sjlemon	return (0);
80952419Sjulian}
81052419Sjulian
81152419Sjulian/*
81258015Sarchie * Shutdown and remove the node and its associated interface.
81352419Sjulian */
81452419Sjulianstatic int
81570700Sjulianng_iface_shutdown(node_p node)
81652419Sjulian{
81770784Sjulian	const priv_p priv = NG_NODE_PRIVATE(node);
81852419Sjulian
819183550Szec	/*
820183550Szec	 * The ifnet may be in a different vnet than the netgraph node,
821183550Szec	 * hence we have to change the current vnet context here.
822183550Szec	 */
823183550Szec	CURVNET_SET_QUIET(priv->ifp->if_vnet);
82458412Sarchie	bpfdetach(priv->ifp);
82558015Sarchie	if_detach(priv->ifp);
826147256Sbrooks	if_free(priv->ifp);
827183550Szec	CURVNET_RESTORE();
82858015Sarchie	priv->ifp = NULL;
829181803Sbz	free_unr(V_ng_iface_unit, priv->unit);
830324176Seugen	rm_destroy(&priv->lock);
831184205Sdes	free(priv, M_NETGRAPH_IFACE);
83270784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
83370784Sjulian	NG_NODE_UNREF(node);
83452419Sjulian	return (0);
83552419Sjulian}
83652419Sjulian
83752419Sjulian/*
83858015Sarchie * Hook disconnection. Note that we do *not* shutdown when all
83958015Sarchie * hooks have been disconnected.
84052419Sjulian */
84152419Sjulianstatic int
84252419Sjulianng_iface_disconnect(hook_p hook)
84352419Sjulian{
84470784Sjulian	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
84552419Sjulian	const iffam_p iffam = get_iffam_from_hook(priv, hook);
84652419Sjulian
84752419Sjulian	if (iffam == NULL)
848213794Srpaulo		panic("%s", __func__);
849324176Seugen	PRIV_WLOCK(priv);
85052419Sjulian	*get_hook_from_iffam(priv, iffam) = NULL;
851324176Seugen	PRIV_WUNLOCK(priv);
85252419Sjulian	return (0);
85352419Sjulian}
85452419Sjulian
855141341Sru/*
856141341Sru * Handle loading and unloading for this node type.
857141341Sru */
858141341Srustatic int
859141341Srung_iface_mod_event(module_t mod, int event, void *data)
860141341Sru{
861141341Sru	int error = 0;
862141341Sru
863141341Sru	switch (event) {
864141341Sru	case MOD_LOAD:
865141341Sru	case MOD_UNLOAD:
866141341Sru		break;
867141341Sru	default:
868141341Sru		error = EOPNOTSUPP;
869141341Sru		break;
870141341Sru	}
871141341Sru	return (error);
872141341Sru}
873191510Szec
874195837Srwatsonstatic void
875195837Srwatsonvnet_ng_iface_init(const void *unused)
876191510Szec{
877191510Szec
878191510Szec	V_ng_iface_unit = new_unrhdr(0, 0xffff, NULL);
879191510Szec}
880195837SrwatsonVNET_SYSINIT(vnet_ng_iface_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
881195837Srwatson    vnet_ng_iface_init, NULL);
882191510Szec
883195837Srwatsonstatic void
884195837Srwatsonvnet_ng_iface_uninit(const void *unused)
885191510Szec{
886191510Szec
887191510Szec	delete_unrhdr(V_ng_iface_unit);
888191510Szec}
889195837SrwatsonVNET_SYSUNINIT(vnet_ng_iface_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
890195837Srwatson    vnet_ng_iface_uninit, NULL);
891