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