xref: /dragonfly/sys/netgraph7/eiface/ng_eiface.c (revision be2ac35f)
192598697SNuno Antunes /*-
292598697SNuno Antunes  *
392598697SNuno Antunes  * Copyright (c) 1999-2001, Vitaly V Belekhov
492598697SNuno Antunes  * All rights reserved.
592598697SNuno Antunes  *
692598697SNuno Antunes  * Redistribution and use in source and binary forms, with or without
792598697SNuno Antunes  * modification, are permitted provided that the following conditions
892598697SNuno Antunes  * are met:
992598697SNuno Antunes  * 1. Redistributions of source code must retain the above copyright
1092598697SNuno Antunes  *    notice unmodified, this list of conditions, and the following
1192598697SNuno Antunes  *    disclaimer.
1292598697SNuno Antunes  * 2. Redistributions in binary form must reproduce the above copyright
1392598697SNuno Antunes  *    notice, this list of conditions and the following disclaimer in the
1492598697SNuno Antunes  *    documentation and/or other materials provided with the distribution.
1592598697SNuno Antunes  *
1692598697SNuno Antunes  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1792598697SNuno Antunes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1892598697SNuno Antunes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1992598697SNuno Antunes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2092598697SNuno Antunes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2192598697SNuno Antunes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2292598697SNuno Antunes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2392598697SNuno Antunes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2492598697SNuno Antunes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2592598697SNuno Antunes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2692598697SNuno Antunes  * SUCH DAMAGE.
2792598697SNuno Antunes  *
2892598697SNuno Antunes  * $FreeBSD: src/sys/netgraph/ng_eiface.c,v 1.39 2007/07/26 10:54:33 glebius Exp $
2992598697SNuno Antunes  */
3092598697SNuno Antunes 
3192598697SNuno Antunes #include <sys/param.h>
3292598697SNuno Antunes #include <sys/systm.h>
3392598697SNuno Antunes #include <sys/errno.h>
3492598697SNuno Antunes #include <sys/kernel.h>
3592598697SNuno Antunes #include <sys/malloc.h>
3692598697SNuno Antunes #include <sys/mbuf.h>
3792598697SNuno Antunes #include <sys/sockio.h>
3892598697SNuno Antunes #include <sys/socket.h>
3992598697SNuno Antunes #include <sys/syslog.h>
4092598697SNuno Antunes 
4192598697SNuno Antunes #include <net/if.h>
4292598697SNuno Antunes #include <net/if_types.h>
4392598697SNuno Antunes #include <net/ifq_var.h>
4492598697SNuno Antunes #include <net/netisr.h>
454ff4d99fSNuno Antunes #include <net/route.h>
4692598697SNuno Antunes 
4792598697SNuno Antunes #include <netgraph7/netgraph.h>
4892598697SNuno Antunes #include <netgraph7/ng_message.h>
4992598697SNuno Antunes #include <netgraph7/ng_parse.h>
5092598697SNuno Antunes #include "ng_eiface.h"
5192598697SNuno Antunes 
5292598697SNuno Antunes #include <net/bpf.h>
5392598697SNuno Antunes #include <net/ethernet.h>
5492598697SNuno Antunes #include <net/if_arp.h>
5592598697SNuno Antunes 
5692598697SNuno Antunes static const struct ng_cmdlist ng_eiface_cmdlist[] = {
5792598697SNuno Antunes 	{
5892598697SNuno Antunes 	  NGM_EIFACE_COOKIE,
5992598697SNuno Antunes 	  NGM_EIFACE_GET_IFNAME,
6092598697SNuno Antunes 	  "getifname",
6192598697SNuno Antunes 	  NULL,
6292598697SNuno Antunes 	  &ng_parse_string_type
6392598697SNuno Antunes 	},
6492598697SNuno Antunes 	{
6592598697SNuno Antunes 	  NGM_EIFACE_COOKIE,
6692598697SNuno Antunes 	  NGM_EIFACE_SET,
6792598697SNuno Antunes 	  "set",
6892598697SNuno Antunes 	  &ng_parse_enaddr_type,
6992598697SNuno Antunes 	  NULL
7092598697SNuno Antunes 	},
7192598697SNuno Antunes 	{ 0 }
7292598697SNuno Antunes };
7392598697SNuno Antunes 
7492598697SNuno Antunes /* Node private data */
7592598697SNuno Antunes struct ng_eiface_private {
7692598697SNuno Antunes 	struct ifnet	*ifp;		/* per-interface network data */
7792598697SNuno Antunes 	int		unit;		/* Interface unit number */
7892598697SNuno Antunes 	node_p		node;		/* Our netgraph node */
7992598697SNuno Antunes 	hook_p		ether;		/* Hook for ethernet stream */
8092598697SNuno Antunes };
8192598697SNuno Antunes typedef struct ng_eiface_private *priv_p;
8292598697SNuno Antunes 
8392598697SNuno Antunes /* Interface methods */
8492598697SNuno Antunes static void	ng_eiface_init(void *xsc);
8592598697SNuno Antunes static void	ng_eiface_start(struct ifnet *ifp, struct ifaltq_subque *);
8692598697SNuno Antunes static int	ng_eiface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data,
8792598697SNuno Antunes 				struct ucred *cr);
8892598697SNuno Antunes #ifdef DEBUG
8992598697SNuno Antunes static void	ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
9092598697SNuno Antunes #endif
9192598697SNuno Antunes 
9292598697SNuno Antunes /* Netgraph methods */
9392598697SNuno Antunes static int		ng_eiface_mod_event(module_t, int, void *);
9492598697SNuno Antunes static ng_constructor_t	ng_eiface_constructor;
9592598697SNuno Antunes static ng_rcvmsg_t	ng_eiface_rcvmsg;
9692598697SNuno Antunes static ng_shutdown_t	ng_eiface_rmnode;
9792598697SNuno Antunes static ng_newhook_t	ng_eiface_newhook;
9892598697SNuno Antunes static ng_rcvdata_t	ng_eiface_rcvdata;
9992598697SNuno Antunes static ng_disconnect_t	ng_eiface_disconnect;
10092598697SNuno Antunes 
10192598697SNuno Antunes /* Node type descriptor */
10292598697SNuno Antunes static struct ng_type typestruct = {
10392598697SNuno Antunes 	.version =	NG_ABI_VERSION,
10492598697SNuno Antunes 	.name =		NG_EIFACE_NODE_TYPE,
10592598697SNuno Antunes 	.mod_event =	ng_eiface_mod_event,
10692598697SNuno Antunes 	.constructor =	ng_eiface_constructor,
10792598697SNuno Antunes 	.rcvmsg =	ng_eiface_rcvmsg,
10892598697SNuno Antunes 	.shutdown =	ng_eiface_rmnode,
10992598697SNuno Antunes 	.newhook =	ng_eiface_newhook,
11092598697SNuno Antunes 	.rcvdata =	ng_eiface_rcvdata,
11192598697SNuno Antunes 	.disconnect =	ng_eiface_disconnect,
11292598697SNuno Antunes 	.cmdlist =	ng_eiface_cmdlist
11392598697SNuno Antunes };
11492598697SNuno Antunes NETGRAPH_INIT(eiface, &typestruct);
11592598697SNuno Antunes 
11692598697SNuno Antunes static int ng_eiface_next_unit;
11792598697SNuno Antunes 
11892598697SNuno Antunes /************************************************************************
11992598697SNuno Antunes 			INTERFACE STUFF
12092598697SNuno Antunes  ************************************************************************/
12192598697SNuno Antunes 
12292598697SNuno Antunes /*
12392598697SNuno Antunes  * Process an ioctl for the virtual interface
12492598697SNuno Antunes  */
12592598697SNuno Antunes static int
ng_eiface_ioctl(struct ifnet * ifp,u_long command,caddr_t data,struct ucred * cr)12692598697SNuno Antunes ng_eiface_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
12792598697SNuno Antunes {
12892598697SNuno Antunes 	struct ifreq *const ifr = (struct ifreq *)data;
12992598697SNuno Antunes 	int error = 0;
13092598697SNuno Antunes 
13192598697SNuno Antunes #ifdef DEBUG
13292598697SNuno Antunes 	ng_eiface_print_ioctl(ifp, command, data);
13392598697SNuno Antunes #endif
13492598697SNuno Antunes 	crit_enter();
13592598697SNuno Antunes 	switch (command) {
13692598697SNuno Antunes 
13792598697SNuno Antunes 	/* These two are mostly handled at a higher layer */
13892598697SNuno Antunes 	case SIOCSIFADDR:
13992598697SNuno Antunes 		error = ether_ioctl(ifp, command, data);
14092598697SNuno Antunes 		break;
14192598697SNuno Antunes 	case SIOCGIFADDR:
14292598697SNuno Antunes 		break;
14392598697SNuno Antunes 
14492598697SNuno Antunes 	/* Set flags */
14592598697SNuno Antunes 	case SIOCSIFFLAGS:
14692598697SNuno Antunes 		/*
14792598697SNuno Antunes 		 * If the interface is marked up and stopped, then start it.
14892598697SNuno Antunes 		 * If it is marked down and running, then stop it.
14992598697SNuno Antunes 		 */
15092598697SNuno Antunes 		if (ifp->if_flags & IFF_UP) {
15192598697SNuno Antunes 			if (!(ifp->if_flags & IFF_RUNNING)) {
15292598697SNuno Antunes 				ifq_clr_oactive(&ifp->if_snd);
15392598697SNuno Antunes 				ifp->if_flags |= IFF_RUNNING;
15492598697SNuno Antunes 			}
15592598697SNuno Antunes 		} else {
156*be2ac35fSSascha Wildner 			if (ifp->if_flags & IFF_RUNNING) {
15792598697SNuno Antunes 				ifq_clr_oactive(&ifp->if_snd);
15892598697SNuno Antunes 				ifp->if_flags &= ~(IFF_RUNNING);
15992598697SNuno Antunes 			}
160*be2ac35fSSascha Wildner 		}
16192598697SNuno Antunes 		break;
16292598697SNuno Antunes 
16392598697SNuno Antunes 	/* Set the interface MTU */
16492598697SNuno Antunes 	case SIOCSIFMTU:
16592598697SNuno Antunes 		if (ifr->ifr_mtu > NG_EIFACE_MTU_MAX ||
16692598697SNuno Antunes 		    ifr->ifr_mtu < NG_EIFACE_MTU_MIN)
16792598697SNuno Antunes 			error = EINVAL;
16892598697SNuno Antunes 		else
16992598697SNuno Antunes 			ifp->if_mtu = ifr->ifr_mtu;
17092598697SNuno Antunes 		break;
17192598697SNuno Antunes 
17292598697SNuno Antunes 	/* Stuff that's not supported */
17392598697SNuno Antunes 	case SIOCADDMULTI:
17492598697SNuno Antunes 	case SIOCDELMULTI:
17592598697SNuno Antunes 		error = 0;
17692598697SNuno Antunes 		break;
17792598697SNuno Antunes 	case SIOCSIFPHYS:
17892598697SNuno Antunes 		error = EOPNOTSUPP;
17992598697SNuno Antunes 		break;
18092598697SNuno Antunes 
18192598697SNuno Antunes 	default:
18292598697SNuno Antunes 		error = EINVAL;
18392598697SNuno Antunes 		break;
18492598697SNuno Antunes 	}
18592598697SNuno Antunes 	crit_exit();
18692598697SNuno Antunes 	return (error);
18792598697SNuno Antunes }
18892598697SNuno Antunes 
18992598697SNuno Antunes static void
ng_eiface_init(void * xsc)19092598697SNuno Antunes ng_eiface_init(void *xsc)
19192598697SNuno Antunes {
19292598697SNuno Antunes 	priv_p sc = xsc;
19392598697SNuno Antunes 	struct ifnet *ifp = sc->ifp;
19492598697SNuno Antunes 
19592598697SNuno Antunes 	crit_enter();
19692598697SNuno Antunes 
19792598697SNuno Antunes 	ifp->if_flags |= IFF_RUNNING;
19892598697SNuno Antunes 	ifq_clr_oactive(&ifp->if_snd);
19992598697SNuno Antunes 
20092598697SNuno Antunes 	crit_exit();
20192598697SNuno Antunes 
20292598697SNuno Antunes }
20392598697SNuno Antunes 
20492598697SNuno Antunes /*
20592598697SNuno Antunes  * We simply relay the packet to the "ether" hook, if it is connected.
20692598697SNuno Antunes  * We have been through the netgraph locking and are guaranteed to
20792598697SNuno Antunes  * be the only code running in this node at this time.
20892598697SNuno Antunes  */
20992598697SNuno Antunes static void
ng_eiface_start2(node_p node,hook_p hook,void * arg1,int arg2)21092598697SNuno Antunes ng_eiface_start2(node_p node, hook_p hook, void *arg1, int arg2)
21192598697SNuno Antunes {
21292598697SNuno Antunes 	struct ifnet *ifp = arg1;
21392598697SNuno Antunes 	const priv_p priv = (priv_p)ifp->if_softc;
21492598697SNuno Antunes 	int error = 0;
21592598697SNuno Antunes 	struct mbuf *m;
21692598697SNuno Antunes 
21792598697SNuno Antunes 	/* Check interface flags */
21892598697SNuno Antunes 
21992598697SNuno Antunes 	if (!((ifp->if_flags & IFF_UP) &&
22092598697SNuno Antunes 	    (ifp->if_flags & IFF_RUNNING)))
22192598697SNuno Antunes 		return;
22292598697SNuno Antunes 
22392598697SNuno Antunes 	for (;;) {
22492598697SNuno Antunes 		/*
22592598697SNuno Antunes 		 * Grab a packet to transmit.
22692598697SNuno Antunes 		 */
22792598697SNuno Antunes 		m = ifq_dequeue(&ifp->if_snd);
22892598697SNuno Antunes 
22992598697SNuno Antunes 		/* If there's nothing to send, break. */
23092598697SNuno Antunes 		if (m == NULL)
23192598697SNuno Antunes 			break;
23292598697SNuno Antunes 
23392598697SNuno Antunes 		/*
23492598697SNuno Antunes 		 * Berkeley packet filter.
23592598697SNuno Antunes 		 * Pass packet to bpf if there is a listener.
23692598697SNuno Antunes 		 * XXX is this safe? locking?
23792598697SNuno Antunes 		 */
23892598697SNuno Antunes 		BPF_MTAP(ifp, m);
23992598697SNuno Antunes 
24092598697SNuno Antunes 		if (ifp->if_flags & IFF_MONITOR) {
24192598697SNuno Antunes 			ifp->if_ipackets++;
24292598697SNuno Antunes 			m_freem(m);
24392598697SNuno Antunes 			continue;
24492598697SNuno Antunes 		}
24592598697SNuno Antunes 
24692598697SNuno Antunes 		/*
24792598697SNuno Antunes 		 * Send packet; if hook is not connected, mbuf will get
24892598697SNuno Antunes 		 * freed.
24992598697SNuno Antunes 		 */
25092598697SNuno Antunes 		NG_SEND_DATA_ONLY(error, priv->ether, m);
25192598697SNuno Antunes 
25292598697SNuno Antunes 		/* Update stats */
25392598697SNuno Antunes 		if (error == 0)
25492598697SNuno Antunes 			ifp->if_opackets++;
25592598697SNuno Antunes 		else
25692598697SNuno Antunes 			ifp->if_oerrors++;
25792598697SNuno Antunes 	}
25892598697SNuno Antunes 
25992598697SNuno Antunes 	ifq_clr_oactive(&ifp->if_snd);
26092598697SNuno Antunes 
26192598697SNuno Antunes 	return;
26292598697SNuno Antunes }
26392598697SNuno Antunes 
26492598697SNuno Antunes /*
26592598697SNuno Antunes  * This routine is called to deliver a packet out the interface.
26692598697SNuno Antunes  * We simply queue the netgraph version to be called when netgraph locking
26792598697SNuno Antunes  * allows it to happen.
26892598697SNuno Antunes  * Until we know what the rest of the networking code is doing for
26992598697SNuno Antunes  * locking, we don't know how we will interact with it.
27092598697SNuno Antunes  * Take comfort from the fact that the ifnet struct is part of our
27192598697SNuno Antunes  * private info and can't go away while we are queued.
27292598697SNuno Antunes  * [Though we don't know it is still there now....]
27392598697SNuno Antunes  * it is possible we don't gain anything from this because
27492598697SNuno Antunes  * we would like to get the mbuf and queue it as data
27592598697SNuno Antunes  * somehow, but we can't and if we did would we solve anything?
27692598697SNuno Antunes  */
27792598697SNuno Antunes static void
ng_eiface_start(struct ifnet * ifp,struct ifaltq_subque * ifsq __unused)27892598697SNuno Antunes ng_eiface_start(struct ifnet *ifp, struct ifaltq_subque *ifsq __unused)
27992598697SNuno Antunes {
28092598697SNuno Antunes 
28192598697SNuno Antunes 	const priv_p priv = (priv_p)ifp->if_softc;
28292598697SNuno Antunes 
28392598697SNuno Antunes 	/* Don't do anything if output is active */
28492598697SNuno Antunes 	if (ifq_is_oactive(&ifp->if_snd))
28592598697SNuno Antunes 		return;
28692598697SNuno Antunes 
28792598697SNuno Antunes 	ifq_set_oactive(&ifp->if_snd);
28892598697SNuno Antunes 
28992598697SNuno Antunes 	if (ng_send_fn(priv->node, NULL, &ng_eiface_start2, ifp, 0) != 0)
29092598697SNuno Antunes 		ifq_clr_oactive(&ifp->if_snd);
29192598697SNuno Antunes }
29292598697SNuno Antunes 
29392598697SNuno Antunes #ifdef DEBUG
29492598697SNuno Antunes /*
29592598697SNuno Antunes  * Display an ioctl to the virtual interface
29692598697SNuno Antunes  */
29792598697SNuno Antunes 
29892598697SNuno Antunes static void
ng_eiface_print_ioctl(struct ifnet * ifp,int command,caddr_t data)29992598697SNuno Antunes ng_eiface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
30092598697SNuno Antunes {
30192598697SNuno Antunes 	char *str;
30292598697SNuno Antunes 
30392598697SNuno Antunes 	switch (command & IOC_DIRMASK) {
30492598697SNuno Antunes 	case IOC_VOID:
30592598697SNuno Antunes 		str = "IO";
30692598697SNuno Antunes 		break;
30792598697SNuno Antunes 	case IOC_OUT:
30892598697SNuno Antunes 		str = "IOR";
30992598697SNuno Antunes 		break;
31092598697SNuno Antunes 	case IOC_IN:
31192598697SNuno Antunes 		str = "IOW";
31292598697SNuno Antunes 		break;
31392598697SNuno Antunes 	case IOC_INOUT:
31492598697SNuno Antunes 		str = "IORW";
31592598697SNuno Antunes 		break;
31692598697SNuno Antunes 	default:
31792598697SNuno Antunes 		str = "IO??";
31892598697SNuno Antunes 	}
31992598697SNuno Antunes 	log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
32092598697SNuno Antunes 	    ifp->if_xname,
32192598697SNuno Antunes 	    str,
32292598697SNuno Antunes 	    IOCGROUP(command),
32392598697SNuno Antunes 	    command & 0xff,
32492598697SNuno Antunes 	    IOCPARM_LEN(command));
32592598697SNuno Antunes }
32692598697SNuno Antunes #endif /* DEBUG */
32792598697SNuno Antunes 
32892598697SNuno Antunes /************************************************************************
32992598697SNuno Antunes 			NETGRAPH NODE STUFF
33092598697SNuno Antunes  ************************************************************************/
33192598697SNuno Antunes 
33292598697SNuno Antunes /*
33392598697SNuno Antunes  * Constructor for a node
33492598697SNuno Antunes  */
33592598697SNuno Antunes static int
ng_eiface_constructor(node_p node)33692598697SNuno Antunes ng_eiface_constructor(node_p node)
33792598697SNuno Antunes {
33892598697SNuno Antunes 	struct ifnet *ifp;
33992598697SNuno Antunes 	priv_p priv;
34092598697SNuno Antunes 	u_char eaddr[6] = {0,0,0,0,0,0};
34192598697SNuno Antunes 
34292598697SNuno Antunes 	/* Allocate node and interface private structures */
34392598697SNuno Antunes 	priv = kmalloc(sizeof(*priv), M_NETGRAPH,
34492598697SNuno Antunes 		       M_WAITOK | M_NULLOK | M_ZERO);
34592598697SNuno Antunes 	if (priv == NULL)
34692598697SNuno Antunes 		return (ENOMEM);
34792598697SNuno Antunes 
34892598697SNuno Antunes 	ifp = priv->ifp = if_alloc(IFT_ETHER);
34992598697SNuno Antunes 	if (ifp == NULL) {
35092598697SNuno Antunes 		kfree(priv, M_NETGRAPH);
35192598697SNuno Antunes 		return (ENOSPC);
35292598697SNuno Antunes 	}
35392598697SNuno Antunes 
35492598697SNuno Antunes 	/* Link them together */
35592598697SNuno Antunes 	ifp->if_softc = priv;
35692598697SNuno Antunes 
35792598697SNuno Antunes 	/* Get an interface unit number */
35892598697SNuno Antunes 	priv->unit = ng_eiface_next_unit++;
35992598697SNuno Antunes 
36092598697SNuno Antunes 	/* Link together node and private info */
36192598697SNuno Antunes 	NG_NODE_SET_PRIVATE(node, priv);
36292598697SNuno Antunes 	priv->node = node;
36392598697SNuno Antunes 
36492598697SNuno Antunes 	/* Initialize interface structure */
36592598697SNuno Antunes 	if_initname(ifp, NG_EIFACE_EIFACE_NAME, priv->unit);
36692598697SNuno Antunes 	ifp->if_init = ng_eiface_init;
36792598697SNuno Antunes /*
36892598697SNuno Antunes 	ifp->if_output = ether_output;
36992598697SNuno Antunes */
37092598697SNuno Antunes 	ifp->if_start = ng_eiface_start;
37192598697SNuno Antunes 	ifp->if_ioctl = ng_eiface_ioctl;
37292598697SNuno Antunes 	ifp->if_watchdog = NULL;
37392598697SNuno Antunes 	ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
37492598697SNuno Antunes 	ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
37592598697SNuno Antunes 
37692598697SNuno Antunes #if 0
37792598697SNuno Antunes 	/* Give this node name */
37892598697SNuno Antunes 	bzero(ifname, sizeof(ifname));
379a62226e4SSascha Wildner 	ksprintf(ifname, "if%s", ifp->if_xname);
38092598697SNuno Antunes 	(void)ng_name_node(node, ifname);
38192598697SNuno Antunes #endif
38292598697SNuno Antunes 
38392598697SNuno Antunes 	/* Attach the interface */
38492598697SNuno Antunes 	ether_ifattach(ifp, eaddr, NULL);
38592598697SNuno Antunes 
38692598697SNuno Antunes 	/* Done */
38792598697SNuno Antunes 	return (0);
38892598697SNuno Antunes }
38992598697SNuno Antunes 
39092598697SNuno Antunes /*
39192598697SNuno Antunes  * Give our ok for a hook to be added
39292598697SNuno Antunes  */
39392598697SNuno Antunes static int
ng_eiface_newhook(node_p node,hook_p hook,const char * name)39492598697SNuno Antunes ng_eiface_newhook(node_p node, hook_p hook, const char *name)
39592598697SNuno Antunes {
39692598697SNuno Antunes 	priv_p priv = NG_NODE_PRIVATE(node);
39792598697SNuno Antunes 	struct ifnet *ifp = priv->ifp;
39892598697SNuno Antunes 
39992598697SNuno Antunes 	if (strcmp(name, NG_EIFACE_HOOK_ETHER))
40092598697SNuno Antunes 		return (EPFNOSUPPORT);
40192598697SNuno Antunes 	if (priv->ether != NULL)
40292598697SNuno Antunes 		return (EISCONN);
40392598697SNuno Antunes 	priv->ether = hook;
40492598697SNuno Antunes 	NG_HOOK_SET_PRIVATE(hook, &priv->ether);
40592598697SNuno Antunes 
40692598697SNuno Antunes 	ifp->if_link_state = LINK_STATE_UP;
40792598697SNuno Antunes 	if_link_state_change(ifp);
40892598697SNuno Antunes 
40992598697SNuno Antunes 	return (0);
41092598697SNuno Antunes }
41192598697SNuno Antunes 
41292598697SNuno Antunes /*
41392598697SNuno Antunes  * Receive a control message
41492598697SNuno Antunes  */
41592598697SNuno Antunes static int
ng_eiface_rcvmsg(node_p node,item_p item,hook_p lasthook)41692598697SNuno Antunes ng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook)
41792598697SNuno Antunes {
41892598697SNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
41992598697SNuno Antunes 	struct ifnet *const ifp = priv->ifp;
42092598697SNuno Antunes 	struct ng_mesg *resp = NULL;
42192598697SNuno Antunes 	int error = 0;
42292598697SNuno Antunes 	struct ng_mesg *msg;
42392598697SNuno Antunes 
42492598697SNuno Antunes 	NGI_GET_MSG(item, msg);
42592598697SNuno Antunes 	switch (msg->header.typecookie) {
42692598697SNuno Antunes 	case NGM_EIFACE_COOKIE:
42792598697SNuno Antunes 		switch (msg->header.cmd) {
42892598697SNuno Antunes 
42992598697SNuno Antunes 		case NGM_EIFACE_SET:
43092598697SNuno Antunes 		    {
43192598697SNuno Antunes 			if (msg->header.arglen != ETHER_ADDR_LEN) {
43292598697SNuno Antunes 				error = EINVAL;
43392598697SNuno Antunes 				break;
43492598697SNuno Antunes 			}
43592598697SNuno Antunes 			error = if_setlladdr(priv->ifp,
43692598697SNuno Antunes 			    (u_char *)msg->data, ETHER_ADDR_LEN);
43792598697SNuno Antunes 			break;
43892598697SNuno Antunes 		    }
43992598697SNuno Antunes 
44092598697SNuno Antunes 		case NGM_EIFACE_GET_IFNAME:
44192598697SNuno Antunes 			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_WAITOK | M_NULLOK);
44292598697SNuno Antunes 			if (resp == NULL) {
44392598697SNuno Antunes 				error = ENOMEM;
44492598697SNuno Antunes 				break;
44592598697SNuno Antunes 			}
44692598697SNuno Antunes 			strlcpy(resp->data, ifp->if_xname, IFNAMSIZ);
44792598697SNuno Antunes 			break;
44892598697SNuno Antunes 
44992598697SNuno Antunes 		case NGM_EIFACE_GET_IFADDRS:
45092598697SNuno Antunes 		    {
45192598697SNuno Antunes 			struct ifaddr_container *ifac;
45292598697SNuno Antunes 			caddr_t ptr;
45392598697SNuno Antunes 			int buflen;
45492598697SNuno Antunes 
4554ff4d99fSNuno Antunes #define SA_SIZE(s)	RT_ROUNDUP((s)->sa_len)
45692598697SNuno Antunes 
45792598697SNuno Antunes 			/* Determine size of response and allocate it */
45892598697SNuno Antunes 			buflen = 0;
45992598697SNuno Antunes 			TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid],
4609a74b592SSepherosa Ziehau 				      ifa_link) {
4619a74b592SSepherosa Ziehau 				/* Ignore marker */
4629a74b592SSepherosa Ziehau 				if (ifac->ifa->ifa_addr->sa_family == AF_UNSPEC)
4639a74b592SSepherosa Ziehau 					continue;
46492598697SNuno Antunes 				buflen += SA_SIZE(ifac->ifa->ifa_addr);
4659a74b592SSepherosa Ziehau 			}
46692598697SNuno Antunes 			NG_MKRESPONSE(resp, msg, buflen, M_WAITOK | M_NULLOK);
46792598697SNuno Antunes 			if (resp == NULL) {
46892598697SNuno Antunes 				error = ENOMEM;
46992598697SNuno Antunes 				break;
47092598697SNuno Antunes 			}
47192598697SNuno Antunes 
47292598697SNuno Antunes 			/* Add addresses */
47392598697SNuno Antunes 			ptr = resp->data;
47492598697SNuno Antunes 			TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid],
47592598697SNuno Antunes 				      ifa_link) {
47692598697SNuno Antunes 				struct ifaddr *ifa = ifac->ifa;
47792598697SNuno Antunes 				const int len = SA_SIZE(ifa->ifa_addr);
47892598697SNuno Antunes 
4799a74b592SSepherosa Ziehau 				/* Ignore marker */
4809a74b592SSepherosa Ziehau 				if (ifa->ifa_addr->sa_family == AF_UNSPEC)
4819a74b592SSepherosa Ziehau 					continue;
4829a74b592SSepherosa Ziehau 
48392598697SNuno Antunes 				if (buflen < len) {
48492598697SNuno Antunes 					log(LOG_ERR, "%s: len changed?\n",
48592598697SNuno Antunes 					    ifp->if_xname);
48692598697SNuno Antunes 					break;
48792598697SNuno Antunes 				}
48892598697SNuno Antunes 				bcopy(ifa->ifa_addr, ptr, len);
48992598697SNuno Antunes 				ptr += len;
49092598697SNuno Antunes 				buflen -= len;
49192598697SNuno Antunes 			}
49292598697SNuno Antunes 			break;
49392598697SNuno Antunes #undef SA_SIZE
49492598697SNuno Antunes 		    }
49592598697SNuno Antunes 
49692598697SNuno Antunes 		default:
49792598697SNuno Antunes 			error = EINVAL;
49892598697SNuno Antunes 			break;
49992598697SNuno Antunes 		} /* end of inner switch() */
50092598697SNuno Antunes 		break;
50192598697SNuno Antunes 	case NGM_FLOW_COOKIE:
50292598697SNuno Antunes 		switch (msg->header.cmd) {
50392598697SNuno Antunes 		case NGM_LINK_IS_UP:
50492598697SNuno Antunes 			ifp->if_link_state = LINK_STATE_UP;
50592598697SNuno Antunes 			if_link_state_change(ifp);
50692598697SNuno Antunes 			break;
50792598697SNuno Antunes 		case NGM_LINK_IS_DOWN:
50892598697SNuno Antunes 			ifp->if_link_state = LINK_STATE_DOWN;
50992598697SNuno Antunes 			if_link_state_change(ifp);
51092598697SNuno Antunes 			break;
51192598697SNuno Antunes 		default:
51292598697SNuno Antunes 			break;
51392598697SNuno Antunes 		}
51492598697SNuno Antunes 		break;
51592598697SNuno Antunes 	default:
51692598697SNuno Antunes 		error = EINVAL;
51792598697SNuno Antunes 		break;
51892598697SNuno Antunes 	}
51992598697SNuno Antunes 	NG_RESPOND_MSG(error, node, item, resp);
52092598697SNuno Antunes 	NG_FREE_MSG(msg);
52192598697SNuno Antunes 	return (error);
52292598697SNuno Antunes }
52392598697SNuno Antunes 
52492598697SNuno Antunes /*
52592598697SNuno Antunes  * Receive data from a hook. Pass the packet to the ether_input routine.
52692598697SNuno Antunes  */
52792598697SNuno Antunes static int
ng_eiface_rcvdata(hook_p hook,item_p item)52892598697SNuno Antunes ng_eiface_rcvdata(hook_p hook, item_p item)
52992598697SNuno Antunes {
53092598697SNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
53192598697SNuno Antunes 	struct ifnet *const ifp = priv->ifp;
53292598697SNuno Antunes 	struct mbuf *m;
53392598697SNuno Antunes 
53492598697SNuno Antunes 	NGI_GET_M(item, m);
53592598697SNuno Antunes 	NG_FREE_ITEM(item);
53692598697SNuno Antunes 
53792598697SNuno Antunes 	if (!((ifp->if_flags & IFF_UP) &&
53892598697SNuno Antunes 	    (ifp->if_flags & IFF_RUNNING))) {
53992598697SNuno Antunes 		NG_FREE_M(m);
54092598697SNuno Antunes 		return (ENETDOWN);
54192598697SNuno Antunes 	}
54292598697SNuno Antunes 
54392598697SNuno Antunes 	if (m->m_len < ETHER_HDR_LEN) {
54492598697SNuno Antunes 		m = m_pullup(m, ETHER_HDR_LEN);
54592598697SNuno Antunes 		if (m == NULL)
54692598697SNuno Antunes 			return (EINVAL);
54792598697SNuno Antunes 	}
54892598697SNuno Antunes 
54992598697SNuno Antunes 	/* Note receiving interface */
55092598697SNuno Antunes 	m->m_pkthdr.rcvif = ifp;
55192598697SNuno Antunes 
55292598697SNuno Antunes 	/* Update interface stats */
55392598697SNuno Antunes 	ifp->if_ipackets++;
55492598697SNuno Antunes 
55592598697SNuno Antunes 	ifp->if_input(ifp, m, NULL, -1);
55692598697SNuno Antunes 
55792598697SNuno Antunes 	/* Done */
55892598697SNuno Antunes 	return (0);
55992598697SNuno Antunes }
56092598697SNuno Antunes 
56192598697SNuno Antunes /*
56292598697SNuno Antunes  * Shutdown processing.
56392598697SNuno Antunes  */
56492598697SNuno Antunes static int
ng_eiface_rmnode(node_p node)56592598697SNuno Antunes ng_eiface_rmnode(node_p node)
56692598697SNuno Antunes {
56792598697SNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(node);
56892598697SNuno Antunes 	struct ifnet *const ifp = priv->ifp;
56992598697SNuno Antunes 
57092598697SNuno Antunes 	ether_ifdetach(ifp);
57192598697SNuno Antunes 	if_free(ifp);
57292598697SNuno Antunes 	kfree(priv, M_NETGRAPH);
57392598697SNuno Antunes 	NG_NODE_SET_PRIVATE(node, NULL);
57492598697SNuno Antunes 	NG_NODE_UNREF(node);
57592598697SNuno Antunes 	return (0);
57692598697SNuno Antunes }
57792598697SNuno Antunes 
57892598697SNuno Antunes /*
57992598697SNuno Antunes  * Hook disconnection
58092598697SNuno Antunes  */
58192598697SNuno Antunes static int
ng_eiface_disconnect(hook_p hook)58292598697SNuno Antunes ng_eiface_disconnect(hook_p hook)
58392598697SNuno Antunes {
58492598697SNuno Antunes 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
58592598697SNuno Antunes 
58692598697SNuno Antunes 	priv->ether = NULL;
58792598697SNuno Antunes 	return (0);
58892598697SNuno Antunes }
58992598697SNuno Antunes 
59092598697SNuno Antunes /*
59192598697SNuno Antunes  * Handle loading and unloading for this node type.
59292598697SNuno Antunes  */
59392598697SNuno Antunes static int
ng_eiface_mod_event(module_t mod,int event,void * data)59492598697SNuno Antunes ng_eiface_mod_event(module_t mod, int event, void *data)
59592598697SNuno Antunes {
59692598697SNuno Antunes 	int error = 0;
59792598697SNuno Antunes 
59892598697SNuno Antunes 	switch (event) {
59992598697SNuno Antunes 	case MOD_LOAD:
60092598697SNuno Antunes 		break;
60192598697SNuno Antunes 	case MOD_UNLOAD:
60292598697SNuno Antunes 		break;
60392598697SNuno Antunes 	default:
60492598697SNuno Antunes 		error = EOPNOTSUPP;
60592598697SNuno Antunes 		break;
60692598697SNuno Antunes 	}
60792598697SNuno Antunes 	return (error);
60892598697SNuno Antunes }
609