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