ng_ether.c revision 121816
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: head/sys/netgraph/ng_ether.c 121816 2003-10-31 18:32:15Z brooks $ 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 u_long hwassist; /* hardware checksum capabilities */ 79 u_int flags; /* flags e.g. really die */ 80}; 81typedef struct private *priv_p; 82 83/* Hook pointers used by if_ethersubr.c to callback to netgraph */ 84extern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); 85extern void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); 86extern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp); 87extern void (*ng_ether_attach_p)(struct ifnet *ifp); 88extern void (*ng_ether_detach_p)(struct ifnet *ifp); 89 90/* Functional hooks called from if_ethersubr.c */ 91static void ng_ether_input(struct ifnet *ifp, struct mbuf **mp); 92static void ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m); 93static int ng_ether_output(struct ifnet *ifp, struct mbuf **mp); 94static void ng_ether_attach(struct ifnet *ifp); 95static void ng_ether_detach(struct ifnet *ifp); 96 97/* Other functions */ 98static void ng_ether_input2(node_p node, struct mbuf **mp); 99static int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta); 100static int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta); 101 102/* Netgraph node methods */ 103static ng_constructor_t ng_ether_constructor; 104static ng_rcvmsg_t ng_ether_rcvmsg; 105static ng_shutdown_t ng_ether_shutdown; 106static ng_newhook_t ng_ether_newhook; 107static ng_connect_t ng_ether_connect; 108static ng_rcvdata_t ng_ether_rcvdata; 109static ng_disconnect_t ng_ether_disconnect; 110static int ng_ether_mod_event(module_t mod, int event, void *data); 111 112/* Parse type for an Ethernet address */ 113static ng_parse_t ng_enaddr_parse; 114static ng_unparse_t ng_enaddr_unparse; 115const struct ng_parse_type ng_ether_enaddr_type = { 116 NULL, 117 NULL, 118 NULL, 119 ng_enaddr_parse, 120 ng_enaddr_unparse, 121 NULL, /* no such thing as a "default" EN address */ 122 0 123}; 124 125/* List of commands and how to convert arguments to/from ASCII */ 126static const struct ng_cmdlist ng_ether_cmdlist[] = { 127 { 128 NGM_ETHER_COOKIE, 129 NGM_ETHER_GET_IFNAME, 130 "getifname", 131 NULL, 132 &ng_parse_string_type 133 }, 134 { 135 NGM_ETHER_COOKIE, 136 NGM_ETHER_GET_IFINDEX, 137 "getifindex", 138 NULL, 139 &ng_parse_int32_type 140 }, 141 { 142 NGM_ETHER_COOKIE, 143 NGM_ETHER_GET_ENADDR, 144 "getenaddr", 145 NULL, 146 &ng_ether_enaddr_type 147 }, 148 { 149 NGM_ETHER_COOKIE, 150 NGM_ETHER_SET_ENADDR, 151 "setenaddr", 152 &ng_ether_enaddr_type, 153 NULL 154 }, 155 { 156 NGM_ETHER_COOKIE, 157 NGM_ETHER_GET_PROMISC, 158 "getpromisc", 159 NULL, 160 &ng_parse_int32_type 161 }, 162 { 163 NGM_ETHER_COOKIE, 164 NGM_ETHER_SET_PROMISC, 165 "setpromisc", 166 &ng_parse_int32_type, 167 NULL 168 }, 169 { 170 NGM_ETHER_COOKIE, 171 NGM_ETHER_GET_AUTOSRC, 172 "getautosrc", 173 NULL, 174 &ng_parse_int32_type 175 }, 176 { 177 NGM_ETHER_COOKIE, 178 NGM_ETHER_SET_AUTOSRC, 179 "setautosrc", 180 &ng_parse_int32_type, 181 NULL 182 }, 183 { 0 } 184}; 185 186static struct ng_type ng_ether_typestruct = { 187 NG_ABI_VERSION, 188 NG_ETHER_NODE_TYPE, 189 ng_ether_mod_event, 190 ng_ether_constructor, 191 ng_ether_rcvmsg, 192 ng_ether_shutdown, 193 ng_ether_newhook, 194 NULL, 195 ng_ether_connect, 196 ng_ether_rcvdata, 197 ng_ether_disconnect, 198 ng_ether_cmdlist, 199}; 200MODULE_VERSION(ng_ether, 1); 201NETGRAPH_INIT(ether, &ng_ether_typestruct); 202 203/****************************************************************** 204 ETHERNET FUNCTION HOOKS 205******************************************************************/ 206 207/* 208 * Handle a packet that has come in on an interface. We get to 209 * look at it here before any upper layer protocols do. 210 * 211 * NOTE: this function will get called at splimp() 212 */ 213static void 214ng_ether_input(struct ifnet *ifp, struct mbuf **mp) 215{ 216 const node_p node = IFP2NG(ifp); 217 const priv_p priv = NG_NODE_PRIVATE(node); 218 219 /* If "lower" hook not connected, let packet continue */ 220 if (priv->lower == NULL || priv->lowerOrphan) 221 return; 222 ng_ether_input2(node, mp); 223} 224 225/* 226 * Handle a packet that has come in on an interface, and which 227 * does not match any of our known protocols (an ``orphan''). 228 * 229 * NOTE: this function will get called at splimp() 230 */ 231static void 232ng_ether_input_orphan(struct ifnet *ifp, struct mbuf *m) 233{ 234 const node_p node = IFP2NG(ifp); 235 const priv_p priv = NG_NODE_PRIVATE(node); 236 237 /* If "orphan" hook not connected, let packet continue */ 238 if (priv->lower == NULL || !priv->lowerOrphan) { 239 m_freem(m); 240 return; 241 } 242 ng_ether_input2(node, &m); 243 if (m != NULL) 244 m_freem(m); 245} 246 247/* 248 * Handle a packet that has come in on an ethernet interface. 249 * The Ethernet header has already been detached from the mbuf, 250 * so we have to put it back. 251 * 252 * NOTE: this function will get called at splimp() 253 */ 254static void 255ng_ether_input2(node_p node, struct mbuf **mp) 256{ 257 const priv_p priv = NG_NODE_PRIVATE(node); 258 int error; 259 260 /* Send out lower/orphan hook */ 261 NG_SEND_DATA_ONLY(error, priv->lower, *mp); 262 *mp = NULL; 263} 264 265/* 266 * Handle a packet that is going out on an interface. 267 * The Ethernet header is already attached to the mbuf. 268 */ 269static int 270ng_ether_output(struct ifnet *ifp, struct mbuf **mp) 271{ 272 const node_p node = IFP2NG(ifp); 273 const priv_p priv = NG_NODE_PRIVATE(node); 274 int error = 0; 275 276 /* If "upper" hook not connected, let packet continue */ 277 if (priv->upper == NULL) 278 return (0); 279 280 /* Send it out "upper" hook */ 281 NG_SEND_DATA_ONLY(error, priv->upper, *mp); 282 return (error); 283} 284 285/* 286 * A new Ethernet interface has been attached. 287 * Create a new node for it, etc. 288 */ 289static void 290ng_ether_attach(struct ifnet *ifp) 291{ 292 priv_p priv; 293 node_p node; 294 295 /* Create node */ 296 KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __func__)); 297 if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) { 298 log(LOG_ERR, "%s: can't %s for %s\n", 299 __func__, "create node", ifp->if_xname); 300 return; 301 } 302 303 /* Allocate private data */ 304 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO); 305 if (priv == NULL) { 306 log(LOG_ERR, "%s: can't %s for %s\n", 307 __func__, "allocate memory", ifp->if_xname); 308 NG_NODE_UNREF(node); 309 return; 310 } 311 NG_NODE_SET_PRIVATE(node, priv); 312 priv->ifp = ifp; 313 IFP2NG(ifp) = node; 314 priv->autoSrcAddr = 1; 315 priv->hwassist = ifp->if_hwassist; 316 317 /* Try to give the node the same name as the interface */ 318 if (ng_name_node(node, ifp->if_xname) != 0) { 319 log(LOG_WARNING, "%s: can't name node %s\n", 320 __func__, ifp->if_xname); 321 } 322} 323 324/* 325 * An Ethernet interface is being detached. 326 * REALLY Destroy its node. 327 */ 328static void 329ng_ether_detach(struct ifnet *ifp) 330{ 331 const node_p node = IFP2NG(ifp); 332 const priv_p priv = NG_NODE_PRIVATE(node); 333 334 if (node == NULL) /* no node (why not?), ignore */ 335 return; 336 NG_NODE_REALLY_DIE(node); /* Force real removal of node */ 337 /* 338 * We can't assume the ifnet is still around when we run shutdown 339 * So zap it now. XXX We HOPE that anything running at this time 340 * handles it (as it should in the non netgraph case). 341 */ 342 IFP2NG(ifp) = NULL; 343 priv->ifp = NULL; /* XXX race if interrupted an output packet */ 344 ng_rmnode_self(node); /* remove all netgraph parts */ 345} 346 347/****************************************************************** 348 NETGRAPH NODE METHODS 349******************************************************************/ 350 351/* 352 * It is not possible or allowable to create a node of this type. 353 * Nodes get created when the interface is attached (or, when 354 * this node type's KLD is loaded). 355 */ 356static int 357ng_ether_constructor(node_p node) 358{ 359 return (EINVAL); 360} 361 362/* 363 * Check for attaching a new hook. 364 */ 365static int 366ng_ether_newhook(node_p node, hook_p hook, const char *name) 367{ 368 const priv_p priv = NG_NODE_PRIVATE(node); 369 u_char orphan = priv->lowerOrphan; 370 hook_p *hookptr; 371 372 /* Divert hook is an alias for lower */ 373 if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0) 374 name = NG_ETHER_HOOK_LOWER; 375 376 /* Which hook? */ 377 if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0) 378 hookptr = &priv->upper; 379 else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) { 380 hookptr = &priv->lower; 381 orphan = 0; 382 } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) { 383 hookptr = &priv->lower; 384 orphan = 1; 385 } else 386 return (EINVAL); 387 388 /* Check if already connected (shouldn't be, but doesn't hurt) */ 389 if (*hookptr != NULL) 390 return (EISCONN); 391 392 /* Disable hardware checksums while 'upper' hook is connected */ 393 if (hookptr == &priv->upper) 394 priv->ifp->if_hwassist = 0; 395 396 /* OK */ 397 *hookptr = hook; 398 priv->lowerOrphan = orphan; 399 return (0); 400} 401 402/* 403 * Hooks are attached, adjust to force queueing. 404 * We don't really care which hook it is. 405 * they should all be queuing for outgoing data. 406 */ 407static int 408ng_ether_connect(hook_p hook) 409{ 410 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 411 return (0); 412} 413 414/* 415 * Receive an incoming control message. 416 */ 417static int 418ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook) 419{ 420 const priv_p priv = NG_NODE_PRIVATE(node); 421 struct ng_mesg *resp = NULL; 422 int error = 0; 423 struct ng_mesg *msg; 424 425 NGI_GET_MSG(item, msg); 426 switch (msg->header.typecookie) { 427 case NGM_ETHER_COOKIE: 428 switch (msg->header.cmd) { 429 case NGM_ETHER_GET_IFNAME: 430 NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT); 431 if (resp == NULL) { 432 error = ENOMEM; 433 break; 434 } 435 strlcpy(resp->data, priv->ifp->if_xname, IFNAMSIZ + 1); 436 break; 437 case NGM_ETHER_GET_IFINDEX: 438 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 439 if (resp == NULL) { 440 error = ENOMEM; 441 break; 442 } 443 *((u_int32_t *)resp->data) = priv->ifp->if_index; 444 break; 445 case NGM_ETHER_GET_ENADDR: 446 NG_MKRESPONSE(resp, msg, ETHER_ADDR_LEN, M_NOWAIT); 447 if (resp == NULL) { 448 error = ENOMEM; 449 break; 450 } 451 bcopy((IFP2AC(priv->ifp))->ac_enaddr, 452 resp->data, ETHER_ADDR_LEN); 453 break; 454 case NGM_ETHER_SET_ENADDR: 455 { 456 if (msg->header.arglen != ETHER_ADDR_LEN) { 457 error = EINVAL; 458 break; 459 } 460 error = if_setlladdr(priv->ifp, 461 (u_char *)msg->data, ETHER_ADDR_LEN); 462 break; 463 } 464 case NGM_ETHER_GET_PROMISC: 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->promisc; 471 break; 472 case NGM_ETHER_SET_PROMISC: 473 { 474 u_char want; 475 476 if (msg->header.arglen != sizeof(u_int32_t)) { 477 error = EINVAL; 478 break; 479 } 480 want = !!*((u_int32_t *)msg->data); 481 if (want ^ priv->promisc) { 482 if ((error = ifpromisc(priv->ifp, want)) != 0) 483 break; 484 priv->promisc = want; 485 } 486 break; 487 } 488 case NGM_ETHER_GET_AUTOSRC: 489 NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT); 490 if (resp == NULL) { 491 error = ENOMEM; 492 break; 493 } 494 *((u_int32_t *)resp->data) = priv->autoSrcAddr; 495 break; 496 case NGM_ETHER_SET_AUTOSRC: 497 if (msg->header.arglen != sizeof(u_int32_t)) { 498 error = EINVAL; 499 break; 500 } 501 priv->autoSrcAddr = !!*((u_int32_t *)msg->data); 502 break; 503 default: 504 error = EINVAL; 505 break; 506 } 507 break; 508 default: 509 error = EINVAL; 510 break; 511 } 512 NG_RESPOND_MSG(error, node, item, resp); 513 NG_FREE_MSG(msg); 514 return (error); 515} 516 517/* 518 * Receive data on a hook. 519 */ 520static int 521ng_ether_rcvdata(hook_p hook, item_p item) 522{ 523 const node_p node = NG_HOOK_NODE(hook); 524 const priv_p priv = NG_NODE_PRIVATE(node); 525 struct mbuf *m; 526 meta_p meta; 527 528 NGI_GET_M(item, m); 529 NGI_GET_META(item, meta); 530 NG_FREE_ITEM(item); 531 if (hook == priv->lower) 532 return ng_ether_rcv_lower(node, m, meta); 533 if (hook == priv->upper) 534 return ng_ether_rcv_upper(node, m, meta); 535 panic("%s: weird hook", __func__); 536#ifdef RESTARTABLE_PANICS /* so we don;t get an error msg in LINT */ 537 return NULL; 538#endif 539} 540 541/* 542 * Handle an mbuf received on the "lower" hook. 543 */ 544static int 545ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta) 546{ 547 const priv_p priv = NG_NODE_PRIVATE(node); 548 struct ifnet *const ifp = priv->ifp; 549 550 /* Discard meta info */ 551 NG_FREE_META(meta); 552 553 /* Check whether interface is ready for packets */ 554 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 555 NG_FREE_M(m); 556 return (ENETDOWN); 557 } 558 559 /* Make sure header is fully pulled up */ 560 if (m->m_pkthdr.len < sizeof(struct ether_header)) { 561 NG_FREE_M(m); 562 return (EINVAL); 563 } 564 if (m->m_len < sizeof(struct ether_header) 565 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 566 return (ENOBUFS); 567 568 /* Drop in the MAC address if desired */ 569 if (priv->autoSrcAddr) { 570 571 /* Make the mbuf writable if it's not already */ 572 if (!M_WRITABLE(m) 573 && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) 574 return (ENOBUFS); 575 576 /* Overwrite source MAC address */ 577 bcopy((IFP2AC(ifp))->ac_enaddr, 578 mtod(m, struct ether_header *)->ether_shost, 579 ETHER_ADDR_LEN); 580 } 581 582 /* Send it on its way */ 583 return ether_output_frame(ifp, m); 584} 585 586/* 587 * Handle an mbuf received on the "upper" hook. 588 */ 589static int 590ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta) 591{ 592 const priv_p priv = NG_NODE_PRIVATE(node); 593 594 /* Discard meta info */ 595 NG_FREE_META(meta); 596 597 m->m_pkthdr.rcvif = priv->ifp; 598 599 /* Route packet back in */ 600 ether_demux(priv->ifp, m); 601 return (0); 602} 603 604/* 605 * Shutdown node. This resets the node but does not remove it 606 * unless the REALLY_DIE flag is set. 607 */ 608static int 609ng_ether_shutdown(node_p node) 610{ 611 const priv_p priv = NG_NODE_PRIVATE(node); 612 613 if (priv->promisc) { /* disable promiscuous mode */ 614 (void)ifpromisc(priv->ifp, 0); 615 priv->promisc = 0; 616 } 617 if (node->nd_flags & NG_REALLY_DIE) { 618 /* 619 * WE came here because the ethernet card is being unloaded, 620 * so stop being persistant. 621 * Actually undo all the things we did on creation. 622 * Assume the ifp has already been freed. 623 */ 624 NG_NODE_SET_PRIVATE(node, NULL); 625 FREE(priv, M_NETGRAPH); 626 NG_NODE_UNREF(node); /* free node itself */ 627 return (0); 628 } 629 priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ 630 node->nd_flags &= ~NG_INVALID; /* Signal ng_rmnode we are persisant */ 631 return (0); 632} 633 634/* 635 * Hook disconnection. 636 */ 637static int 638ng_ether_disconnect(hook_p hook) 639{ 640 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 641 642 if (hook == priv->upper) { 643 priv->upper = NULL; 644 priv->ifp->if_hwassist = priv->hwassist; /* restore h/w csum */ 645 } else if (hook == priv->lower) { 646 priv->lower = NULL; 647 priv->lowerOrphan = 0; 648 } else 649 panic("%s: weird hook", __func__); 650 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 651 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 652 ng_rmnode_self(NG_HOOK_NODE(hook)); /* reset node */ 653 return (0); 654} 655 656static int 657ng_enaddr_parse(const struct ng_parse_type *type, 658 const char *s, int *const off, const u_char *const start, 659 u_char *const buf, int *const buflen) 660{ 661 char *eptr; 662 u_long val; 663 int i; 664 665 if (*buflen < ETHER_ADDR_LEN) 666 return (ERANGE); 667 for (i = 0; i < ETHER_ADDR_LEN; i++) { 668 val = strtoul(s + *off, &eptr, 16); 669 if (val > 0xff || eptr == s + *off) 670 return (EINVAL); 671 buf[i] = (u_char)val; 672 *off = (eptr - s); 673 if (i < ETHER_ADDR_LEN - 1) { 674 if (*eptr != ':') 675 return (EINVAL); 676 (*off)++; 677 } 678 } 679 *buflen = ETHER_ADDR_LEN; 680 return (0); 681} 682 683static int 684ng_enaddr_unparse(const struct ng_parse_type *type, 685 const u_char *data, int *off, char *cbuf, int cbuflen) 686{ 687 int len; 688 689 len = snprintf(cbuf, cbuflen, "%02x:%02x:%02x:%02x:%02x:%02x", 690 data[*off], data[*off + 1], data[*off + 2], 691 data[*off + 3], data[*off + 4], data[*off + 5]); 692 if (len >= cbuflen) 693 return (ERANGE); 694 *off += ETHER_ADDR_LEN; 695 return (0); 696} 697 698/****************************************************************** 699 INITIALIZATION 700******************************************************************/ 701 702/* 703 * Handle loading and unloading for this node type. 704 */ 705static int 706ng_ether_mod_event(module_t mod, int event, void *data) 707{ 708 struct ifnet *ifp; 709 int error = 0; 710 int s; 711 712 s = splnet(); 713 switch (event) { 714 case MOD_LOAD: 715 716 /* Register function hooks */ 717 if (ng_ether_attach_p != NULL) { 718 error = EEXIST; 719 break; 720 } 721 ng_ether_attach_p = ng_ether_attach; 722 ng_ether_detach_p = ng_ether_detach; 723 ng_ether_output_p = ng_ether_output; 724 ng_ether_input_p = ng_ether_input; 725 ng_ether_input_orphan_p = ng_ether_input_orphan; 726 727 /* Create nodes for any already-existing Ethernet interfaces */ 728 IFNET_RLOCK(); 729 TAILQ_FOREACH(ifp, &ifnet, if_link) { 730 if (ifp->if_type == IFT_ETHER 731 || ifp->if_type == IFT_L2VLAN) 732 ng_ether_attach(ifp); 733 } 734 IFNET_RUNLOCK(); 735 break; 736 737 case MOD_UNLOAD: 738 739 /* 740 * Note that the base code won't try to unload us until 741 * all nodes have been removed, and that can't happen 742 * until all Ethernet interfaces are removed. In any 743 * case, we know there are no nodes left if the action 744 * is MOD_UNLOAD, so there's no need to detach any nodes. 745 */ 746 747 /* Unregister function hooks */ 748 ng_ether_attach_p = NULL; 749 ng_ether_detach_p = NULL; 750 ng_ether_output_p = NULL; 751 ng_ether_input_p = NULL; 752 ng_ether_input_orphan_p = NULL; 753 break; 754 755 default: 756 error = EOPNOTSUPP; 757 break; 758 } 759 splx(s); 760 return (error); 761} 762 763