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