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