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