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