1 2 /* 3 * ng_ether.c 4 * 5 * Copyright (c) 1996-2000 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 * 37 * Authors: Archie Cobbs <archie@freebsd.org> 38 * Julian Elischer <julian@freebsd.org> 39 * 40 * $FreeBSD: src/sys/netgraph/ng_ether.c,v 1.2.2.13 2002/07/02 20:10:25 archie Exp $ 41 */ 42 43 /* 44 * ng_ether(4) netgraph node type 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 #include <sys/mbuf.h> 52 #include <sys/errno.h> 53 #include <sys/syslog.h> 54 #include <sys/socket.h> 55 #include <sys/thread2.h> 56 57 #include <net/if.h> 58 #include <net/if_types.h> 59 #include <net/if_arp.h> 60 #include <net/if_var.h> 61 #include <net/ethernet.h> 62 63 #include <netgraph/ng_message.h> 64 #include <netgraph/netgraph.h> 65 #include <netgraph/ng_parse.h> 66 #include "ng_ether.h" 67 68 #define IFP2AC(IFP) ((struct arpcom *)IFP) 69 #define IFP2NG(ifp) (IFP2AC((ifp))->ac_netgraph) 70 71 /* Per-node private data */ 72 struct private { 73 struct ifnet *ifp; /* associated interface */ 74 hook_p upper; /* upper hook connection */ 75 hook_p lower; /* lower OR orphan hook connection */ 76 u_char lowerOrphan; /* whether lower is lower or orphan */ 77 u_char autoSrcAddr; /* always overwrite source address */ 78 u_char promisc; /* promiscuous mode enabled */ 79 u_long hwassist; /* hardware checksum capabilities */ 80 }; 81 typedef struct private *priv_p; 82 83 /* Functional hooks called from if_ethersubr.c */ 84 static void ng_ether_input(struct ifnet *ifp, struct mbuf **mp); 85 static void ng_ether_input_orphan(struct ifnet *ifp, 86 struct mbuf *m, const struct ether_header *eh); 87 static int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 88 static void ng_ether_attach(struct ifnet *ifp); 89 static void ng_ether_detach(struct ifnet *ifp); 90 91 /* Other functions */ 92 static void ng_ether_input2(node_p node, 93 struct mbuf **mp, const struct ether_header *eh); 94 static int ng_ether_glueback_header(struct mbuf **mp, 95 const struct ether_header *eh); 96 static int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 97 static int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 98 99 /* Netgraph node methods */ 100 static ng_constructor_t ng_ether_constructor; 101 static ng_rcvmsg_t ng_ether_rcvmsg; 102 static ng_shutdown_t ng_ether_rmnode; 103 static ng_newhook_t ng_ether_newhook; 104 static ng_rcvdata_t ng_ether_rcvdata; 105 static ng_disconnect_t ng_ether_disconnect; 106 static int ng_ether_mod_event(module_t mod, int event, void *data); 107 108 /* Parse type for an Ethernet address */ 109 static ng_parse_t ng_enaddr_parse; 110 static ng_unparse_t ng_enaddr_unparse; 111 const struct ng_parse_type ng_ether_enaddr_type = { 112 NULL, 113 NULL, 114 NULL, 115 ng_enaddr_parse, 116 ng_enaddr_unparse, 117 NULL, /* no such thing as a "default" EN address */ 118 0 119 }; 120 121 /* List of commands and how to convert arguments to/from ASCII */ 122 static const struct ng_cmdlist ng_ether_cmdlist[] = { 123 { 124 NGM_ETHER_COOKIE, 125 NGM_ETHER_GET_IFNAME, 126 "getifname", 127 NULL, 128 &ng_parse_string_type 129 }, 130 { 131 NGM_ETHER_COOKIE, 132 NGM_ETHER_GET_IFINDEX, 133 "getifindex", 134 NULL, 135 &ng_parse_int32_type 136 }, 137 { 138 NGM_ETHER_COOKIE, 139 NGM_ETHER_GET_ENADDR, 140 "getenaddr", 141 NULL, 142 &ng_ether_enaddr_type 143 }, 144 { 145 NGM_ETHER_COOKIE, 146 NGM_ETHER_SET_ENADDR, 147 "setenaddr", 148 &ng_ether_enaddr_type, 149 NULL 150 }, 151 { 152 NGM_ETHER_COOKIE, 153 NGM_ETHER_GET_PROMISC, 154 "getpromisc", 155 NULL, 156 &ng_parse_int32_type 157 }, 158 { 159 NGM_ETHER_COOKIE, 160 NGM_ETHER_SET_PROMISC, 161 "setpromisc", 162 &ng_parse_int32_type, 163 NULL 164 }, 165 { 166 NGM_ETHER_COOKIE, 167 NGM_ETHER_GET_AUTOSRC, 168 "getautosrc", 169 NULL, 170 &ng_parse_int32_type 171 }, 172 { 173 NGM_ETHER_COOKIE, 174 NGM_ETHER_SET_AUTOSRC, 175 "setautosrc", 176 &ng_parse_int32_type, 177 NULL 178 }, 179 { 0 } 180 }; 181 182 static struct ng_type ng_ether_typestruct = { 183 NG_VERSION, 184 NG_ETHER_NODE_TYPE, 185 ng_ether_mod_event, 186 ng_ether_constructor, 187 ng_ether_rcvmsg, 188 ng_ether_rmnode, 189 ng_ether_newhook, 190 NULL, 191 NULL, 192 ng_ether_rcvdata, 193 ng_ether_rcvdata, 194 ng_ether_disconnect, 195 ng_ether_cmdlist, 196 }; 197 NETGRAPH_INIT(ether, &ng_ether_typestruct); 198 199 /****************************************************************** 200 ETHERNET FUNCTION HOOKS 201 ******************************************************************/ 202 203 /* 204 * Handle a packet that has come in on an interface. We get to 205 * look at it here before any upper layer protocols do. 206 */ 207 static void 208 ng_ether_input(struct ifnet *ifp, struct mbuf **mp) 209 { 210 const node_p node = IFP2NG(ifp); 211 const priv_p priv = node->private; 212 213 /* If "lower" hook not connected, let packet continue */ 214 if (priv->lower == NULL || priv->lowerOrphan) 215 return; 216 ng_ether_input2(node, mp, NULL); 217 } 218 219 /* 220 * Handle a packet that has come in on an interface, and which 221 * does not match any of our known protocols (an ``orphan''). 222 */ 223 static void 224 ng_ether_input_orphan(struct ifnet *ifp, 225 struct mbuf *m, const struct ether_header *eh) 226 { 227 const node_p node = IFP2NG(ifp); 228 const priv_p priv = node->private; 229 230 /* If "orphan" hook not connected, let packet continue */ 231 if (priv->lower == NULL || !priv->lowerOrphan) { 232 m_freem(m); 233 return; 234 } 235 ng_ether_input2(node, &m, eh); 236 if (m != NULL) 237 m_freem(m); 238 } 239 240 /* 241 * Handle a packet that has come in on an interface. 242 * The Ethernet header has already been detached from the mbuf, 243 * so we have to put it back. 244 * 245 * NOTE: this function will get called at splimp() 246 */ 247 static void 248 ng_ether_input2(node_p node, struct mbuf **mp, const struct ether_header *eh) 249 { 250 const priv_p priv = node->private; 251 meta_p meta = NULL; 252 int error; 253 254 /* Glue Ethernet header back on */ 255 if (eh != NULL && (error = ng_ether_glueback_header(mp, eh)) != 0) 256 return; 257 258 /* Send out lower/orphan hook */ 259 ng_queue_data(priv->lower, *mp, meta); 260 *mp = NULL; 261 } 262 263 /* 264 * Handle a packet that is going out on an interface. 265 * The Ethernet header is already attached to the mbuf. 266 */ 267 static int 268 ng_ether_output(struct ifnet *ifp, struct mbuf **mp) 269 { 270 const node_p node = IFP2NG(ifp); 271 const priv_p priv = node->private; 272 meta_p meta = NULL; 273 int error = 0; 274 275 /* If "upper" hook not connected, let packet continue */ 276 if (priv->upper == NULL) 277 return (0); 278 279 /* Send it out "upper" hook */ 280 NG_SEND_DATA(error, priv->upper, *mp, meta); 281 *mp = NULL; 282 return (error); 283 } 284 285 /* 286 * A new Ethernet interface has been attached. 287 * Create a new node for it, etc. 288 */ 289 static void 290 ng_ether_attach(struct ifnet *ifp) 291 { 292 char name[IFNAMSIZ + 1]; 293 priv_p priv; 294 node_p node; 295 296 /* Create node */ 297 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 298 strlcpy(name, ifp->if_xname, sizeof(name)); 299 if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 300 log(LOG_ERR, "%s: can't %s for %s\n", 301 __func__, "create node", name); 302 return; 303 } 304 305 /* Allocate private data */ 306 priv = kmalloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 307 if (priv == NULL) { 308 log(LOG_ERR, "%s: can't %s for %s\n", 309 __func__, "allocate memory", name); 310 ng_unref(node); 311 return; 312 } 313 node->private = priv; 314 priv->ifp = ifp; 315 IFP2NG(ifp) = node; 316 priv->autoSrcAddr = 1; 317 priv->hwassist = ifp->if_hwassist; 318 319 /* Try to give the node the same name as the interface */ 320 if (ng_name_node(node, name) != 0) { 321 log(LOG_WARNING, "%s: can't name node %s\n", 322 __func__, name); 323 } 324 } 325 326 /* 327 * An Ethernet interface is being detached. 328 * Destroy its node. 329 */ 330 static void 331 ng_ether_detach(struct ifnet *ifp) 332 { 333 const node_p node = IFP2NG(ifp); 334 priv_p priv; 335 336 if (node == NULL) /* no node (why not?), ignore */ 337 return; 338 ng_rmnode(node); /* break all links to other nodes */ 339 node->flags |= NG_INVALID; 340 ng_unname(node); /* free name (and its reference) */ 341 IFP2NG(ifp) = NULL; /* detach node from interface */ 342 priv = node->private; /* free node private info */ 343 bzero(priv, sizeof(*priv)); 344 kfree(priv, M_NETGRAPH); 345 node->private = NULL; 346 ng_unref(node); /* free node itself */ 347 } 348 349 /* 350 * Optimization for gluing the Ethernet header back onto 351 * the front of an incoming packet. 352 */ 353 static int 354 ng_ether_glueback_header(struct mbuf **mp, const struct ether_header *eh) 355 { 356 struct mbuf *m = *mp; 357 int error = 0; 358 359 /* 360 * Optimize for the case where the header is already in place 361 * at the front of the mbuf. This is actually quite likely 362 * because many Ethernet drivers generate packets this way. 363 */ 364 if (eh == mtod(m, struct ether_header *) - 1) { 365 m->m_len += sizeof(*eh); 366 m->m_data -= sizeof(*eh); 367 m->m_pkthdr.len += sizeof(*eh); 368 goto done; 369 } 370 371 /* Prepend the header back onto the front of the mbuf */ 372 M_PREPEND(m, sizeof(*eh), MB_DONTWAIT); 373 if (m == NULL) { 374 error = ENOBUFS; 375 goto done; 376 } 377 378 /* Copy header into front of mbuf */ 379 bcopy(eh, mtod(m, void *), sizeof(*eh)); 380 381 done: 382 /* Done */ 383 *mp = m; 384 return error; 385 } 386 387 /****************************************************************** 388 NETGRAPH NODE METHODS 389 ******************************************************************/ 390 391 /* 392 * It is not possible or allowable to create a node of this type. 393 * Nodes get created when the interface is attached (or, when 394 * this node type's KLD is loaded). 395 */ 396 static int 397 ng_ether_constructor(node_p *nodep) 398 { 399 return (EINVAL); 400 } 401 402 /* 403 * Check for attaching a new hook. 404 */ 405 static int 406 ng_ether_newhook(node_p node, hook_p hook, const char *name) 407 { 408 const priv_p priv = node->private; 409 u_char orphan = priv->lowerOrphan; 410 hook_p *hookptr; 411 412 /* Divert hook is an alias for lower */ 413 if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 414 name = NG_ETHER_HOOK_LOWER; 415 416 /* Which hook? */ 417 if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 418 hookptr = &priv->upper; 419 else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 420 hookptr = &priv->lower; 421 orphan = 0; 422 } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 423 hookptr = &priv->lower; 424 orphan = 1; 425 } else 426 return (EINVAL); 427 428 /* Check if already connected (shouldn't be, but doesn't hurt) */ 429 if (*hookptr != NULL) 430 return (EISCONN); 431 432 /* Disable hardware checksums while 'upper' hook is connected */ 433 if (hookptr == &priv->upper) 434 priv->ifp->if_hwassist = 0; 435 436 /* OK */ 437 *hookptr = hook; 438 priv->lowerOrphan = orphan; 439 return (0); 440 } 441 442 /* 443 * Receive an incoming control message. 444 */ 445 static int 446 ng_ether_rcvmsg(node_p node, struct ng_mesg *msg, 447 const char *retaddr, struct ng_mesg **rptr) 448 { 449 const priv_p priv = node->private; 450 struct ng_mesg *resp = NULL; 451 int error = 0; 452 453 switch (msg->header.typecookie) { 454 case NGM_ETHER_COOKIE: 455 switch (msg->header.cmd) { 456 case NGM_ETHER_GET_IFNAME: 457 NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 458 if (resp == NULL) { 459 error = ENOMEM; 460 break; 461 } 462 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ); 463 break; 464 case NGM_ETHER_GET_IFINDEX: 465 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 466 if (resp == NULL) { 467 error = ENOMEM; 468 break; 469 } 470 *((u_int32_t *)resp->data) = priv->ifp->if_index; 471 break; 472 case NGM_ETHER_GET_ENADDR: 473 NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 474 if (resp == NULL) { 475 error = ENOMEM; 476 break; 477 } 478 bcopy((IFP2AC(priv->ifp))->ac_enaddr, 479 resp->data, ETHER_ADDR_LEN); 480 break; 481 case NGM_ETHER_SET_ENADDR: 482 { 483 if (msg->header.arglen != ETHER_ADDR_LEN) { 484 error = EINVAL; 485 break; 486 } 487 error = if_setlladdr(priv->ifp, 488 (u_char *)msg->data, ETHER_ADDR_LEN); 489 break; 490 } 491 case NGM_ETHER_GET_PROMISC: 492 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 493 if (resp == NULL) { 494 error = ENOMEM; 495 break; 496 } 497 *((u_int32_t *)resp->data) = priv->promisc; 498 break; 499 case NGM_ETHER_SET_PROMISC: 500 { 501 u_char want; 502 503 if (msg->header.arglen != sizeof(u_int32_t)) { 504 error = EINVAL; 505 break; 506 } 507 want = !!*((u_int32_t *)msg->data); 508 if (want ^ priv->promisc) { 509 if ((error = ifpromisc(priv->ifp, want)) != 0) 510 break; 511 priv->promisc = want; 512 } 513 break; 514 } 515 case NGM_ETHER_GET_AUTOSRC: 516 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 517 if (resp == NULL) { 518 error = ENOMEM; 519 break; 520 } 521 *((u_int32_t *)resp->data) = priv->autoSrcAddr; 522 break; 523 case NGM_ETHER_SET_AUTOSRC: 524 if (msg->header.arglen != sizeof(u_int32_t)) { 525 error = EINVAL; 526 break; 527 } 528 priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 529 break; 530 default: 531 error = EINVAL; 532 break; 533 } 534 break; 535 default: 536 error = EINVAL; 537 break; 538 } 539 if (rptr) 540 *rptr = resp; 541 else if (resp != NULL) 542 kfree(resp, M_NETGRAPH); 543 kfree(msg, M_NETGRAPH); 544 return (error); 545 } 546 547 /* 548 * Receive data on a hook. 549 */ 550 static int 551 ng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 552 { 553 const node_p node = hook->node; 554 const priv_p priv = node->private; 555 556 if (hook == priv->lower) 557 return ng_ether_rcv_lower(node, m, meta); 558 if (hook == priv->upper) 559 return ng_ether_rcv_upper(node, m, meta); 560 panic("%s: weird hook", __func__); 561 } 562 563 /* 564 * Handle an mbuf received on the "lower" hook. 565 */ 566 static int 567 ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 568 { 569 const priv_p priv = node->private; 570 struct ifnet *const ifp = priv->ifp; 571 int error; 572 573 /* Discard meta info */ 574 NG_FREE_META(meta); 575 576 /* Check whether interface is ready for packets */ 577 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 578 m_freem(m); 579 return (ENETDOWN); 580 } 581 582 /* Make sure header is fully pulled up */ 583 if (m->m_pkthdr.len < sizeof(struct ether_header)) { 584 m_freem(m); 585 return (EINVAL); 586 } 587 if (m->m_len < sizeof(struct ether_header) 588 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 589 return (ENOBUFS); 590 591 /* Drop in the MAC address if desired */ 592 if (priv->autoSrcAddr) { 593 594 /* Make the mbuf writable if it's not already */ 595 if (!M_WRITABLE(m) 596 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 597 return (ENOBUFS); 598 599 /* Overwrite source MAC address */ 600 bcopy((IFP2AC(ifp))->ac_enaddr, 601 mtod(m, struct ether_header *)->ether_shost, 602 ETHER_ADDR_LEN); 603 } 604 605 /* Send it on its way */ 606 error = ether_output_frame(ifp, m); 607 return (error); 608 } 609 610 /* 611 * Handle an mbuf received on the "upper" hook. 612 */ 613 static int 614 ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 615 { 616 const priv_p priv = node->private; 617 618 /* Discard meta info */ 619 NG_FREE_META(meta); 620 621 /* Check length and pull off header */ 622 if (m->m_pkthdr.len < ETHER_HDR_LEN) { 623 m_freem(m); 624 return (EINVAL); 625 } 626 if (m->m_len < ETHER_HDR_LEN && 627 (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) 628 return (ENOBUFS); 629 630 m->m_pkthdr.rcvif = priv->ifp; 631 632 /* Route packet back in */ 633 ether_demux(m); 634 return (0); 635 } 636 637 /* 638 * Shutdown node. This resets the node but does not remove it. 639 */ 640 static int 641 ng_ether_rmnode(node_p node) 642 { 643 const priv_p priv = node->private; 644 645 ng_cutlinks(node); 646 node->flags &= ~NG_INVALID; /* bounce back to life */ 647 if (priv->promisc) { /* disable promiscuous mode */ 648 ifpromisc(priv->ifp, 0); 649 priv->promisc = 0; 650 } 651 priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 652 return (0); 653 } 654 655 /* 656 * Hook disconnection. 657 */ 658 static int 659 ng_ether_disconnect(hook_p hook) 660 { 661 const priv_p priv = hook->node->private; 662 663 if (hook == priv->upper) { 664 priv->upper = NULL; 665 priv->ifp->if_hwassist = priv->hwassist; /* restore h/w csum */ 666 } else if (hook == priv->lower) { 667 priv->lower = NULL; 668 priv->lowerOrphan = 0; 669 } else 670 panic("%s: weird hook", __func__); 671 if (hook->node->numhooks == 0) 672 ng_rmnode(hook->node); /* reset node */ 673 return (0); 674 } 675 676 static int 677 ng_enaddr_parse(const struct ng_parse_type *type, 678 const char *s, int *const off, const u_char *const start, 679 u_char *const buf, int *const buflen) 680 { 681 char *eptr; 682 u_long val; 683 int i; 684 685 if (*buflen < ETHER_ADDR_LEN) 686 return (ERANGE); 687 for (i = 0; i < ETHER_ADDR_LEN; i++) { 688 val = strtoul(s + *off, &eptr, 16); 689 if (val > 0xff || eptr == s + *off) 690 return (EINVAL); 691 buf[i] = (u_char)val; 692 *off = (eptr - s); 693 if (i < ETHER_ADDR_LEN - 1) { 694 if (*eptr != ':') 695 return (EINVAL); 696 (*off)++; 697 } 698 } 699 *buflen = ETHER_ADDR_LEN; 700 return (0); 701 } 702 703 static int 704 ng_enaddr_unparse(const struct ng_parse_type *type, 705 const u_char *data, int *off, char *cbuf, int cbuflen) 706 { 707 int len; 708 709 len = ksnprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 710 data[*off], data[*off + 1], data[*off + 2], 711 data[*off + 3], data[*off + 4], data[*off + 5]); 712 if (len >= cbuflen) 713 return (ERANGE); 714 *off += ETHER_ADDR_LEN; 715 return (0); 716 } 717 718 /****************************************************************** 719 INITIALIZATION 720 ******************************************************************/ 721 722 /* 723 * Handle loading and unloading for this node type. 724 */ 725 static int 726 ng_ether_mod_event(module_t mod, int event, void *data) 727 { 728 struct ifnet *ifp; 729 int error = 0; 730 731 crit_enter(); 732 switch (event) { 733 case MOD_LOAD: 734 735 /* Register function hooks */ 736 if (ng_ether_attach_p != NULL) { 737 error = EEXIST; 738 break; 739 } 740 ng_ether_attach_p = ng_ether_attach; 741 ng_ether_detach_p = ng_ether_detach; 742 ng_ether_output_p = ng_ether_output; 743 ng_ether_input_p = ng_ether_input; 744 ng_ether_input_orphan_p = ng_ether_input_orphan; 745 746 /* Create nodes for any already-existing Ethernet interfaces */ 747 TAILQ_FOREACH(ifp, &ifnet, if_link) { 748 if (ifp->if_type == IFT_ETHER || 749 ifp->if_type == IFT_L2VLAN) 750 ng_ether_attach(ifp); 751 } 752 break; 753 754 case MOD_UNLOAD: 755 756 /* 757 * Note that the base code won't try to unload us until 758 * all nodes have been removed, and that can't happen 759 * until all Ethernet interfaces are removed. In any 760 * case, we know there are no nodes left if the action 761 * is MOD_UNLOAD, so there's no need to detach any nodes. 762 */ 763 764 /* Unregister function hooks */ 765 ng_ether_attach_p = NULL; 766 ng_ether_detach_p = NULL; 767 ng_ether_output_p = NULL; 768 ng_ether_input_p = NULL; 769 ng_ether_input_orphan_p = NULL; 770 break; 771 772 default: 773 error = EOPNOTSUPP; 774 break; 775 } 776 crit_exit(); 777 return (error); 778 } 779 780