ng_ether.c revision 151282
1 2/* 3 * ng_ether.c 4 */ 5 6/*- 7 * Copyright (c) 1996-2000 Whistle Communications, Inc. 8 * All rights reserved. 9 * 10 * Subject to the following obligations and disclaimer of warranty, use and 11 * redistribution of this software, in source or object code forms, with or 12 * without modifications are expressly permitted by Whistle Communications; 13 * provided, however, that: 14 * 1. Any and all reproductions of the source or object code must include the 15 * copyright notice above and the following disclaimer of warranties; and 16 * 2. No rights are granted, in any manner or form, to use Whistle 17 * Communications, Inc. trademarks, including the mark "WHISTLE 18 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 19 * such appears in the above copyright notice or in the software. 20 * 21 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 22 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 23 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 24 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 26 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 27 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 28 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 29 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 30 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 31 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 32 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 33 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 37 * OF SUCH DAMAGE. 38 * 39 * Authors: Archie Cobbs <archie@freebsd.org> 40 * Julian Elischer <julian@freebsd.org> 41 * 42 * $FreeBSD: head/sys/netgraph/ng_ether.c 151282 2005-10-13 09:43:30Z thompsa $ 43 */ 44 45/* 46 * ng_ether(4) netgraph node type 47 */ 48 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/kernel.h> 52#include <sys/malloc.h> 53#include <sys/mbuf.h> 54#include <sys/errno.h> 55#include <sys/syslog.h> 56#include <sys/socket.h> 57 58#include <net/if.h> 59#include <net/if_dl.h> 60#include <net/if_types.h> 61#include <net/if_arp.h> 62#include <net/if_var.h> 63#include <net/ethernet.h> 64 65#include <netgraph/ng_message.h> 66#include <netgraph/netgraph.h> 67#include <netgraph/ng_parse.h> 68#include <netgraph/ng_ether.h> 69 70#define IFP2NG(ifp) ((struct ng_node *)IFP2AC((ifp))->ac_netgraph) 71#define IFP2NG_SET(ifp, val) (IFP2AC((ifp))->ac_netgraph = (val)) 72 73/* Per-node private data */ 74struct private { 75 struct ifnet *ifp; /* associated interface */ 76 hook_p upper; /* upper hook connection */ 77 hook_p lower; /* lower hook connection */ 78 hook_p orphan; /* orphan hook connection */ 79 u_char autoSrcAddr; /* always overwrite source address */ 80 u_char promisc; /* promiscuous mode enabled */ 81 u_long hwassist; /* hardware checksum capabilities */ 82 u_int flags; /* flags e.g. really die */ 83}; 84typedef struct private *priv_p; 85 86/* Hook pointers used by if_ethersubr.c to callback to netgraph */ 87extern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); 88extern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); 89extern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 90extern void (*ng_ether_attach_p)(struct ifnet *ifp); 91extern void (*ng_ether_detach_p)(struct ifnet *ifp); 92extern void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); 93 94/* Functional hooks called from if_ethersubr.c */ 95static void ng_ether_input(struct ifnet *ifp, struct mbuf **mp); 96static void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m); 97static int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 98static void ng_ether_attach(struct ifnet *ifp); 99static void ng_ether_detach(struct ifnet *ifp); 100static void ng_ether_link_state(struct ifnet *ifp, int state); 101 102/* Other functions */ 103static int ng_ether_rcv_lower(node_p node, struct mbuf *m); 104static int ng_ether_rcv_upper(node_p node, struct mbuf *m); 105 106/* if_bridge(4) support. XXX: should go into some include. */ 107extern struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); 108 109/* Netgraph node methods */ 110static ng_constructor_t ng_ether_constructor; 111static ng_rcvmsg_t ng_ether_rcvmsg; 112static ng_shutdown_t ng_ether_shutdown; 113static ng_newhook_t ng_ether_newhook; 114static ng_connect_t ng_ether_connect; 115static ng_rcvdata_t ng_ether_rcvdata; 116static ng_disconnect_t ng_ether_disconnect; 117static int ng_ether_mod_event(module_t mod, int event, void *data); 118 119/* List of commands and how to convert arguments to/from ASCII */ 120static const struct ng_cmdlist ng_ether_cmdlist[] = { 121 { 122 NGM_ETHER_COOKIE, 123 NGM_ETHER_GET_IFNAME, 124 "getifname", 125 NULL, 126 &ng_parse_string_type 127 }, 128 { 129 NGM_ETHER_COOKIE, 130 NGM_ETHER_GET_IFINDEX, 131 "getifindex", 132 NULL, 133 &ng_parse_int32_type 134 }, 135 { 136 NGM_ETHER_COOKIE, 137 NGM_ETHER_GET_ENADDR, 138 "getenaddr", 139 NULL, 140 &ng_parse_enaddr_type 141 }, 142 { 143 NGM_ETHER_COOKIE, 144 NGM_ETHER_SET_ENADDR, 145 "setenaddr", 146 &ng_parse_enaddr_type, 147 NULL 148 }, 149 { 150 NGM_ETHER_COOKIE, 151 NGM_ETHER_GET_PROMISC, 152 "getpromisc", 153 NULL, 154 &ng_parse_int32_type 155 }, 156 { 157 NGM_ETHER_COOKIE, 158 NGM_ETHER_SET_PROMISC, 159 "setpromisc", 160 &ng_parse_int32_type, 161 NULL 162 }, 163 { 164 NGM_ETHER_COOKIE, 165 NGM_ETHER_GET_AUTOSRC, 166 "getautosrc", 167 NULL, 168 &ng_parse_int32_type 169 }, 170 { 171 NGM_ETHER_COOKIE, 172 NGM_ETHER_SET_AUTOSRC, 173 "setautosrc", 174 &ng_parse_int32_type, 175 NULL 176 }, 177 { 178 NGM_ETHER_COOKIE, 179 NGM_ETHER_ADD_MULTI, 180 "addmulti", 181 &ng_parse_enaddr_type, 182 NULL 183 }, 184 { 185 NGM_ETHER_COOKIE, 186 NGM_ETHER_DEL_MULTI, 187 "delmulti", 188 &ng_parse_enaddr_type, 189 NULL 190 }, 191 { 192 NGM_ETHER_COOKIE, 193 NGM_ETHER_DETACH, 194 "detach", 195 NULL, 196 NULL 197 }, 198 { 0 } 199}; 200 201static struct ng_type ng_ether_typestruct = { 202 .version = NG_ABI_VERSION, 203 .name = NG_ETHER_NODE_TYPE, 204 .mod_event = ng_ether_mod_event, 205 .constructor = ng_ether_constructor, 206 .rcvmsg = ng_ether_rcvmsg, 207 .shutdown = ng_ether_shutdown, 208 .newhook = ng_ether_newhook, 209 .connect = ng_ether_connect, 210 .rcvdata = ng_ether_rcvdata, 211 .disconnect = ng_ether_disconnect, 212 .cmdlist = ng_ether_cmdlist, 213}; 214NETGRAPH_INIT(ether, &ng_ether_typestruct); 215 216/****************************************************************** 217 ETHERNET FUNCTION HOOKS 218******************************************************************/ 219 220/* 221 * Handle a packet that has come in on an interface. We get to 222 * look at it here before any upper layer protocols do. 223 * 224 * NOTE: this function will get called at splimp() 225 */ 226static void 227ng_ether_input(struct ifnet *ifp, struct mbuf **mp) 228{ 229 const node_p node = IFP2NG(ifp); 230 const priv_p priv = NG_NODE_PRIVATE(node); 231 int error; 232 233 /* If "lower" hook not connected, let packet continue */ 234 if (priv->lower == NULL) 235 return; 236 NG_SEND_DATA_ONLY(error, priv->lower, *mp); /* sets *mp = NULL */ 237} 238 239/* 240 * Handle a packet that has come in on an interface, and which 241 * does not match any of our known protocols (an ``orphan''). 242 * 243 * NOTE: this function will get called at splimp() 244 */ 245static void 246ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m) 247{ 248 const node_p node = IFP2NG(ifp); 249 const priv_p priv = NG_NODE_PRIVATE(node); 250 int error; 251 252 /* If "orphan" hook not connected, discard packet */ 253 if (priv->orphan == NULL) { 254 m_freem(m); 255 return; 256 } 257 NG_SEND_DATA_ONLY(error, priv->orphan, m); 258} 259 260/* 261 * Handle a packet that is going out on an interface. 262 * The Ethernet header is already attached to the mbuf. 263 */ 264static int 265ng_ether_output(struct ifnet *ifp, struct mbuf **mp) 266{ 267 const node_p node = IFP2NG(ifp); 268 const priv_p priv = NG_NODE_PRIVATE(node); 269 int error = 0; 270 271 /* If "upper" hook not connected, let packet continue */ 272 if (priv->upper == NULL) 273 return (0); 274 275 /* Send it out "upper" hook */ 276 NG_SEND_DATA_ONLY(error, priv->upper, *mp); 277 return (error); 278} 279 280/* 281 * A new Ethernet interface has been attached. 282 * Create a new node for it, etc. 283 */ 284static void 285ng_ether_attach(struct ifnet *ifp) 286{ 287 priv_p priv; 288 node_p node; 289 290 /* Create node */ 291 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 292 if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 293 log(LOG_ERR, "%s: can't %s for %s\n", 294 __func__, "create node", ifp->if_xname); 295 return; 296 } 297 298 /* Allocate private data */ 299 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 300 if (priv == NULL) { 301 log(LOG_ERR, "%s: can't %s for %s\n", 302 __func__, "allocate memory", ifp->if_xname); 303 NG_NODE_UNREF(node); 304 return; 305 } 306 NG_NODE_SET_PRIVATE(node, priv); 307 priv->ifp = ifp; 308 IFP2NG_SET(ifp, node); 309 priv->autoSrcAddr = 1; 310 priv->hwassist = ifp->if_hwassist; 311 312 /* Try to give the node the same name as the interface */ 313 if (ng_name_node(node, ifp->if_xname) != 0) { 314 log(LOG_WARNING, "%s: can't name node %s\n", 315 __func__, ifp->if_xname); 316 } 317} 318 319/* 320 * An Ethernet interface is being detached. 321 * REALLY Destroy its node. 322 */ 323static void 324ng_ether_detach(struct ifnet *ifp) 325{ 326 const node_p node = IFP2NG(ifp); 327 const priv_p priv = NG_NODE_PRIVATE(node); 328 329 NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 330 /* 331 * We can't assume the ifnet is still around when we run shutdown 332 * So zap it now. XXX We HOPE that anything running at this time 333 * handles it (as it should in the non netgraph case). 334 */ 335 IFP2NG_SET(ifp, NULL); 336 priv->ifp = NULL; /* XXX race if interrupted an output packet */ 337 ng_rmnode_self(node); /* remove all netgraph parts */ 338} 339 340/* 341 * Notify graph about link event. 342 * if_link_state_change() has already checked that the state has changed. 343 */ 344static void 345ng_ether_link_state(struct ifnet *ifp, int state) 346{ 347 const node_p node = IFP2NG(ifp); 348 const priv_p priv = NG_NODE_PRIVATE(node); 349 struct ng_mesg *msg; 350 int cmd, dummy_error = 0; 351 352 if (priv->lower == NULL) 353 return; 354 355 if (state == LINK_STATE_UP) 356 cmd = NGM_LINK_IS_UP; 357 else if (state == LINK_STATE_DOWN) 358 cmd = NGM_LINK_IS_DOWN; 359 else 360 return; 361 362 NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT); 363 if (msg != NULL) 364 NG_SEND_MSG_HOOK(dummy_error, node, msg, priv->lower, 0); 365} 366 367/****************************************************************** 368 NETGRAPH NODE METHODS 369******************************************************************/ 370 371/* 372 * It is not possible or allowable to create a node of this type. 373 * Nodes get created when the interface is attached (or, when 374 * this node type's KLD is loaded). 375 */ 376static int 377ng_ether_constructor(node_p node) 378{ 379 return (EINVAL); 380} 381 382/* 383 * Check for attaching a new hook. 384 */ 385static int 386ng_ether_newhook(node_p node, hook_p hook, const char *name) 387{ 388 const priv_p priv = NG_NODE_PRIVATE(node); 389 hook_p *hookptr; 390 391 /* Divert hook is an alias for lower */ 392 if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 393 name = NG_ETHER_HOOK_LOWER; 394 395 /* Which hook? */ 396 if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 397 hookptr = &priv->upper; 398 else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) 399 hookptr = &priv->lower; 400 else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) 401 hookptr = &priv->orphan; 402 else 403 return (EINVAL); 404 405 /* Check if already connected (shouldn't be, but doesn't hurt) */ 406 if (*hookptr != NULL) 407 return (EISCONN); 408 409 /* Disable hardware checksums while 'upper' hook is connected */ 410 if (hookptr == &priv->upper) 411 priv->ifp->if_hwassist = 0; 412 413 /* OK */ 414 *hookptr = hook; 415 return (0); 416} 417 418/* 419 * Hooks are attached, adjust to force queueing. 420 * We don't really care which hook it is. 421 * they should all be queuing for outgoing data. 422 */ 423static int 424ng_ether_connect(hook_p hook) 425{ 426 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 427 return (0); 428} 429 430/* 431 * Receive an incoming control message. 432 */ 433static int 434ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 435{ 436 const priv_p priv = NG_NODE_PRIVATE(node); 437 struct ng_mesg *resp = NULL; 438 int error = 0; 439 struct ng_mesg *msg; 440 441 NGI_GET_MSG(item, msg); 442 switch (msg->header.typecookie) { 443 case NGM_ETHER_COOKIE: 444 switch (msg->header.cmd) { 445 case NGM_ETHER_GET_IFNAME: 446 NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT); 447 if (resp == NULL) { 448 error = ENOMEM; 449 break; 450 } 451 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ); 452 break; 453 case NGM_ETHER_GET_IFINDEX: 454 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 455 if (resp == NULL) { 456 error = ENOMEM; 457 break; 458 } 459 *((u_int32_t *)resp->data) = priv->ifp->if_index; 460 break; 461 case NGM_ETHER_GET_ENADDR: 462 NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 463 if (resp == NULL) { 464 error = ENOMEM; 465 break; 466 } 467 bcopy(IFP2ENADDR(priv->ifp), 468 resp->data, ETHER_ADDR_LEN); 469 break; 470 case NGM_ETHER_SET_ENADDR: 471 { 472 if (msg->header.arglen != ETHER_ADDR_LEN) { 473 error = EINVAL; 474 break; 475 } 476 error = if_setlladdr(priv->ifp, 477 (u_char *)msg->data, ETHER_ADDR_LEN); 478 break; 479 } 480 case NGM_ETHER_GET_PROMISC: 481 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 482 if (resp == NULL) { 483 error = ENOMEM; 484 break; 485 } 486 *((u_int32_t *)resp->data) = priv->promisc; 487 break; 488 case NGM_ETHER_SET_PROMISC: 489 { 490 u_char want; 491 492 if (msg->header.arglen != sizeof(u_int32_t)) { 493 error = EINVAL; 494 break; 495 } 496 want = !!*((u_int32_t *)msg->data); 497 if (want ^ priv->promisc) { 498 if ((error = ifpromisc(priv->ifp, want)) != 0) 499 break; 500 priv->promisc = want; 501 } 502 break; 503 } 504 case NGM_ETHER_GET_AUTOSRC: 505 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 506 if (resp == NULL) { 507 error = ENOMEM; 508 break; 509 } 510 *((u_int32_t *)resp->data) = priv->autoSrcAddr; 511 break; 512 case NGM_ETHER_SET_AUTOSRC: 513 if (msg->header.arglen != sizeof(u_int32_t)) { 514 error = EINVAL; 515 break; 516 } 517 priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 518 break; 519 case NGM_ETHER_ADD_MULTI: 520 { 521 struct sockaddr_dl sa_dl; 522 struct ifmultiaddr *ifm; 523 524 if (msg->header.arglen != ETHER_ADDR_LEN) { 525 error = EINVAL; 526 break; 527 } 528 bzero(&sa_dl, sizeof(struct sockaddr_dl)); 529 sa_dl.sdl_len = sizeof(struct sockaddr_dl); 530 sa_dl.sdl_family = AF_LINK; 531 sa_dl.sdl_alen = ETHER_ADDR_LEN; 532 bcopy((void *)msg->data, LLADDR(&sa_dl), 533 ETHER_ADDR_LEN); 534 error = if_addmulti(priv->ifp, 535 (struct sockaddr *)&sa_dl, &ifm); 536 break; 537 } 538 case NGM_ETHER_DEL_MULTI: 539 { 540 struct sockaddr_dl sa_dl; 541 542 if (msg->header.arglen != ETHER_ADDR_LEN) { 543 error = EINVAL; 544 break; 545 } 546 bzero(&sa_dl, sizeof(struct sockaddr_dl)); 547 sa_dl.sdl_len = sizeof(struct sockaddr_dl); 548 sa_dl.sdl_family = AF_LINK; 549 sa_dl.sdl_alen = ETHER_ADDR_LEN; 550 bcopy((void *)msg->data, LLADDR(&sa_dl), 551 ETHER_ADDR_LEN); 552 error = if_delmulti(priv->ifp, 553 (struct sockaddr *)&sa_dl); 554 break; 555 } 556 case NGM_ETHER_DETACH: 557 ng_ether_detach(priv->ifp); 558 break; 559 default: 560 error = EINVAL; 561 break; 562 } 563 break; 564 default: 565 error = EINVAL; 566 break; 567 } 568 NG_RESPOND_MSG(error, node, item, resp); 569 NG_FREE_MSG(msg); 570 return (error); 571} 572 573/* 574 * Receive data on a hook. 575 */ 576static int 577ng_ether_rcvdata(hook_p hook, item_p item) 578{ 579 const node_p node = NG_HOOK_NODE(hook); 580 const priv_p priv = NG_NODE_PRIVATE(node); 581 struct mbuf *m; 582 583 NGI_GET_M(item, m); 584 NG_FREE_ITEM(item); 585 586 if (hook == priv->lower || hook == priv->orphan) 587 return ng_ether_rcv_lower(node, m); 588 if (hook == priv->upper) 589 return ng_ether_rcv_upper(node, m); 590 panic("%s: weird hook", __func__); 591#ifdef RESTARTABLE_PANICS /* so we don't get an error msg in LINT */ 592 return (0); 593#endif 594} 595 596/* 597 * Handle an mbuf received on the "lower" or "orphan" hook. 598 */ 599static int 600ng_ether_rcv_lower(node_p node, struct mbuf *m) 601{ 602 const priv_p priv = NG_NODE_PRIVATE(node); 603 struct ifnet *const ifp = priv->ifp; 604 605 /* Check whether interface is ready for packets */ 606 if (!((ifp->if_flags & IFF_UP) && 607 (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 608 NG_FREE_M(m); 609 return (ENETDOWN); 610 } 611 612 /* Make sure header is fully pulled up */ 613 if (m->m_pkthdr.len < sizeof(struct ether_header)) { 614 NG_FREE_M(m); 615 return (EINVAL); 616 } 617 if (m->m_len < sizeof(struct ether_header) 618 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 619 return (ENOBUFS); 620 621 /* Drop in the MAC address if desired */ 622 if (priv->autoSrcAddr) { 623 624 /* Make the mbuf writable if it's not already */ 625 if (!M_WRITABLE(m) 626 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 627 return (ENOBUFS); 628 629 /* Overwrite source MAC address */ 630 bcopy(IFP2ENADDR(ifp), 631 mtod(m, struct ether_header *)->ether_shost, 632 ETHER_ADDR_LEN); 633 } 634 635 /* Send it on its way */ 636 return ether_output_frame(ifp, m); 637} 638 639/* 640 * Handle an mbuf received on the "upper" hook. 641 */ 642static int 643ng_ether_rcv_upper(node_p node, struct mbuf *m) 644{ 645 const priv_p priv = NG_NODE_PRIVATE(node); 646 struct ifnet *ifp = priv->ifp; 647 648 m->m_pkthdr.rcvif = ifp; 649 650 /* 651 * XXX: This is a copy'and'paste from if_ethersubr.c:ether_input() 652 */ 653 if (ifp->if_bridge) { 654 KASSERT(bridge_input_p != NULL, 655 ("%s: if_bridge not loaded!", __func__)); 656 657 m = (*bridge_input_p)(ifp, m); 658 if (m == NULL) 659 return (0); 660 /* 661 * Bridge has determined that the packet is for us. 662 * Update our interface pointer -- we may have had 663 * to "bridge" the packet locally. 664 */ 665 ifp = m->m_pkthdr.rcvif; 666 } 667 668 /* Route packet back in */ 669 ether_demux(priv->ifp, m); 670 return (0); 671} 672 673/* 674 * Shutdown node. This resets the node but does not remove it 675 * unless the REALLY_DIE flag is set. 676 */ 677static int 678ng_ether_shutdown(node_p node) 679{ 680 const priv_p priv = NG_NODE_PRIVATE(node); 681 682 if (node->nd_flags & NGF_REALLY_DIE) { 683 /* 684 * WE came here because the ethernet card is being unloaded, 685 * so stop being persistant. 686 * Actually undo all the things we did on creation. 687 * Assume the ifp has already been freed. 688 */ 689 NG_NODE_SET_PRIVATE(node, NULL); 690 FREE(priv, M_NETGRAPH); 691 NG_NODE_UNREF(node); /* free node itself */ 692 return (0); 693 } 694 if (priv->promisc) { /* disable promiscuous mode */ 695 (void)ifpromisc(priv->ifp, 0); 696 priv->promisc = 0; 697 } 698 priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 699 NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */ 700 701 return (0); 702} 703 704/* 705 * Hook disconnection. 706 */ 707static int 708ng_ether_disconnect(hook_p hook) 709{ 710 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 711 712 if (hook == priv->upper) { 713 priv->upper = NULL; 714 if (priv->ifp != NULL) /* restore h/w csum */ 715 priv->ifp->if_hwassist = priv->hwassist; 716 } else if (hook == priv->lower) 717 priv->lower = NULL; 718 else if (hook == priv->orphan) 719 priv->orphan = NULL; 720 else 721 panic("%s: weird hook", __func__); 722 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 723 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 724 ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 725 return (0); 726} 727 728/****************************************************************** 729 INITIALIZATION 730******************************************************************/ 731 732/* 733 * Handle loading and unloading for this node type. 734 */ 735static int 736ng_ether_mod_event(module_t mod, int event, void *data) 737{ 738 struct ifnet *ifp; 739 int error = 0; 740 int s; 741 742 s = splnet(); 743 switch (event) { 744 case MOD_LOAD: 745 746 /* Register function hooks */ 747 if (ng_ether_attach_p != NULL) { 748 error = EEXIST; 749 break; 750 } 751 ng_ether_attach_p = ng_ether_attach; 752 ng_ether_detach_p = ng_ether_detach; 753 ng_ether_output_p = ng_ether_output; 754 ng_ether_input_p = ng_ether_input; 755 ng_ether_input_orphan_p = ng_ether_input_orphan; 756 ng_ether_link_state_p = ng_ether_link_state; 757 758 /* Create nodes for any already-existing Ethernet interfaces */ 759 IFNET_RLOCK(); 760 TAILQ_FOREACH(ifp, &ifnet, if_link) { 761 if (ifp->if_type == IFT_ETHER 762 || ifp->if_type == IFT_L2VLAN) 763 ng_ether_attach(ifp); 764 } 765 IFNET_RUNLOCK(); 766 break; 767 768 case MOD_UNLOAD: 769 770 /* 771 * Note that the base code won't try to unload us until 772 * all nodes have been removed, and that can't happen 773 * until all Ethernet interfaces are removed. In any 774 * case, we know there are no nodes left if the action 775 * is MOD_UNLOAD, so there's no need to detach any nodes. 776 */ 777 778 /* Unregister function hooks */ 779 ng_ether_attach_p = NULL; 780 ng_ether_detach_p = NULL; 781 ng_ether_output_p = NULL; 782 ng_ether_input_p = NULL; 783 ng_ether_input_orphan_p = NULL; 784 ng_ether_link_state_p = NULL; 785 break; 786 787 default: 788 error = EOPNOTSUPP; 789 break; 790 } 791 splx(s); 792 return (error); 793} 794 795