ng_ether.c revision 64653
185722Sjulian 285722Sjulian/* 385722Sjulian * ng_ether.c 485722Sjulian * 585722Sjulian * Copyright (c) 1996-2000 Whistle Communications, Inc. 685722Sjulian * All rights reserved. 785722Sjulian * 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: head/sys/netgraph/ng_ether.c 64653 2000-08-15 01:05:50Z archie $ 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 56#include <net/if.h> 57#include <net/if_types.h> 58#include <net/if_arp.h> 59#include <net/if_var.h> 60#include <net/ethernet.h> 61 62#include <netgraph/ng_message.h> 63#include <netgraph/netgraph.h> 64#include <netgraph/ng_parse.h> 65#include <netgraph/ng_ether.h> 66 67#define IFP2AC(IFP) ((struct arpcom *)IFP) 68#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph) 69 70/* Per-node private data */ 71struct private { 72 struct ifnet *ifp; /* associated interface */ 73 hook_p upper; /* upper hook connection */ 74 hook_p lower; /* lower OR orphan hook connection */ 75 u_char lowerOrphan; /* whether lower is lower or orphan */ 76 u_char autoSrcAddr; /* always overwrite source address */ 77 u_char promisc; /* promiscuous mode enabled */ 78}; 79typedef struct private *priv_p; 80 81/* Functional hooks called from if_ethersubr.c */ 82static void ng_ether_input(struct ifnet *ifp, 83 struct mbuf **mp, struct ether_header *eh); 84static void ng_ether_input_orphan(struct ifnet *ifp, 85 struct mbuf *m, struct ether_header *eh); 86static int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 87static void ng_ether_attach(struct ifnet *ifp); 88static void ng_ether_detach(struct ifnet *ifp); 89 90/* Other functions */ 91static void ng_ether_input2(node_p node, 92 struct mbuf **mp, struct ether_header *eh); 93static int ng_ether_glueback_header(struct mbuf **mp, 94 struct ether_header *eh); 95static int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 96static int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 97 98/* Netgraph node methods */ 99static ng_constructor_t ng_ether_constructor; 100static ng_rcvmsg_t ng_ether_rcvmsg; 101static ng_shutdown_t ng_ether_rmnode; 102static ng_newhook_t ng_ether_newhook; 103static ng_rcvdata_t ng_ether_rcvdata; 104static ng_disconnect_t ng_ether_disconnect; 105static int ng_ether_mod_event(module_t mod, int event, void *data); 106 107/* Parse type for an Ethernet address */ 108static ng_parse_t ng_enaddr_parse; 109static ng_unparse_t ng_enaddr_unparse; 110const struct ng_parse_type ng_ether_enaddr_type = { 111 NULL, 112 NULL, 113 NULL, 114 ng_enaddr_parse, 115 ng_enaddr_unparse, 116 NULL, /* no such thing as a "default" EN address */ 117 0 118}; 119 120/* List of commands and how to convert arguments to/from ASCII */ 121static const struct ng_cmdlist ng_ether_cmdlist[] = { 122 { 123 NGM_ETHER_COOKIE, 124 NGM_ETHER_GET_IFNAME, 125 "getifname", 126 NULL, 127 &ng_parse_string_type 128 }, 129 { 130 NGM_ETHER_COOKIE, 131 NGM_ETHER_GET_IFINDEX, 132 "getifindex", 133 NULL, 134 &ng_parse_int32_type 135 }, 136 { 137 NGM_ETHER_COOKIE, 138 NGM_ETHER_GET_ENADDR, 139 "getenaddr", 140 NULL, 141 &ng_ether_enaddr_type 142 }, 143 { 144 NGM_ETHER_COOKIE, 145 NGM_ETHER_SET_ENADDR, 146 "setenaddr", 147 &ng_ether_enaddr_type, 148 NULL 149 }, 150 { 151 NGM_ETHER_COOKIE, 152 NGM_ETHER_GET_PROMISC, 153 "getpromisc", 154 NULL, 155 &ng_parse_int32_type 156 }, 157 { 158 NGM_ETHER_COOKIE, 159 NGM_ETHER_SET_PROMISC, 160 "setpromisc", 161 &ng_parse_int32_type, 162 NULL 163 }, 164 { 165 NGM_ETHER_COOKIE, 166 NGM_ETHER_GET_AUTOSRC, 167 "getautosrc", 168 NULL, 169 &ng_parse_int32_type 170 }, 171 { 172 NGM_ETHER_COOKIE, 173 NGM_ETHER_SET_AUTOSRC, 174 "setautosrc", 175 &ng_parse_int32_type, 176 NULL 177 }, 178 { 0 } 179}; 180 181static struct ng_type ng_ether_typestruct = { 182 NG_VERSION, 183 NG_ETHER_NODE_TYPE, 184 ng_ether_mod_event, 185 ng_ether_constructor, 186 ng_ether_rcvmsg, 187 ng_ether_rmnode, 188 ng_ether_newhook, 189 NULL, 190 NULL, 191 ng_ether_rcvdata, 192 ng_ether_rcvdata, 193 ng_ether_disconnect, 194 ng_ether_cmdlist, 195}; 196NETGRAPH_INIT(ether, &ng_ether_typestruct); 197 198/****************************************************************** 199 ETHERNET FUNCTION HOOKS 200******************************************************************/ 201 202/* 203 * Handle a packet that has come in on an interface. We get to 204 * look at it here before any upper layer protocols do. 205 * 206 * NOTE: this function will get called at splimp() 207 */ 208static void 209ng_ether_input(struct ifnet *ifp, 210 struct mbuf **mp, struct ether_header *eh) 211{ 212 const node_p node = IFP2NG(ifp); 213 const priv_p priv = node->private; 214 215 /* If "lower" hook not connected, let packet continue */ 216 if (priv->lower == NULL || priv->lowerOrphan) 217 return; 218 ng_ether_input2(node, mp, eh); 219} 220 221/* 222 * Handle a packet that has come in on an interface, and which 223 * does not match any of our known protocols (an ``orphan''). 224 * 225 * NOTE: this function will get called at splimp() 226 */ 227static void 228ng_ether_input_orphan(struct ifnet *ifp, 229 struct mbuf *m, struct ether_header *eh) 230{ 231 const node_p node = IFP2NG(ifp); 232 const priv_p priv = node->private; 233 234 /* If "orphan" hook not connected, let packet continue */ 235 if (priv->lower == NULL || !priv->lowerOrphan) { 236 m_freem(m); 237 return; 238 } 239 ng_ether_input2(node, &m, eh); 240 if (m != NULL) 241 m_freem(m); 242} 243 244/* 245 * Handle a packet that has come in on an interface. 246 * The Ethernet header has already been detached from the mbuf, 247 * so we have to put it back. 248 * 249 * NOTE: this function will get called at splimp() 250 */ 251static void 252ng_ether_input2(node_p node, struct mbuf **mp, struct ether_header *eh) 253{ 254 const priv_p priv = node->private; 255 meta_p meta = NULL; 256 int error; 257 258 /* Glue Ethernet header back on */ 259 if ((error = ng_ether_glueback_header(mp, eh)) != 0) 260 return; 261 262 /* Send out lower/orphan hook */ 263 (void)ng_queue_data(priv->lower, *mp, meta); 264 *mp = NULL; 265} 266 267/* 268 * Handle a packet that is going out on an interface. 269 * The Ethernet header is already attached to the mbuf. 270 */ 271static int 272ng_ether_output(struct ifnet *ifp, struct mbuf **mp) 273{ 274 const node_p node = IFP2NG(ifp); 275 const priv_p priv = node->private; 276 meta_p meta = NULL; 277 int error = 0; 278 279 /* If "upper" hook not connected, let packet continue */ 280 if (priv->upper == NULL) 281 return (0); 282 283 /* Send it out "upper" hook */ 284 NG_SEND_DATA_RET(error, priv->upper, *mp, meta); 285 286 /* If we got a reflected packet back, handle it */ 287 if (error == 0 && *mp != NULL) { 288 error = ng_ether_rcv_upper(node, *mp, meta); 289 *mp = NULL; 290 } 291 return (error); 292} 293 294/* 295 * A new Ethernet interface has been attached. 296 * Create a new node for it, etc. 297 */ 298static void 299ng_ether_attach(struct ifnet *ifp) 300{ 301 char name[IFNAMSIZ + 1]; 302 priv_p priv; 303 node_p node; 304 305 /* Create node */ 306 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__)); 307 snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit); 308 if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 309 log(LOG_ERR, "%s: can't %s for %s\n", 310 __FUNCTION__, "create node", name); 311 return; 312 } 313 314 /* Allocate private data */ 315 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT); 316 if (priv == NULL) { 317 log(LOG_ERR, "%s: can't %s for %s\n", 318 __FUNCTION__, "allocate memory", name); 319 ng_unref(node); 320 return; 321 } 322 bzero(priv, sizeof(*priv)); 323 node->private = priv; 324 priv->ifp = ifp; 325 IFP2NG(ifp) = node; 326 priv->autoSrcAddr = 1; 327 328 /* Try to give the node the same name as the interface */ 329 if (ng_name_node(node, name) != 0) { 330 log(LOG_WARNING, "%s: can't name node %s\n", 331 __FUNCTION__, name); 332 } 333} 334 335/* 336 * An Ethernet interface is being detached. 337 * Destroy its node. 338 */ 339static void 340ng_ether_detach(struct ifnet *ifp) 341{ 342 const node_p node = IFP2NG(ifp); 343 priv_p priv; 344 345 if (node == NULL) /* no node (why not?), ignore */ 346 return; 347 ng_rmnode(node); /* break all links to other nodes */ 348 node->flags |= NG_INVALID; 349 ng_unname(node); /* free name (and its reference) */ 350 IFP2NG(ifp) = NULL; /* detach node from interface */ 351 priv = node->private; /* free node private info */ 352 bzero(priv, sizeof(*priv)); 353 FREE(priv, M_NETGRAPH); 354 node->private = NULL; 355 ng_unref(node); /* free node itself */ 356} 357 358/* 359 * Optimization for gluing the Ethernet header back onto 360 * the front of an incoming packet. 361 */ 362static int 363ng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh) 364{ 365 struct mbuf *m = *mp; 366 uintfptr_t room; 367 int error = 0; 368 369 /* 370 * Possibly the header is already on the front. 371 * If this is the case so just move the markers back 372 * to re-include it. We lucked out. 373 * This allows us to avoid a yucky m_pullup 374 * in later nodes if it works. 375 */ 376 if (eh == mtod(m, struct ether_header *) - 1) { 377 m->m_len += sizeof(*eh); 378 m->m_data -= sizeof(*eh); 379 m->m_pkthdr.len += sizeof(*eh); 380 goto done; 381 } 382 383 /* 384 * Alternatively there may be room even though 385 * it is stored somewhere else. If so, copy it in. 386 * This only safe because we KNOW that this packet has 387 * just been generated by an ethernet card, so there are 388 * no aliases to the buffer (not so for outgoing packets). 389 * Nearly all ethernet cards will end up producing mbufs 390 * that fall into these cases. So we are not optimizing 391 * contorted cases. 392 */ 393 if ((m->m_flags & M_EXT) != 0) { 394 room = mtod(m, caddr_t) - m->m_ext.ext_buf; 395 if (room > m->m_ext.ext_size) /* garbage, fail immediately */ 396 room = 0; 397 } else 398 room = mtod(m, caddr_t) - m->m_pktdat; 399 400 /* 401 * If we have room, just copy it and adjust 402 */ 403 if (room >= sizeof(*eh)) { 404 m->m_len += sizeof(*eh); 405 m->m_data -= sizeof(*eh); 406 m->m_pkthdr.len += sizeof(*eh); 407 goto copy; 408 } 409 410 /* 411 * Doing anything more is likely to get more 412 * expensive than it's worth.. 413 * it's probable that everything else is in one 414 * big lump. The next node will do an m_pullup() 415 * for exactly the amount of data it needs and 416 * hopefully everything after that will not 417 * need one. So let's just use M_PREPEND. 418 */ 419 M_PREPEND(m, sizeof (*eh), M_DONTWAIT); 420 if (m == NULL) { 421 error = ENOBUFS; 422 goto done; 423 } 424 425copy: 426 /* Copy header and return (possibly new) mbuf */ 427 bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh)); 428done: 429 *mp = m; 430 return error; 431} 432 433/****************************************************************** 434 NETGRAPH NODE METHODS 435******************************************************************/ 436 437/* 438 * It is not possible or allowable to create a node of this type. 439 * Nodes get created when the interface is attached (or, when 440 * this node type's KLD is loaded). 441 */ 442static int 443ng_ether_constructor(node_p *nodep) 444{ 445 return (EINVAL); 446} 447 448/* 449 * Check for attaching a new hook. 450 */ 451static int 452ng_ether_newhook(node_p node, hook_p hook, const char *name) 453{ 454 const priv_p priv = node->private; 455 u_char orphan = priv->lowerOrphan; 456 hook_p *hookptr; 457 458 /* Divert hook is an alias for lower */ 459 if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 460 name = NG_ETHER_HOOK_LOWER; 461 462 /* Which hook? */ 463 if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 464 hookptr = &priv->upper; 465 else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 466 hookptr = &priv->lower; 467 orphan = 0; 468 } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 469 hookptr = &priv->lower; 470 orphan = 1; 471 } else 472 return (EINVAL); 473 474 /* Check if already connected (shouldn't be, but doesn't hurt) */ 475 if (*hookptr != NULL) 476 return (EISCONN); 477 478 /* OK */ 479 *hookptr = hook; 480 priv->lowerOrphan = orphan; 481 return (0); 482} 483 484/* 485 * Receive an incoming control message. 486 */ 487static int 488ng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 489 struct ng_mesg **rptr, hook_p lasthook) 490{ 491 const priv_p priv = node->private; 492 struct ng_mesg *resp = NULL; 493 int error = 0; 494 495 switch (msg->header.typecookie) { 496 case NGM_ETHER_COOKIE: 497 switch (msg->header.cmd) { 498 case NGM_ETHER_GET_IFNAME: 499 NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 500 if (resp == NULL) { 501 error = ENOMEM; 502 break; 503 } 504 snprintf(resp->data, IFNAMSIZ + 1, 505 "%s%d", priv->ifp->if_name, priv->ifp->if_unit); 506 break; 507 case NGM_ETHER_GET_IFINDEX: 508 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 509 if (resp == NULL) { 510 error = ENOMEM; 511 break; 512 } 513 *((u_int32_t *)resp->data) = priv->ifp->if_index; 514 break; 515 case NGM_ETHER_GET_ENADDR: 516 NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 517 if (resp == NULL) { 518 error = ENOMEM; 519 break; 520 } 521 bcopy((IFP2AC(priv->ifp))->ac_enaddr, 522 resp->data, ETHER_ADDR_LEN); 523 break; 524 case NGM_ETHER_SET_ENADDR: 525 { 526 if (msg->header.arglen != ETHER_ADDR_LEN) { 527 error = EINVAL; 528 break; 529 } 530 error = if_setlladdr(priv->ifp, 531 (u_char *)msg->data, ETHER_ADDR_LEN); 532 break; 533 } 534 case NGM_ETHER_GET_PROMISC: 535 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 536 if (resp == NULL) { 537 error = ENOMEM; 538 break; 539 } 540 *((u_int32_t *)resp->data) = priv->promisc; 541 break; 542 case NGM_ETHER_SET_PROMISC: 543 { 544 u_char want; 545 546 if (msg->header.arglen != sizeof(u_int32_t)) { 547 error = EINVAL; 548 break; 549 } 550 want = !!*((u_int32_t *)msg->data); 551 if (want ^ priv->promisc) { 552 if ((error = ifpromisc(priv->ifp, want)) != 0) 553 break; 554 priv->promisc = want; 555 } 556 break; 557 } 558 case NGM_ETHER_GET_AUTOSRC: 559 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 560 if (resp == NULL) { 561 error = ENOMEM; 562 break; 563 } 564 *((u_int32_t *)resp->data) = priv->autoSrcAddr; 565 break; 566 case NGM_ETHER_SET_AUTOSRC: 567 if (msg->header.arglen != sizeof(u_int32_t)) { 568 error = EINVAL; 569 break; 570 } 571 priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 572 break; 573 default: 574 error = EINVAL; 575 break; 576 } 577 break; 578 default: 579 error = EINVAL; 580 break; 581 } 582 if (rptr) 583 *rptr = resp; 584 else if (resp != NULL) 585 FREE(resp, M_NETGRAPH); 586 FREE(msg, M_NETGRAPH); 587 return (error); 588} 589 590/* 591 * Receive data on a hook. 592 */ 593static int 594ng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 595 struct mbuf **ret_m, meta_p *ret_meta) 596{ 597 const node_p node = hook->node; 598 const priv_p priv = node->private; 599 600 if (hook == priv->lower) 601 return ng_ether_rcv_lower(node, m, meta); 602 if (hook == priv->upper) 603 return ng_ether_rcv_upper(node, m, meta); 604 panic("%s: weird hook", __FUNCTION__); 605} 606 607/* 608 * Handle an mbuf received on the "lower" hook. 609 */ 610static int 611ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 612{ 613 const priv_p priv = node->private; 614 615 /* Make sure header is fully pulled up */ 616 if (m->m_pkthdr.len < sizeof(struct ether_header)) { 617 NG_FREE_DATA(m, meta); 618 return (EINVAL); 619 } 620 if (m->m_len < sizeof(struct ether_header) 621 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 622 NG_FREE_META(meta); 623 return (ENOBUFS); 624 } 625 626 /* Drop in the MAC address if desired */ 627 if (priv->autoSrcAddr) { 628 bcopy((IFP2AC(priv->ifp))->ac_enaddr, 629 mtod(m, struct ether_header *)->ether_shost, 630 ETHER_ADDR_LEN); 631 } 632 633 /* Send it on its way */ 634 NG_FREE_META(meta); 635 return ether_output_frame(priv->ifp, m); 636} 637 638/* 639 * Handle an mbuf received on the "upper" hook. 640 */ 641static int 642ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 643{ 644 const priv_p priv = node->private; 645 struct ether_header *eh; 646 647 /* Check length and pull off header */ 648 if (m->m_pkthdr.len < sizeof(*eh)) { 649 NG_FREE_DATA(m, meta); 650 return (EINVAL); 651 } 652 if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) { 653 NG_FREE_META(meta); 654 return (ENOBUFS); 655 } 656 eh = mtod(m, struct ether_header *); 657 m->m_data += sizeof(*eh); 658 m->m_len -= sizeof(*eh); 659 m->m_pkthdr.len -= sizeof(*eh); 660 661 /* Route packet back in */ 662 NG_FREE_META(meta); 663 ether_demux(priv->ifp, eh, m); 664 return (0); 665} 666 667/* 668 * Shutdown node. This resets the node but does not remove it. 669 */ 670static int 671ng_ether_rmnode(node_p node) 672{ 673 const priv_p priv = node->private; 674 675 ng_cutlinks(node); 676 node->flags &= ~NG_INVALID; /* bounce back to life */ 677 if (priv->promisc) { /* disable promiscuous mode */ 678 (void)ifpromisc(priv->ifp, 0); 679 priv->promisc = 0; 680 } 681 priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 682 return (0); 683} 684 685/* 686 * Hook disconnection. 687 */ 688static int 689ng_ether_disconnect(hook_p hook) 690{ 691 const priv_p priv = hook->node->private; 692 693 if (hook == priv->upper) 694 priv->upper = NULL; 695 else if (hook == priv->lower) { 696 priv->lower = NULL; 697 priv->lowerOrphan = 0; 698 } else 699 panic("%s: weird hook", __FUNCTION__); 700 return (0); 701} 702 703static int 704ng_enaddr_parse(const struct ng_parse_type *type, 705 const char *s, int *const off, const u_char *const start, 706 u_char *const buf, int *const buflen) 707{ 708 char *eptr; 709 u_long val; 710 int i; 711 712 if (*buflen < ETHER_ADDR_LEN) 713 return (ERANGE); 714 for (i = 0; i < ETHER_ADDR_LEN; i++) { 715 val = strtoul(s + *off, &eptr, 16); 716 if (val > 0xff || eptr == s + *off) 717 return (EINVAL); 718 buf[i] = (u_char)val; 719 *off = (eptr - s); 720 if (i < ETHER_ADDR_LEN - 1) { 721 if (*eptr != ':') 722 return (EINVAL); 723 (*off)++; 724 } 725 } 726 *buflen = ETHER_ADDR_LEN; 727 return (0); 728} 729 730static int 731ng_enaddr_unparse(const struct ng_parse_type *type, 732 const u_char *data, int *off, char *cbuf, int cbuflen) 733{ 734 int len; 735 736 len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 737 data[0], data[1], data[2], data[3], data[4], data[5]); 738 if (len >= cbuflen) 739 return (ERANGE); 740 *off += ETHER_ADDR_LEN; 741 return (0); 742} 743 744/****************************************************************** 745 INITIALIZATION 746******************************************************************/ 747 748/* 749 * Handle loading and unloading for this node type. 750 */ 751static int 752ng_ether_mod_event(module_t mod, int event, void *data) 753{ 754 struct ifnet *ifp; 755 int error = 0; 756 int s; 757 758 s = splnet(); 759 switch (event) { 760 case MOD_LOAD: 761 762 /* Register function hooks */ 763 if (ng_ether_attach_p != NULL) { 764 error = EEXIST; 765 break; 766 } 767 ng_ether_attach_p = ng_ether_attach; 768 ng_ether_detach_p = ng_ether_detach; 769 ng_ether_output_p = ng_ether_output; 770 ng_ether_input_p = ng_ether_input; 771 ng_ether_input_orphan_p = ng_ether_input_orphan; 772 773 /* Create nodes for any already-existing Ethernet interfaces */ 774 TAILQ_FOREACH(ifp, &ifnet, if_link) { 775 if (ifp->if_type == IFT_ETHER) 776 ng_ether_attach(ifp); 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 break; 797 798 default: 799 error = EOPNOTSUPP; 800 break; 801 } 802 splx(s); 803 return (error); 804} 805 806