ng_eiface.c revision 143604
1254721Semaste/*-
2254721Semaste *
3254721Semaste * Copyright (c) 1999-2001, Vitaly V Belekhov
4254721Semaste * All rights reserved.
5254721Semaste *
6254721Semaste * Redistribution and use in source and binary forms, with or without
7254721Semaste * modification, are permitted provided that the following conditions
8254721Semaste * are met:
9254721Semaste * 1. Redistributions of source code must retain the above copyright
10254721Semaste *    notice unmodified, this list of conditions, and the following
11254721Semaste *    disclaimer.
12254721Semaste * 2. Redistributions in binary form must reproduce the above copyright
13254721Semaste *    notice, this list of conditions and the following disclaimer in the
14254721Semaste *    documentation and/or other materials provided with the distribution.
15254721Semaste *
16254721Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19254721Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26254721Semaste * SUCH DAMAGE.
27254721Semaste *
28254721Semaste * $FreeBSD: head/sys/netgraph/ng_eiface.c 143604 2005-03-14 20:11:29Z glebius $
29254721Semaste */
30254721Semaste
31254721Semaste#include <sys/param.h>
32254721Semaste#include <sys/systm.h>
33254721Semaste#include <sys/errno.h>
34254721Semaste#include <sys/kernel.h>
35254721Semaste#include <sys/malloc.h>
36254721Semaste#include <sys/mbuf.h>
37254721Semaste#include <sys/errno.h>
38254721Semaste#include <sys/sockio.h>
39254721Semaste#include <sys/socket.h>
40254721Semaste#include <sys/syslog.h>
41254721Semaste
42254721Semaste#include <net/if.h>
43254721Semaste#include <net/if_dl.h>
44254721Semaste#include <net/if_types.h>
45254721Semaste#include <net/netisr.h>
46254721Semaste
47254721Semaste#include <netgraph/ng_message.h>
48254721Semaste#include <netgraph/netgraph.h>
49254721Semaste#include <netgraph/ng_parse.h>
50254721Semaste#include <netgraph/ng_eiface.h>
51254721Semaste
52254721Semaste#include <net/bpf.h>
53254721Semaste#include <net/ethernet.h>
54254721Semaste#include <net/if_arp.h>
55254721Semaste
56254721Semastestatic const struct ng_cmdlist ng_eiface_cmdlist[] = {
57254721Semaste	{
58254721Semaste	  NGM_EIFACE_COOKIE,
59254721Semaste	  NGM_EIFACE_GET_IFNAME,
60254721Semaste	  "getifname",
61254721Semaste	  NULL,
62254721Semaste	  &ng_parse_string_type
63254721Semaste	},
64254721Semaste	{
65254721Semaste	  NGM_EIFACE_COOKIE,
66254721Semaste	  NGM_EIFACE_SET,
67254721Semaste	  "set",
68254721Semaste	  &ng_parse_enaddr_type,
69254721Semaste	  NULL
70254721Semaste	},
71254721Semaste	{ 0 }
72254721Semaste};
73254721Semaste
74254721Semaste/* Node private data */
75254721Semastestruct ng_eiface_private {
76254721Semaste	struct arpcom	arpcom;		/* per-interface network data */
77254721Semaste	struct ifnet	*ifp;		/* This interface */
78254721Semaste	int		unit;		/* Interface unit number */
79254721Semaste	node_p		node;		/* Our netgraph node */
80254721Semaste	hook_p		ether;		/* Hook for ethernet stream */
81254721Semaste};
82254721Semastetypedef struct ng_eiface_private *priv_p;
83254721Semaste
84254721Semaste/* Interface methods */
85254721Semastestatic void	ng_eiface_init(void *xsc);
86254721Semastestatic void	ng_eiface_start(struct ifnet *ifp);
87254721Semastestatic int	ng_eiface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
88254721Semaste#ifdef DEBUG
89254721Semastestatic void	ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
90254721Semaste#endif
91254721Semaste
92254721Semaste/* Netgraph methods */
93254721Semastestatic int		ng_eiface_mod_event(module_t, int, void *);
94254721Semastestatic ng_constructor_t	ng_eiface_constructor;
95254721Semastestatic ng_rcvmsg_t	ng_eiface_rcvmsg;
96254721Semastestatic ng_shutdown_t	ng_eiface_rmnode;
97254721Semastestatic ng_newhook_t	ng_eiface_newhook;
98254721Semastestatic ng_rcvdata_t	ng_eiface_rcvdata;
99254721Semastestatic ng_connect_t	ng_eiface_connect;
100254721Semastestatic ng_disconnect_t	ng_eiface_disconnect;
101254721Semaste
102254721Semaste/* Node type descriptor */
103254721Semastestatic struct ng_type typestruct = {
104254721Semaste	.version =	NG_ABI_VERSION,
105254721Semaste	.name =		NG_EIFACE_NODE_TYPE,
106254721Semaste	.mod_event =	ng_eiface_mod_event,
107254721Semaste	.constructor =	ng_eiface_constructor,
108254721Semaste	.rcvmsg =	ng_eiface_rcvmsg,
109254721Semaste	.shutdown =	ng_eiface_rmnode,
110254721Semaste	.newhook =	ng_eiface_newhook,
111254721Semaste	.connect =	ng_eiface_connect,
112254721Semaste	.rcvdata =	ng_eiface_rcvdata,
113254721Semaste	.disconnect =	ng_eiface_disconnect,
114254721Semaste	.cmdlist =	ng_eiface_cmdlist
115254721Semaste};
116254721SemasteNETGRAPH_INIT(eiface, &typestruct);
117254721Semaste
118254721Semastestatic struct unrhdr	*ng_eiface_unit;
119254721Semaste
120254721Semaste/************************************************************************
121254721Semaste			INTERFACE STUFF
122254721Semaste ************************************************************************/
123254721Semaste
124254721Semaste/*
125254721Semaste * Process an ioctl for the virtual interface
126254721Semaste */
127254721Semastestatic int
128254721Semasteng_eiface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
129254721Semaste{
130254721Semaste	struct ifreq *const ifr = (struct ifreq *)data;
131254721Semaste	int s, error = 0;
132254721Semaste
133254721Semaste#ifdef DEBUG
134254721Semaste	ng_eiface_print_ioctl(ifp, command, data);
135254721Semaste#endif
136254721Semaste	s = splimp();
137254721Semaste	switch (command) {
138254721Semaste
139254721Semaste	/* These two are mostly handled at a higher layer */
140254721Semaste	case SIOCSIFADDR:
141254721Semaste		error = ether_ioctl(ifp, command, data);
142254721Semaste		break;
143254721Semaste	case SIOCGIFADDR:
144254721Semaste		break;
145254721Semaste
146254721Semaste	/* Set flags */
147254721Semaste	case SIOCSIFFLAGS:
148254721Semaste		/*
149254721Semaste		 * If the interface is marked up and stopped, then start it.
150254721Semaste		 * If it is marked down and running, then stop it.
151254721Semaste		 */
152254721Semaste		if (ifr->ifr_flags & IFF_UP) {
153254721Semaste			if (!(ifp->if_flags & IFF_RUNNING)) {
154254721Semaste				ifp->if_flags &= ~(IFF_OACTIVE);
155254721Semaste				ifp->if_flags |= IFF_RUNNING;
156254721Semaste			}
157254721Semaste		} else {
158254721Semaste			if (ifp->if_flags & IFF_RUNNING)
159254721Semaste				ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
160254721Semaste		}
161254721Semaste		break;
162254721Semaste
163254721Semaste	/* Set the interface MTU */
164254721Semaste	case SIOCSIFMTU:
165254721Semaste		if (ifr->ifr_mtu > NG_EIFACE_MTU_MAX ||
166254721Semaste		    ifr->ifr_mtu < NG_EIFACE_MTU_MIN)
167254721Semaste			error = EINVAL;
168254721Semaste		else
169254721Semaste			ifp->if_mtu = ifr->ifr_mtu;
170254721Semaste		break;
171254721Semaste
172254721Semaste	/* Stuff that's not supported */
173254721Semaste	case SIOCADDMULTI:
174254721Semaste	case SIOCDELMULTI:
175254721Semaste		error = 0;
176254721Semaste		break;
177254721Semaste	case SIOCSIFPHYS:
178254721Semaste		error = EOPNOTSUPP;
179254721Semaste		break;
180254721Semaste
181254721Semaste	default:
182254721Semaste		error = EINVAL;
183254721Semaste		break;
184254721Semaste	}
185254721Semaste	splx(s);
186254721Semaste	return (error);
187254721Semaste}
188254721Semaste
189254721Semastestatic void
190254721Semasteng_eiface_init(void *xsc)
191254721Semaste{
192254721Semaste	priv_p sc = xsc;
193254721Semaste	struct ifnet *ifp = sc->ifp;
194254721Semaste	int s;
195254721Semaste
196254721Semaste	s = splimp();
197254721Semaste
198254721Semaste	ifp->if_flags |= IFF_RUNNING;
199254721Semaste	ifp->if_flags &= ~IFF_OACTIVE;
200254721Semaste
201254721Semaste	splx(s);
202254721Semaste}
203254721Semaste
204254721Semaste/*
205254721Semaste * We simply relay the packet to the "ether" hook, if it is connected.
206254721Semaste * We have been through the netgraph locking and are guaranteed to
207254721Semaste * be the only code running in this node at this time.
208254721Semaste */
209254721Semastestatic void
210254721Semasteng_eiface_start2(node_p node, hook_p hook, void *arg1, int arg2)
211254721Semaste{
212254721Semaste	struct ifnet *ifp = arg1;
213254721Semaste	const priv_p priv = (priv_p)ifp->if_softc;
214254721Semaste	int len, error = 0;
215254721Semaste	struct mbuf *m;
216254721Semaste
217254721Semaste	/* Check interface flags */
218254721Semaste	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
219254721Semaste		return;
220254721Semaste
221254721Semaste	/* Don't do anything if output is active */
222254721Semaste	if (ifp->if_flags & IFF_OACTIVE)
223254721Semaste		return;
224254721Semaste
225254721Semaste	ifp->if_flags |= IFF_OACTIVE;
226254721Semaste
227254721Semaste	/*
228254721Semaste	 * Grab a packet to transmit.
229254721Semaste	 */
230254721Semaste	IF_DEQUEUE(&ifp->if_snd, m);
231254721Semaste
232254721Semaste	/* If there's nothing to send, return. */
233254721Semaste	if (m == NULL) {
234254721Semaste		ifp->if_flags &= ~IFF_OACTIVE;
235254721Semaste		return;
236254721Semaste	}
237254721Semaste
238254721Semaste	/*
239254721Semaste	 * Berkeley packet filter.
240254721Semaste	 * Pass packet to bpf if there is a listener.
241254721Semaste	 * XXX is this safe? locking?
242254721Semaste	 */
243254721Semaste	BPF_MTAP(ifp, m);
244254721Semaste
245254721Semaste	/* Copy length before the mbuf gets invalidated */
246254721Semaste	len = m->m_pkthdr.len;
247254721Semaste
248254721Semaste	/*
249254721Semaste	 * Send packet; if hook is not connected, mbuf will get
250254721Semaste	 * freed.
251254721Semaste	 */
252254721Semaste	NG_SEND_DATA_ONLY(error, priv->ether, m);
253254721Semaste
254254721Semaste	/* Update stats */
255254721Semaste	if (error == 0) {
256254721Semaste		ifp->if_obytes += len;
257254721Semaste		ifp->if_opackets++;
258254721Semaste	}
259254721Semaste
260254721Semaste	ifp->if_flags &= ~IFF_OACTIVE;
261254721Semaste
262254721Semaste	return;
263254721Semaste}
264254721Semaste
265254721Semaste/*
266254721Semaste * This routine is called to deliver a packet out the interface.
267254721Semaste * We simply queue the netgraph version to be called when netgraph locking
268254721Semaste * allows it to happen.
269254721Semaste * Until we know what the rest of the networking code is doing for
270254721Semaste * locking, we don't know how we will interact with it.
271254721Semaste * Take comfort from the fact that the ifnet struct is part of our
272254721Semaste * private info and can't go away while we are queued.
273254721Semaste * [Though we don't know it is still there now....]
274254721Semaste * it is possible we don't gain anything from this because
275254721Semaste * we would like to get the mbuf and queue it as data
276254721Semaste * somehow, but we can't and if we did would we solve anything?
277254721Semaste */
278254721Semastestatic void
279254721Semasteng_eiface_start(struct ifnet *ifp)
280254721Semaste{
281254721Semaste
282254721Semaste	const priv_p priv = (priv_p)ifp->if_softc;
283254721Semaste
284254721Semaste	ng_send_fn(priv->node, NULL, &ng_eiface_start2, ifp, 0);
285254721Semaste}
286254721Semaste
287254721Semaste#ifdef DEBUG
288254721Semaste/*
289254721Semaste * Display an ioctl to the virtual interface
290254721Semaste */
291254721Semaste
292254721Semastestatic void
293254721Semasteng_eiface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
294254721Semaste{
295254721Semaste	char *str;
296254721Semaste
297254721Semaste	switch (command & IOC_DIRMASK) {
298254721Semaste	case IOC_VOID:
299254721Semaste		str = "IO";
300254721Semaste		break;
301254721Semaste	case IOC_OUT:
302254721Semaste		str = "IOR";
303254721Semaste		break;
304254721Semaste	case IOC_IN:
305254721Semaste		str = "IOW";
306254721Semaste		break;
307254721Semaste	case IOC_INOUT:
308254721Semaste		str = "IORW";
309254721Semaste		break;
310254721Semaste	default:
311254721Semaste		str = "IO??";
312254721Semaste	}
313254721Semaste	log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
314254721Semaste	    ifp->if_xname,
315254721Semaste	    str,
316254721Semaste	    IOCGROUP(command),
317254721Semaste	    command & 0xff,
318254721Semaste	    IOCPARM_LEN(command));
319254721Semaste}
320254721Semaste#endif /* DEBUG */
321254721Semaste
322254721Semaste/************************************************************************
323254721Semaste			NETGRAPH NODE STUFF
324254721Semaste ************************************************************************/
325254721Semaste
326254721Semaste/*
327254721Semaste * Constructor for a node
328254721Semaste */
329254721Semastestatic int
330254721Semasteng_eiface_constructor(node_p node)
331254721Semaste{
332254721Semaste	struct ifnet *ifp;
333254721Semaste	priv_p priv;
334254721Semaste
335254721Semaste	/* Allocate node and interface private structures */
336254721Semaste	MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
337254721Semaste	if (priv == NULL)
338254721Semaste		return (ENOMEM);
339254721Semaste
340254721Semaste	ifp = &(priv->arpcom.ac_if);
341254721Semaste
342254721Semaste	/* Link them together */
343254721Semaste	ifp->if_softc = priv;
344254721Semaste	priv->ifp = ifp;
345254721Semaste
346254721Semaste	/* Get an interface unit number */
347254721Semaste	priv->unit = alloc_unr(ng_eiface_unit);
348254721Semaste
349254721Semaste	/* Link together node and private info */
350254721Semaste	NG_NODE_SET_PRIVATE(node, priv);
351254721Semaste	priv->node = node;
352254721Semaste
353254721Semaste	/* Initialize interface structure */
354254721Semaste	if_initname(ifp, NG_EIFACE_EIFACE_NAME, priv->unit);
355254721Semaste	ifp->if_init = ng_eiface_init;
356254721Semaste	ifp->if_output = ether_output;
357254721Semaste	ifp->if_start = ng_eiface_start;
358254721Semaste	ifp->if_ioctl = ng_eiface_ioctl;
359254721Semaste	ifp->if_watchdog = NULL;
360254721Semaste	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
361254721Semaste	ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
362254721Semaste
363254721Semaste#if 0
364254721Semaste	/* Give this node name */
365254721Semaste	bzero(ifname, sizeof(ifname));
366254721Semaste	sprintf(ifname, "if%s", ifp->if_xname);
367254721Semaste	(void)ng_name_node(node, ifname);
368254721Semaste#endif
369254721Semaste
370254721Semaste	/* Attach the interface */
371254721Semaste	ether_ifattach(ifp, priv->arpcom.ac_enaddr);
372254721Semaste
373254721Semaste	/* Done */
374254721Semaste	return (0);
375254721Semaste}
376254721Semaste
377254721Semaste/*
378254721Semaste * Give our ok for a hook to be added
379254721Semaste */
380254721Semastestatic int
381254721Semasteng_eiface_newhook(node_p node, hook_p hook, const char *name)
382254721Semaste{
383254721Semaste	priv_p priv = NG_NODE_PRIVATE(node);
384254721Semaste
385254721Semaste	if (strcmp(name, NG_EIFACE_HOOK_ETHER))
386254721Semaste		return (EPFNOSUPPORT);
387254721Semaste	if (priv->ether != NULL)
388254721Semaste		return (EISCONN);
389254721Semaste	priv->ether = hook;
390254721Semaste	NG_HOOK_SET_PRIVATE(hook, &priv->ether);
391254721Semaste
392254721Semaste	return (0);
393254721Semaste}
394254721Semaste
395254721Semaste/*
396254721Semaste * Receive a control message
397254721Semaste */
398254721Semastestatic int
399254721Semasteng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook)
400254721Semaste{
401254721Semaste	const priv_p priv = NG_NODE_PRIVATE(node);
402254721Semaste	struct ifnet *const ifp = priv->ifp;
403254721Semaste	struct ng_mesg *resp = NULL;
404254721Semaste	int error = 0;
405254721Semaste	struct ng_mesg *msg;
406254721Semaste
407254721Semaste	NGI_GET_MSG(item, msg);
408254721Semaste	switch (msg->header.typecookie) {
409254721Semaste	case NGM_EIFACE_COOKIE:
410254721Semaste		switch (msg->header.cmd) {
411254721Semaste
412254721Semaste		case NGM_EIFACE_SET:
413254721Semaste		    {
414254721Semaste			struct ether_addr *eaddr;
415254721Semaste			struct ifaddr *ifa;
416254721Semaste			struct sockaddr_dl *sdl;
417254721Semaste
418254721Semaste			if (msg->header.arglen != sizeof(struct ether_addr)) {
419254721Semaste				error = EINVAL;
420254721Semaste				break;
421254721Semaste			}
422254721Semaste			eaddr = (struct ether_addr *)(msg->data);
423254721Semaste			bcopy(eaddr, priv->arpcom.ac_enaddr, ETHER_ADDR_LEN);
424254721Semaste
425254721Semaste			/* And put it in the ifaddr list */
426254721Semaste			TAILQ_FOREACH(ifa, &(ifp->if_addrhead), ifa_link) {
427254721Semaste				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
428254721Semaste				if (sdl->sdl_type == IFT_ETHER) {
429254721Semaste					bcopy((IFP2AC(ifp))->ac_enaddr,
430254721Semaste						LLADDR(sdl), ifp->if_addrlen);
431254721Semaste					break;
432254721Semaste				}
433254721Semaste			}
434254721Semaste			break;
435254721Semaste		    }
436254721Semaste
437254721Semaste		case NGM_EIFACE_GET_IFNAME:
438254721Semaste			NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
439254721Semaste			if (resp == NULL) {
440254721Semaste				error = ENOMEM;
441254721Semaste				break;
442254721Semaste			}
443254721Semaste			strlcpy(resp->data, ifp->if_xname, IFNAMSIZ);
444254721Semaste			break;
445254721Semaste
446254721Semaste		case NGM_EIFACE_GET_IFADDRS:
447254721Semaste		    {
448254721Semaste			struct ifaddr *ifa;
449254721Semaste			caddr_t ptr;
450254721Semaste			int buflen;
451254721Semaste
452254721Semaste#define SA_SIZE(s)	((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len)
453254721Semaste
454254721Semaste			/* Determine size of response and allocate it */
455254721Semaste			buflen = 0;
456254721Semaste			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
457254721Semaste				buflen += SA_SIZE(ifa->ifa_addr);
458254721Semaste			NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT);
459254721Semaste			if (resp == NULL) {
460254721Semaste				error = ENOMEM;
461254721Semaste				break;
462254721Semaste			}
463254721Semaste
464254721Semaste			/* Add addresses */
465254721Semaste			ptr = resp->data;
466254721Semaste			TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
467254721Semaste				const int len = SA_SIZE(ifa->ifa_addr);
468254721Semaste
469254721Semaste				if (buflen < len) {
470254721Semaste					log(LOG_ERR, "%s: len changed?\n",
471254721Semaste					    ifp->if_xname);
472254721Semaste					break;
473254721Semaste				}
474254721Semaste				bcopy(ifa->ifa_addr, ptr, len);
475254721Semaste				ptr += len;
476254721Semaste				buflen -= len;
477254721Semaste			}
478254721Semaste			break;
479254721Semaste#undef SA_SIZE
480254721Semaste		    }
481254721Semaste
482254721Semaste		default:
483254721Semaste			error = EINVAL;
484254721Semaste			break;
485254721Semaste		} /* end of inner switch() */
486254721Semaste		break;
487254721Semaste	case NGM_FLOW_COOKIE:
488254721Semaste		switch (msg->header.cmd) {
489254721Semaste		case NGM_LINK_IS_UP:
490254721Semaste			ifp->if_flags |= IFF_RUNNING;
491254721Semaste			break;
492254721Semaste		case NGM_LINK_IS_DOWN:
493254721Semaste			ifp->if_flags &= ~IFF_RUNNING;
494254721Semaste			break;
495254721Semaste		default:
496254721Semaste			break;
497254721Semaste		}
498254721Semaste		break;
499254721Semaste	default:
500		error = EINVAL;
501		break;
502	}
503	NG_RESPOND_MSG(error, node, item, resp);
504	NG_FREE_MSG(msg);
505	return (error);
506}
507
508/*
509 * Receive data from a hook. Pass the packet to the ether_input routine.
510 */
511static int
512ng_eiface_rcvdata(hook_p hook, item_p item)
513{
514	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
515	struct ifnet *const ifp = priv->ifp;
516	struct mbuf *m;
517
518	NGI_GET_M(item, m);
519	NG_FREE_ITEM(item);
520
521	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
522	    (IFF_UP | IFF_RUNNING)) {
523		NG_FREE_M(m);
524		return (ENETDOWN);
525	}
526
527	if (m->m_len < ETHER_HDR_LEN) {
528		m = m_pullup(m, ETHER_HDR_LEN);
529		if (m == NULL)
530			return (EINVAL);
531	}
532
533	/* Note receiving interface */
534	m->m_pkthdr.rcvif = ifp;
535
536	/* Update interface stats */
537	ifp->if_ipackets++;
538
539	(*ifp->if_input)(ifp, m);
540
541	/* Done */
542	return (0);
543}
544
545/*
546 * Shutdown processing.
547 */
548static int
549ng_eiface_rmnode(node_p node)
550{
551	const priv_p priv = NG_NODE_PRIVATE(node);
552	struct ifnet *const ifp = priv->ifp;
553
554	ether_ifdetach(ifp);
555	free_unr(ng_eiface_unit, priv->unit);
556	FREE(priv, M_NETGRAPH);
557	NG_NODE_SET_PRIVATE(node, NULL);
558	NG_NODE_UNREF(node);
559	return (0);
560}
561
562
563/*
564 * This is called once we've already connected a new hook to the other node.
565 * It gives us a chance to balk at the last minute.
566 */
567static int
568ng_eiface_connect(hook_p hook)
569{
570	/* be really amiable and just say "YUP that's OK by me! " */
571	return (0);
572}
573
574/*
575 * Hook disconnection
576 */
577static int
578ng_eiface_disconnect(hook_p hook)
579{
580	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
581
582	priv->ether = NULL;
583	return (0);
584}
585
586/*
587 * Handle loading and unloading for this node type.
588 */
589static int
590ng_eiface_mod_event(module_t mod, int event, void *data)
591{
592	int error = 0;
593
594	switch (event) {
595	case MOD_LOAD:
596		ng_eiface_unit = new_unrhdr(0, 0xffff, NULL);
597		break;
598	case MOD_UNLOAD:
599		delete_unrhdr(ng_eiface_unit);
600		break;
601	default:
602		error = EOPNOTSUPP;
603		break;
604	}
605	return (error);
606}
607