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