1 /* 2 * ng_fec.c 3 */ 4 5 /*- 6 * Copyright (c) 2001 Berkeley Software Design, Inc. 7 * Copyright (c) 2000, 2001 8 * Bill Paul <wpaul@osd.bsdi.com>. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Bill Paul. 21 * 4. Neither the name of the author nor the names of any co-contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 * THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * $FreeBSD: src/sys/netgraph/ng_fec.c,v 1.30 2007/05/18 15:05:49 dwmalone Exp $ 38 */ 39 /*- 40 * Copyright (c) 1996-1999 Whistle Communications, Inc. 41 * All rights reserved. 42 * 43 * Subject to the following obligations and disclaimer of warranty, use and 44 * redistribution of this software, in source or object code forms, with or 45 * without modifications are expressly permitted by Whistle Communications; 46 * provided, however, that: 47 * 1. Any and all reproductions of the source or object code must include the 48 * copyright notice above and the following disclaimer of warranties; and 49 * 2. No rights are granted, in any manner or form, to use Whistle 50 * Communications, Inc. trademarks, including the mark "WHISTLE 51 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 52 * such appears in the above copyright notice or in the software. 53 * 54 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 55 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 56 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 57 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 58 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 59 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 60 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 61 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 62 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 63 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 64 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 65 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 66 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 67 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 69 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 70 * OF SUCH DAMAGE. 71 * 72 * Author: Archie Cobbs <archie@freebsd.org> 73 * 74 * $Whistle: ng_fec.c,v 1.33 1999/11/01 09:24:51 julian Exp $ 75 */ 76 77 /* 78 * This module implements ethernet channel bonding using the Cisco 79 * Fast EtherChannel mechanism. Two or four ports may be combined 80 * into a single aggregate interface. 81 * 82 * Interfaces are named fec0, fec1, etc. New nodes take the 83 * first available interface name. 84 * 85 * This node also includes Berkeley packet filter support. 86 * 87 * Note that this node doesn't need to connect to any other 88 * netgraph nodes in order to do its work. 89 */ 90 91 #include <sys/param.h> 92 #include <sys/systm.h> 93 #include <sys/errno.h> 94 #include <sys/kernel.h> 95 #include <sys/malloc.h> 96 #include <sys/mbuf.h> 97 #include <sys/sockio.h> 98 #include <sys/socket.h> 99 #include <sys/syslog.h> 100 #include <sys/libkern.h> 101 #include <sys/queue.h> 102 103 #include <net/if.h> 104 #include <net/if_dl.h> 105 #include <net/if_types.h> 106 #include <net/if_media.h> 107 #include <net/bpf.h> 108 #include <net/ethernet.h> 109 110 #include "opt_inet.h" 111 #include "opt_inet6.h" 112 113 #include <netinet/in.h> 114 #ifdef INET 115 #include <netinet/in_systm.h> 116 #include <netinet/ip.h> 117 #endif 118 119 #ifdef INET6 120 #include <netinet/ip6.h> 121 #endif 122 123 #include "ng_message.h" 124 #include "netgraph.h" 125 #include "ng_parse.h" 126 #include "ng_fec.h" 127 128 /* 129 * We need a way to stash a pointer to our netgraph node in the 130 * ifnet structure so that receive handling works. As far as I can 131 * tell, although there is an AF_NETGRAPH address family, it's only 132 * used to identify sockaddr_ng structures: there is no netgraph address 133 * family domain. This means the AF_NETGRAPH entry in ifp->if_afdata 134 * should be unused, so we can use to hold our node context. 135 */ 136 #define IFP2NG(ifp) ((ifp)->if_afdata[AF_NETGRAPH]) 137 138 /* 139 * Current fast etherchannel implementations use either 2 or 4 140 * ports, so for now we limit the maximum bundle size to 4 interfaces. 141 */ 142 #define FEC_BUNDLESIZ 4 143 144 struct ng_fec_portlist { 145 struct ifnet *fec_if; 146 void (*fec_if_input) (struct ifnet *, 147 struct mbuf *); 148 int fec_idx; 149 int fec_ifstat; 150 struct ether_addr fec_mac; 151 SLIST_HEAD(__mclhd, ng_fec_mc) fec_mc_head; 152 TAILQ_ENTRY(ng_fec_portlist) fec_list; 153 }; 154 155 struct ng_fec_mc { 156 struct ifmultiaddr *mc_ifma; 157 SLIST_ENTRY(ng_fec_mc) mc_entries; 158 }; 159 160 struct ng_fec_bundle { 161 TAILQ_HEAD(,ng_fec_portlist) ng_fec_ports; 162 int fec_ifcnt; 163 int fec_btype; 164 int (*fec_if_output) (struct ifnet *, 165 struct mbuf *, 166 struct sockaddr *, 167 struct rtentry *); 168 }; 169 170 #define FEC_BTYPE_MAC 0x01 171 #define FEC_BTYPE_INET 0x02 172 #define FEC_BTYPE_INET6 0x03 173 174 /* Node private data */ 175 struct ng_fec_private { 176 struct ifnet *ifp; 177 struct ifmedia ifmedia; 178 int if_flags; 179 int if_error; /* XXX */ 180 int unit; /* Interface unit number */ 181 node_p node; /* Our netgraph node */ 182 struct ng_fec_bundle fec_bundle;/* Aggregate bundle */ 183 struct callout_handle fec_ch; /* callout handle for ticker */ 184 }; 185 typedef struct ng_fec_private *priv_p; 186 187 /* Interface methods */ 188 static void ng_fec_input(struct ifnet *, struct mbuf *); 189 static void ng_fec_start(struct ifnet *ifp, struct ifaltq_subque *); 190 static int ng_fec_choose_port(struct ng_fec_bundle *b, 191 struct mbuf *m, struct ifnet **ifp); 192 static int ng_fec_setport(struct ifnet *ifp, u_long cmd, caddr_t data); 193 static void ng_fec_init(void *arg); 194 static void ng_fec_stop(struct ifnet *ifp); 195 static int ng_fec_ifmedia_upd(struct ifnet *ifp); 196 static void ng_fec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 197 static int ng_fec_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 198 static int ng_fec_output(struct ifnet *ifp, struct mbuf *m0, 199 struct sockaddr *dst, struct rtentry *rt0); 200 static void ng_fec_tick(void *arg); 201 static int ng_fec_addport(struct ng_fec_private *priv, char *iface); 202 static int ng_fec_delport(struct ng_fec_private *priv, char *iface); 203 static int ng_fec_ether_cmdmulti(struct ifnet *trifp, struct ng_fec_portlist *p, int set); 204 205 #ifdef DEBUG 206 static void ng_fec_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 207 #endif 208 209 /* Netgraph methods */ 210 static int ng_fec_mod_event(module_t, int, void *); 211 static ng_constructor_t ng_fec_constructor; 212 static ng_rcvmsg_t ng_fec_rcvmsg; 213 static ng_shutdown_t ng_fec_shutdown; 214 215 /* List of commands and how to convert arguments to/from ASCII */ 216 static const struct ng_cmdlist ng_fec_cmds[] = { 217 { 218 NGM_FEC_COOKIE, 219 NGM_FEC_ADD_IFACE, 220 "add_iface", 221 &ng_parse_string_type, 222 NULL, 223 }, 224 { 225 NGM_FEC_COOKIE, 226 NGM_FEC_DEL_IFACE, 227 "del_iface", 228 &ng_parse_string_type, 229 NULL, 230 }, 231 { 232 NGM_FEC_COOKIE, 233 NGM_FEC_SET_MODE_MAC, 234 "set_mode_mac", 235 NULL, 236 NULL, 237 }, 238 { 239 NGM_FEC_COOKIE, 240 NGM_FEC_SET_MODE_INET, 241 "set_mode_inet", 242 NULL, 243 NULL, 244 }, 245 { 0 } 246 }; 247 248 /* Node type descriptor */ 249 static struct ng_type typestruct = { 250 .version = NG_ABI_VERSION, 251 .name = NG_FEC_NODE_TYPE, 252 .mod_event = ng_fec_mod_event, 253 .constructor = ng_fec_constructor, 254 .rcvmsg = ng_fec_rcvmsg, 255 .shutdown = ng_fec_shutdown, 256 .cmdlist = ng_fec_cmds, 257 }; 258 NETGRAPH_INIT(fec, &typestruct); 259 260 /* We keep a bitmap indicating which unit numbers are free. 261 One means the unit number is free, zero means it's taken. */ 262 static int *ng_fec_units = NULL; 263 static int ng_fec_units_len = 0; 264 static int ng_units_in_use = 0; 265 266 #define UNITS_BITSPERWORD (sizeof(*ng_fec_units) * NBBY) 267 268 static struct mtx ng_fec_mtx; 269 270 /* 271 * Find the first free unit number for a new interface. 272 * Increase the size of the unit bitmap as necessary. 273 */ 274 static __inline int 275 ng_fec_get_unit(int *unit) 276 { 277 int index, bit; 278 279 mtx_lock(&ng_fec_mtx); 280 for (index = 0; index < ng_fec_units_len 281 && ng_fec_units[index] == 0; index++); 282 if (index == ng_fec_units_len) { /* extend array */ 283 int i, *newarray, newlen; 284 285 newlen = (2 * ng_fec_units_len) + 4; 286 newarray = kmalloc(newlen * sizeof(*ng_fec_units), 287 M_NETGRAPH, M_WAITOK | M_NULLOK); 288 if (newarray == NULL) { 289 mtx_unlock(&ng_fec_mtx); 290 return (ENOMEM); 291 } 292 bcopy(ng_fec_units, newarray, 293 ng_fec_units_len * sizeof(*ng_fec_units)); 294 for (i = ng_fec_units_len; i < newlen; i++) 295 newarray[i] = ~0; 296 if (ng_fec_units != NULL) 297 kfree(ng_fec_units, M_NETGRAPH); 298 ng_fec_units = newarray; 299 ng_fec_units_len = newlen; 300 } 301 bit = ffs(ng_fec_units[index]) - 1; 302 KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1, 303 ("%s: word=%d bit=%d", __func__, ng_fec_units[index], bit)); 304 ng_fec_units[index] &= ~(1 << bit); 305 *unit = (index * UNITS_BITSPERWORD) + bit; 306 ng_units_in_use++; 307 mtx_unlock(&ng_fec_mtx); 308 return (0); 309 } 310 311 /* 312 * Free a no longer needed unit number. 313 */ 314 static __inline void 315 ng_fec_free_unit(int unit) 316 { 317 int index, bit; 318 319 index = unit / UNITS_BITSPERWORD; 320 bit = unit % UNITS_BITSPERWORD; 321 mtx_lock(&ng_fec_mtx); 322 KASSERT(index < ng_fec_units_len, 323 ("%s: unit=%d len=%d", __func__, unit, ng_fec_units_len)); 324 KASSERT((ng_fec_units[index] & (1 << bit)) == 0, 325 ("%s: unit=%d is free", __func__, unit)); 326 ng_fec_units[index] |= (1 << bit); 327 /* 328 * XXX We could think about reducing the size of ng_fec_units[] 329 * XXX here if the last portion is all ones 330 * XXX At least free it if no more units 331 * Needed if we are to eventually be able to unload. 332 */ 333 ng_units_in_use--; 334 if (ng_units_in_use == 0) { /* XXX make SMP safe */ 335 kfree(ng_fec_units, M_NETGRAPH); 336 ng_fec_units_len = 0; 337 ng_fec_units = NULL; 338 } 339 mtx_unlock(&ng_fec_mtx); 340 } 341 342 /************************************************************************ 343 INTERFACE STUFF 344 ************************************************************************/ 345 346 static int 347 ng_fec_addport(struct ng_fec_private *priv, char *iface) 348 { 349 struct ng_fec_bundle *b; 350 struct ifnet *ifp, *bifp; 351 struct ng_fec_portlist *p, *new; 352 353 if (priv == NULL || iface == NULL) 354 return(EINVAL); 355 356 b = &priv->fec_bundle; 357 ifp = priv->ifp; 358 359 /* Only allow reconfiguration if not running. */ 360 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 361 printf("fec%d: can't add new iface; bundle is running\n", 362 priv->unit); 363 return (EINVAL); 364 } 365 366 /* Find the interface */ 367 bifp = ifunit(iface); 368 if (bifp == NULL) { 369 printf("fec%d: tried to add iface %s, which " 370 "doesn't seem to exist\n", priv->unit, iface); 371 return(ENOENT); 372 } 373 374 /* See if we have room in the bundle */ 375 if (b->fec_ifcnt == FEC_BUNDLESIZ) { 376 printf("fec%d: can't add new iface; bundle is full\n", 377 priv->unit); 378 return(ENOSPC); 379 } 380 381 /* See if the interface is already in the bundle */ 382 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 383 if (p->fec_if == bifp) { 384 printf("fec%d: iface %s is already in this " 385 "bundle\n", priv->unit, iface); 386 return(EINVAL); 387 } 388 } 389 390 /* 391 * All interfaces must use the same output vector. Once the 392 * user attaches an interface of one type, make all subsequent 393 * interfaces have the same output vector. 394 */ 395 if (b->fec_if_output != NULL) { 396 if (b->fec_if_output != bifp->if_output) { 397 printf("fec%d: iface %s is not the same type " 398 "as the other interface(s) already in " 399 "the bundle\n", priv->unit, iface); 400 return(EINVAL); 401 } 402 } 403 404 /* Allocate new list entry. */ 405 new = kmalloc(sizeof(struct ng_fec_portlist), M_NETGRAPH, 406 M_WAITOK | M_NULLOK); 407 if (new == NULL) 408 return(ENOMEM); 409 410 IF_AFDATA_LOCK(bifp); 411 IFP2NG(bifp) = priv->node; 412 IF_AFDATA_UNLOCK(bifp); 413 414 /* 415 * If this is the first interface added to the bundle, 416 * use its MAC address for the virtual interface (and, 417 * by extension, all the other ports in the bundle). 418 */ 419 if (b->fec_ifcnt == 0) 420 if_setlladdr(ifp, IF_LLADDR(bifp), ETHER_ADDR_LEN); 421 422 b->fec_btype = FEC_BTYPE_MAC; 423 new->fec_idx = b->fec_ifcnt; 424 b->fec_ifcnt++; 425 426 /* Initialise the list of multicast addresses that we own. */ 427 SLIST_INIT(&new->fec_mc_head); 428 429 /* Save the real MAC address. */ 430 bcopy(IF_LLADDR(bifp), 431 (char *)&new->fec_mac, ETHER_ADDR_LEN); 432 433 /* Set up phony MAC address. */ 434 if_setlladdr(bifp, IF_LLADDR(ifp), ETHER_ADDR_LEN); 435 436 /* Save original input vector */ 437 new->fec_if_input = bifp->if_input; 438 439 /* Override it with our own */ 440 bifp->if_input = ng_fec_input; 441 442 /* Save output vector too. */ 443 if (b->fec_if_output == NULL) 444 b->fec_if_output = bifp->if_output; 445 446 /* Add to the queue */ 447 new->fec_if = bifp; 448 new->fec_ifstat = -1; 449 TAILQ_INSERT_TAIL(&b->ng_fec_ports, new, fec_list); 450 451 /* Add multicast addresses to this port. */ 452 ng_fec_ether_cmdmulti(ifp, new, 1); 453 454 return(0); 455 } 456 457 static int 458 ng_fec_delport(struct ng_fec_private *priv, char *iface) 459 { 460 struct ng_fec_bundle *b; 461 struct ifnet *ifp, *bifp; 462 struct ng_fec_portlist *p; 463 464 if (priv == NULL || iface == NULL) 465 return(EINVAL); 466 467 b = &priv->fec_bundle; 468 ifp = priv->ifp; 469 470 /* Only allow reconfiguration if not running. */ 471 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 472 printf("fec%d: can't remove iface; bundle is running\n", 473 priv->unit); 474 return (EINVAL); 475 } 476 477 /* Find the interface */ 478 bifp = ifunit(iface); 479 if (bifp == NULL) { 480 printf("fec%d: tried to remove iface %s, which " 481 "doesn't seem to exist\n", priv->unit, iface); 482 return(ENOENT); 483 } 484 485 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 486 if (p->fec_if == bifp) 487 break; 488 } 489 490 if (p == NULL) { 491 printf("fec%d: tried to remove iface %s which " 492 "is not in our bundle\n", priv->unit, iface); 493 return(EINVAL); 494 } 495 496 /* Stop interface */ 497 bifp->if_flags &= ~IFF_UP; 498 (*bifp->if_ioctl)(bifp, SIOCSIFFLAGS, NULL); 499 500 /* Restore MAC address. */ 501 if_setlladdr(bifp, (u_char *)&p->fec_mac, ETHER_ADDR_LEN); 502 503 /* Restore input vector */ 504 bifp->if_input = p->fec_if_input; 505 506 /* Remove our node context pointer. */ 507 IF_AFDATA_LOCK(bifp); 508 IFP2NG(bifp) = NULL; 509 IF_AFDATA_UNLOCK(bifp); 510 511 /* Delete port */ 512 TAILQ_REMOVE(&b->ng_fec_ports, p, fec_list); 513 kfree(p, M_NETGRAPH); 514 b->fec_ifcnt--; 515 516 if (b->fec_ifcnt == 0) 517 b->fec_if_output = NULL; 518 519 return(0); 520 } 521 522 static int 523 ng_fec_ether_cmdmulti(struct ifnet *trifp, struct ng_fec_portlist *p, int set) 524 { 525 struct ifnet *ifp = p->fec_if; 526 struct ng_fec_mc *mc; 527 struct ifmultiaddr *ifma, *rifma = NULL; 528 struct sockaddr_dl sdl; 529 int error; 530 531 bzero((char *)&sdl, sizeof(sdl)); 532 sdl.sdl_len = sizeof(sdl); 533 sdl.sdl_family = AF_LINK; 534 sdl.sdl_type = IFT_ETHER; 535 sdl.sdl_alen = ETHER_ADDR_LEN; 536 sdl.sdl_index = ifp->if_index; 537 538 if (set) { 539 TAILQ_FOREACH(ifma, &trifp->if_multiaddrs, ifma_link) { 540 if (ifma->ifma_addr->sa_family != AF_LINK) 541 continue; 542 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 543 LLADDR(&sdl), ETHER_ADDR_LEN); 544 545 error = if_addmulti(ifp, (struct sockaddr *)&sdl, &rifma); 546 if (error) 547 return (error); 548 mc = kmalloc(sizeof(struct ng_fec_mc), M_DEVBUF, M_WAITOK | M_NULLOK); 549 if (mc == NULL) 550 return (ENOMEM); 551 mc->mc_ifma = rifma; 552 SLIST_INSERT_HEAD(&p->fec_mc_head, mc, mc_entries); 553 } 554 } else { 555 while ((mc = SLIST_FIRST(&p->fec_mc_head)) != NULL) { 556 SLIST_REMOVE(&p->fec_mc_head, mc, ng_fec_mc, mc_entries); 557 if_delmulti_ifma(mc->mc_ifma); 558 kfree(mc, M_DEVBUF); 559 } 560 } 561 return (0); 562 } 563 564 static int 565 ng_fec_ether_setmulti(struct ifnet *ifp) 566 { 567 struct ng_fec_private *priv; 568 struct ng_fec_bundle *b; 569 struct ng_fec_portlist *p; 570 571 priv = ifp->if_softc; 572 b = &priv->fec_bundle; 573 574 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 575 /* First, remove any existing filter entries. */ 576 ng_fec_ether_cmdmulti(ifp, p, 0); 577 /* copy all addresses from the fec interface to the port */ 578 ng_fec_ether_cmdmulti(ifp, p, 1); 579 } 580 return (0); 581 } 582 583 /* 584 * Pass an ioctl command down to all the underyling interfaces in a 585 * bundle. Used for setting flags. 586 */ 587 588 static int 589 ng_fec_setport(struct ifnet *ifp, u_long command, caddr_t data) 590 { 591 struct ng_fec_private *priv; 592 struct ng_fec_bundle *b; 593 struct ifnet *oifp; 594 struct ng_fec_portlist *p; 595 596 priv = ifp->if_softc; 597 b = &priv->fec_bundle; 598 599 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 600 oifp = p->fec_if; 601 if (oifp != NULL) 602 (*oifp->if_ioctl)(oifp, command, data); 603 } 604 605 return(0); 606 } 607 608 static void 609 ng_fec_init(void *arg) 610 { 611 struct ng_fec_private *priv; 612 struct ng_fec_bundle *b; 613 struct ifnet *ifp, *bifp; 614 struct ng_fec_portlist *p; 615 616 priv = arg; 617 ifp = priv->ifp; 618 b = &priv->fec_bundle; 619 620 if (b->fec_ifcnt != 2 && b->fec_ifcnt != FEC_BUNDLESIZ) { 621 printf("fec%d: invalid bundle " 622 "size: %d\n", priv->unit, 623 b->fec_ifcnt); 624 return; 625 } 626 627 ng_fec_stop(ifp); 628 629 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 630 bifp = p->fec_if; 631 bifp->if_flags |= IFF_UP; 632 (*bifp->if_ioctl)(bifp, SIOCSIFFLAGS, NULL); 633 /* mark iface as up and let the monitor check it */ 634 p->fec_ifstat = -1; 635 } 636 637 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 638 ifp->if_drv_flags |= IFF_DRV_RUNNING; 639 640 priv->fec_ch = timeout(ng_fec_tick, priv, hz); 641 642 return; 643 } 644 645 static void 646 ng_fec_stop(struct ifnet *ifp) 647 { 648 struct ng_fec_private *priv; 649 struct ng_fec_bundle *b; 650 struct ifnet *bifp; 651 struct ng_fec_portlist *p; 652 653 priv = ifp->if_softc; 654 b = &priv->fec_bundle; 655 656 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 657 bifp = p->fec_if; 658 bifp->if_flags &= ~IFF_UP; 659 (*bifp->if_ioctl)(bifp, SIOCSIFFLAGS, NULL); 660 } 661 662 untimeout(ng_fec_tick, priv, priv->fec_ch); 663 664 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 665 666 return; 667 } 668 669 static void 670 ng_fec_tick(void *arg) 671 { 672 struct ng_fec_private *priv; 673 struct ng_fec_bundle *b; 674 struct ifmediareq ifmr; 675 struct ifnet *ifp; 676 struct ng_fec_portlist *p; 677 int error = 0; 678 679 priv = arg; 680 b = &priv->fec_bundle; 681 682 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 683 bzero((char *)&ifmr, sizeof(ifmr)); 684 ifp = p->fec_if; 685 error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr); 686 if (error) { 687 printf("fec%d: failed to check status " 688 "of link %s\n", priv->unit, ifp->if_xname); 689 continue; 690 } 691 692 if (ifmr.ifm_status & IFM_AVALID) { 693 if (ifmr.ifm_status & IFM_ACTIVE) { 694 if (p->fec_ifstat == -1 || 695 p->fec_ifstat == 0) { 696 p->fec_ifstat = 1; 697 printf("fec%d: port %s in bundle " 698 "is up\n", priv->unit, 699 ifp->if_xname); 700 } 701 } else { 702 if (p->fec_ifstat == -1 || 703 p->fec_ifstat == 1) { 704 p->fec_ifstat = 0; 705 printf("fec%d: port %s in bundle " 706 "is down\n", priv->unit, 707 ifp->if_xname); 708 } 709 } 710 } 711 } 712 713 ifp = priv->ifp; 714 if (ifp->if_drv_flags & IFF_DRV_RUNNING) 715 priv->fec_ch = timeout(ng_fec_tick, priv, hz); 716 717 return; 718 } 719 720 static int 721 ng_fec_ifmedia_upd(struct ifnet *ifp) 722 { 723 return(0); 724 } 725 726 static void ng_fec_ifmedia_sts(struct ifnet *ifp, 727 struct ifmediareq *ifmr) 728 { 729 struct ng_fec_private *priv; 730 struct ng_fec_bundle *b; 731 struct ng_fec_portlist *p; 732 733 priv = ifp->if_softc; 734 b = &priv->fec_bundle; 735 736 ifmr->ifm_status = IFM_AVALID; 737 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 738 if (p->fec_ifstat == 1) { 739 ifmr->ifm_status |= IFM_ACTIVE; 740 break; 741 } 742 } 743 744 return; 745 } 746 747 /* 748 * Process an ioctl for the virtual interface 749 */ 750 static int 751 ng_fec_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 752 { 753 struct ifreq *const ifr = (struct ifreq *) data; 754 int s, error = 0; 755 struct ng_fec_private *priv; 756 struct ng_fec_bundle *b; 757 758 priv = ifp->if_softc; 759 b = &priv->fec_bundle; 760 761 #ifdef DEBUG 762 ng_fec_print_ioctl(ifp, command, data); 763 #endif 764 s = splimp(); 765 switch (command) { 766 767 /* These two are mostly handled at a higher layer */ 768 case SIOCSIFADDR: 769 case SIOCGIFADDR: 770 error = ether_ioctl(ifp, command, data); 771 break; 772 773 case SIOCSIFMTU: 774 if (ifr->ifr_mtu >= NG_FEC_MTU_MIN && 775 ifr->ifr_mtu <= NG_FEC_MTU_MAX) { 776 struct ng_fec_portlist *p; 777 struct ifnet *bifp; 778 779 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 780 bifp = p->fec_if; 781 error = (*bifp->if_ioctl)(bifp, SIOCSIFMTU, 782 data); 783 if (error != 0) 784 break; 785 } 786 if (error == 0) 787 ifp->if_mtu = ifr->ifr_mtu; 788 } else 789 error = EINVAL; 790 break; 791 792 /* Set flags */ 793 case SIOCSIFFLAGS: 794 /* 795 * If the interface is marked up and stopped, then start it. 796 * If it is marked down and running, then stop it. 797 */ 798 if (ifr->ifr_flags & IFF_UP) { 799 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 800 /* Sanity. */ 801 if (b->fec_ifcnt != 2 && 802 b->fec_ifcnt != FEC_BUNDLESIZ) { 803 printf("fec%d: invalid bundle " 804 "size: %d\n", priv->unit, 805 b->fec_ifcnt); 806 error = EINVAL; 807 break; 808 } 809 ng_fec_init(priv); 810 } 811 /* 812 * Bubble down changes in promisc mode to 813 * underlying interfaces. 814 */ 815 if ((ifp->if_flags & IFF_PROMISC) != 816 (priv->if_flags & IFF_PROMISC)) { 817 ng_fec_setport(ifp, command, data); 818 priv->if_flags = ifp->if_flags; 819 } 820 } else { 821 if (ifp->if_drv_flags & IFF_DRV_RUNNING) 822 ng_fec_stop(ifp); 823 } 824 break; 825 826 case SIOCADDMULTI: 827 case SIOCDELMULTI: 828 ng_fec_ether_setmulti(ifp); 829 error = 0; 830 break; 831 case SIOCGIFMEDIA: 832 case SIOCSIFMEDIA: 833 error = ifmedia_ioctl(ifp, ifr, &priv->ifmedia, command); 834 break; 835 /* Stuff that's not supported */ 836 case SIOCSIFPHYS: 837 error = EOPNOTSUPP; 838 break; 839 840 default: 841 error = EINVAL; 842 break; 843 } 844 (void) splx(s); 845 return (error); 846 } 847 848 /* 849 * This routine spies on mbufs received by underlying network device 850 * drivers. When we add an interface to our bundle, we override its 851 * if_input routine with a pointer to ng_fec_input(). This means we 852 * get to look at all the device's packets before sending them to the 853 * real ether_input() for processing by the stack. Once we verify the 854 * packet comes from an interface that's been aggregated into 855 * our bundle, we fix up the rcvif pointer and increment our 856 * packet counters so that it looks like the frames are actually 857 * coming from us. 858 */ 859 static void 860 ng_fec_input(struct ifnet *ifp, struct mbuf *m0) 861 { 862 struct ng_node *node; 863 struct ng_fec_private *priv; 864 struct ng_fec_bundle *b; 865 struct ifnet *bifp; 866 struct ng_fec_portlist *p; 867 868 /* Sanity check */ 869 if (ifp == NULL || m0 == NULL) 870 return; 871 872 node = IFP2NG(ifp); 873 874 /* Sanity check part II */ 875 if (node == NULL) 876 return; 877 878 priv = NG_NODE_PRIVATE(node); 879 b = &priv->fec_bundle; 880 bifp = priv->ifp; 881 882 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 883 if (p->fec_if == m0->m_pkthdr.rcvif) 884 break; 885 } 886 887 /* Wasn't meant for us; leave this frame alone. */ 888 if (p == NULL) 889 return; 890 891 /* 892 * Check for a BPF tap on the underlying interface. This 893 * is mainly a debugging aid: it allows tcpdump-ing of an 894 * individual interface in a bundle to work, which it 895 * otherwise would not. BPF tapping of our own aggregate 896 * interface will occur once we call ether_input(). 897 */ 898 BPF_MTAP(m0->m_pkthdr.rcvif, m0); 899 900 /* Convince the system that this is our frame. */ 901 m0->m_pkthdr.rcvif = bifp; 902 903 /* 904 * Count bytes on an individual interface in a bundle. 905 * The bytes will also be added to the aggregate interface 906 * once we call ether_input(). 907 */ 908 ifp->if_ibytes += m0->m_pkthdr.len; 909 910 bifp->if_ipackets++; 911 (*bifp->if_input)(bifp, m0); 912 913 return; 914 } 915 916 /* 917 * Take a quick peek at the packet and see if it's ok for us to use 918 * the inet or inet6 hash methods on it, if they're enabled. We do 919 * this by setting flags in the mbuf header. Once we've made up our 920 * mind what to do, we pass the frame to output vector for further 921 * processing. 922 */ 923 924 static int 925 ng_fec_output(struct ifnet *ifp, struct mbuf *m, 926 struct sockaddr *dst, struct rtentry *rt0) 927 { 928 const priv_p priv = (priv_p) ifp->if_softc; 929 struct ng_fec_bundle *b; 930 int error; 931 932 /* Check interface flags */ 933 if (!((ifp->if_flags & IFF_UP) && 934 (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 935 m_freem(m); 936 return (ENETDOWN); 937 } 938 939 b = &priv->fec_bundle; 940 941 switch (b->fec_btype) { 942 case FEC_BTYPE_MAC: 943 m->m_flags |= M_FEC_MAC; 944 break; 945 #ifdef INET 946 case FEC_BTYPE_INET: 947 /* 948 * We can't use the INET address port selection 949 * scheme if this isn't an INET packet. 950 */ 951 if (dst->sa_family == AF_INET) 952 m->m_flags |= M_FEC_INET; 953 #ifdef INET6 954 else if (dst->sa_family == AF_INET6) 955 m->m_flags |= M_FEC_INET6; 956 #endif 957 else { 958 #ifdef DEBUG 959 if_printf(ifp, "can't do inet aggregation of non " 960 "inet packet\n"); 961 #endif 962 m->m_flags |= M_FEC_MAC; 963 } 964 break; 965 #endif 966 default: 967 if_printf(ifp, "bogus hash type: %d\n", 968 b->fec_btype); 969 m_freem(m); 970 return(EINVAL); 971 break; 972 } 973 974 /* 975 * Pass the frame to the output vector for all the protocol 976 * handling. This will put the ethernet header on the packet 977 * for us. 978 */ 979 priv->if_error = 0; 980 error = (*b->fec_if_output)(ifp, m, dst, rt0); 981 if (priv->if_error && !error) 982 error = priv->if_error; 983 984 return(error); 985 } 986 987 /* 988 * Apply a hash to the source and destination addresses in the packet 989 * in order to select an interface. Also check link status and handle 990 * dead links accordingly. 991 */ 992 993 static int 994 ng_fec_choose_port(struct ng_fec_bundle *b, 995 struct mbuf *m, struct ifnet **ifp) 996 { 997 struct ether_header *eh; 998 struct mbuf *m0; 999 #ifdef INET 1000 struct ip *ip; 1001 #ifdef INET6 1002 struct ip6_hdr *ip6; 1003 #endif 1004 #endif 1005 1006 struct ng_fec_portlist *p; 1007 int port = 0, mask; 1008 1009 /* 1010 * If there are only two ports, mask off all but the 1011 * last bit for XORing. If there are 4, mask off all 1012 * but the last 2 bits. 1013 */ 1014 mask = b->fec_ifcnt == 2 ? 0x1 : 0x3; 1015 eh = mtod(m, struct ether_header *); 1016 #ifdef INET 1017 ip = (struct ip *)(mtod(m, char *) + 1018 sizeof(struct ether_header)); 1019 #ifdef INET6 1020 ip6 = (struct ip6_hdr *)(mtod(m, char *) + 1021 sizeof(struct ether_header)); 1022 #endif 1023 #endif 1024 1025 /* 1026 * The fg_fec_output() routine is supposed to leave a 1027 * flag for us in the mbuf that tells us what hash to 1028 * use, but sometimes a new mbuf is prepended to the 1029 * chain, so we have to search every mbuf in the chain 1030 * to find the flags. 1031 */ 1032 m0 = m; 1033 while (m0) { 1034 if (m0->m_flags & (M_FEC_MAC|M_FEC_INET|M_FEC_INET6)) 1035 break; 1036 m0 = m0->m_next; 1037 } 1038 if (m0 == NULL) 1039 return(EINVAL); 1040 1041 switch (m0->m_flags & (M_FEC_MAC|M_FEC_INET|M_FEC_INET6)) { 1042 case M_FEC_MAC: 1043 port = (eh->ether_dhost[5] ^ 1044 eh->ether_shost[5]) & mask; 1045 break; 1046 #ifdef INET 1047 case M_FEC_INET: 1048 port = (ntohl(ip->ip_dst.s_addr) ^ 1049 ntohl(ip->ip_src.s_addr)) & mask; 1050 break; 1051 #ifdef INET6 1052 case M_FEC_INET6: 1053 port = (ip6->ip6_dst.s6_addr[15] ^ 1054 ip6->ip6_dst.s6_addr[15]) & mask; 1055 break; 1056 #endif 1057 #endif 1058 default: 1059 return(EINVAL); 1060 break; 1061 } 1062 1063 TAILQ_FOREACH(p, &b->ng_fec_ports, fec_list) { 1064 if (port == p->fec_idx) 1065 break; 1066 } 1067 1068 /* 1069 * Now that we've chosen a port, make sure it's 1070 * alive. If it's not alive, cycle through the bundle 1071 * looking for a port that is alive. If we don't find 1072 * any, return an error. 1073 */ 1074 if (p->fec_ifstat != 1) { 1075 struct ng_fec_portlist *n = NULL; 1076 1077 n = TAILQ_NEXT(p, fec_list); 1078 if (n == NULL) 1079 n = TAILQ_FIRST(&b->ng_fec_ports); 1080 while (n != p) { 1081 if (n->fec_ifstat == 1) 1082 break; 1083 n = TAILQ_NEXT(n, fec_list); 1084 if (n == NULL) 1085 n = TAILQ_FIRST(&b->ng_fec_ports); 1086 } 1087 if (n == p) 1088 return(EAGAIN); 1089 p = n; 1090 } 1091 1092 *ifp = p->fec_if; 1093 1094 return(0); 1095 } 1096 1097 /* 1098 * Now that the packet has been run through ether_output(), yank it 1099 * off our own send queue and stick it on the queue for the appropriate 1100 * underlying physical interface. Note that if the interface's send 1101 * queue is full, we save an error status in our private netgraph 1102 * space which will eventually be handed up to ng_fec_output(), which 1103 * will return it to the rest of the IP stack. We need to do this 1104 * in order to duplicate the effect of ether_output() returning ENOBUFS 1105 * when it detects that an interface's send queue is full. There's no 1106 * other way to signal the error status from here since the if_start() 1107 * routine is spec'ed to return void. 1108 * 1109 * Once the frame is queued, we call ether_output_frame() to initiate 1110 * transmission. 1111 */ 1112 static void 1113 ng_fec_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 1114 { 1115 struct ng_fec_private *priv; 1116 struct ng_fec_bundle *b; 1117 struct ifnet *oifp = NULL; 1118 struct mbuf *m0; 1119 int error; 1120 1121 priv = ifp->if_softc; 1122 b = &priv->fec_bundle; 1123 1124 m0 = ifq_dequeue(&ifp->if_snd); 1125 if (m0 == NULL) 1126 return; 1127 1128 BPF_MTAP(ifp, m0); 1129 1130 /* Queue up packet on the proper port. */ 1131 error = ng_fec_choose_port(b, m0, &oifp); 1132 if (error) { 1133 ifp->if_ierrors++; 1134 m_freem(m0); 1135 priv->if_error = ENOBUFS; 1136 return; 1137 } 1138 ifp->if_opackets++; 1139 1140 ifnet_deserialize_tx(ifp, ifsq); 1141 error = ifq_dispatch(oifp, m0, NULL); 1142 ifnet_serialize_tx(ifp, ifsq); 1143 1144 priv->if_error = error; 1145 } 1146 1147 #ifdef DEBUG 1148 /* 1149 * Display an ioctl to the virtual interface 1150 */ 1151 1152 static void 1153 ng_fec_print_ioctl(struct ifnet *ifp, int command, caddr_t data) 1154 { 1155 char *str; 1156 1157 switch (command & IOC_DIRMASK) { 1158 case IOC_VOID: 1159 str = "IO"; 1160 break; 1161 case IOC_OUT: 1162 str = "IOR"; 1163 break; 1164 case IOC_IN: 1165 str = "IOW"; 1166 break; 1167 case IOC_INOUT: 1168 str = "IORW"; 1169 break; 1170 default: 1171 str = "IO??"; 1172 } 1173 log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n", 1174 ifp->if_xname, 1175 str, 1176 IOCGROUP(command), 1177 command & 0xff, 1178 IOCPARM_LEN(command)); 1179 } 1180 #endif /* DEBUG */ 1181 1182 /************************************************************************ 1183 NETGRAPH NODE STUFF 1184 ************************************************************************/ 1185 1186 /* 1187 * Constructor for a node 1188 */ 1189 static int 1190 ng_fec_constructor(node_p node) 1191 { 1192 char ifname[NG_FEC_FEC_NAME_MAX + 1]; 1193 struct ifnet *ifp; 1194 priv_p priv; 1195 const uint8_t eaddr[ETHER_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 1196 struct ng_fec_bundle *b; 1197 int error = 0; 1198 1199 /* Allocate node and interface private structures */ 1200 priv = kmalloc(sizeof(*priv), M_NETGRAPH, 1201 M_WAITOK | M_NULLOK | M_ZERO); 1202 if (priv == NULL) 1203 return (ENOMEM); 1204 1205 ifp = priv->ifp = if_alloc(IFT_ETHER); 1206 if (ifp == NULL) { 1207 kfree(priv, M_NETGRAPH); 1208 return (ENOSPC); 1209 } 1210 b = &priv->fec_bundle; 1211 1212 /* Link them together */ 1213 ifp->if_softc = priv; 1214 1215 /* Get an interface unit number */ 1216 if ((error = ng_fec_get_unit(&priv->unit)) != 0) { 1217 if_free(ifp); 1218 kfree(priv, M_NETGRAPH); 1219 return (error); 1220 } 1221 1222 /* Link together node and private info */ 1223 NG_NODE_SET_PRIVATE(node, priv); 1224 priv->node = node; 1225 1226 /* Initialize interface structure */ 1227 if_initname(ifp, NG_FEC_FEC_NAME, priv->unit); 1228 ifp->if_start = ng_fec_start; 1229 ifp->if_ioctl = ng_fec_ioctl; 1230 ifp->if_init = ng_fec_init; 1231 ifp->if_watchdog = NULL; 1232 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); 1233 ifp->if_mtu = NG_FEC_MTU_DEFAULT; 1234 ifp->if_flags = (IFF_SIMPLEX|IFF_BROADCAST|IFF_MULTICAST); 1235 ifp->if_addrlen = 0; /* XXX */ 1236 ifp->if_hdrlen = 0; /* XXX */ 1237 ifp->if_baudrate = 100000000; /* XXX */ 1238 TAILQ_INIT(&ifp->if_addrhead); /* XXX useless - done in if_attach */ 1239 1240 /* Give this node the same name as the interface (if possible) */ 1241 bzero(ifname, sizeof(ifname)); 1242 strlcpy(ifname, ifp->if_xname, sizeof(ifname)); 1243 if (ng_name_node(node, ifname) != 0) 1244 log(LOG_WARNING, "%s: can't acquire netgraph name\n", ifname); 1245 1246 /* Attach the interface */ 1247 ether_ifattach(ifp, eaddr); 1248 callout_handle_init(&priv->fec_ch); 1249 1250 /* Override output method with our own */ 1251 ifp->if_output = ng_fec_output; 1252 1253 TAILQ_INIT(&b->ng_fec_ports); 1254 b->fec_ifcnt = 0; 1255 1256 ifmedia_init(&priv->ifmedia, 0, 1257 ng_fec_ifmedia_upd, ng_fec_ifmedia_sts); 1258 ifmedia_add(&priv->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL); 1259 ifmedia_set(&priv->ifmedia, IFM_ETHER|IFM_NONE); 1260 1261 /* Done */ 1262 return (0); 1263 } 1264 1265 /* 1266 * Receive a control message 1267 */ 1268 static int 1269 ng_fec_rcvmsg(node_p node, item_p item, hook_p lasthook) 1270 { 1271 const priv_p priv = NG_NODE_PRIVATE(node); 1272 struct ng_fec_bundle *b; 1273 struct ng_mesg *resp = NULL; 1274 struct ng_mesg *msg; 1275 char *ifname; 1276 int error = 0; 1277 1278 NGI_GET_MSG(item, msg); 1279 b = &priv->fec_bundle; 1280 1281 switch (msg->header.typecookie) { 1282 case NGM_FEC_COOKIE: 1283 switch (msg->header.cmd) { 1284 case NGM_FEC_ADD_IFACE: 1285 ifname = msg->data; 1286 error = ng_fec_addport(priv, ifname); 1287 break; 1288 case NGM_FEC_DEL_IFACE: 1289 ifname = msg->data; 1290 error = ng_fec_delport(priv, ifname); 1291 break; 1292 case NGM_FEC_SET_MODE_MAC: 1293 b->fec_btype = FEC_BTYPE_MAC; 1294 break; 1295 #ifdef INET 1296 case NGM_FEC_SET_MODE_INET: 1297 b->fec_btype = FEC_BTYPE_INET; 1298 break; 1299 #ifdef INET6 1300 case NGM_FEC_SET_MODE_INET6: 1301 b->fec_btype = FEC_BTYPE_INET6; 1302 break; 1303 #endif 1304 #endif 1305 default: 1306 error = EINVAL; 1307 break; 1308 } 1309 break; 1310 default: 1311 error = EINVAL; 1312 break; 1313 } 1314 NG_RESPOND_MSG(error, node, item, resp); 1315 NG_FREE_MSG(msg); 1316 return (error); 1317 } 1318 1319 /* 1320 * Shutdown and remove the node and its associated interface. 1321 */ 1322 static int 1323 ng_fec_shutdown(node_p node) 1324 { 1325 const priv_p priv = NG_NODE_PRIVATE(node); 1326 struct ng_fec_bundle *b; 1327 struct ng_fec_portlist *p; 1328 1329 b = &priv->fec_bundle; 1330 ng_fec_stop(priv->ifp); 1331 1332 while (!TAILQ_EMPTY(&b->ng_fec_ports)) { 1333 p = TAILQ_FIRST(&b->ng_fec_ports); 1334 ng_fec_ether_cmdmulti(priv->ifp, p, 0); 1335 ng_fec_delport(priv, p->fec_if->if_xname); 1336 } 1337 1338 ether_ifdetach(priv->ifp); 1339 if_free_type(priv->ifp, IFT_ETHER); 1340 ifmedia_removeall(&priv->ifmedia); 1341 ng_fec_free_unit(priv->unit); 1342 kfree(priv, M_NETGRAPH); 1343 NG_NODE_SET_PRIVATE(node, NULL); 1344 NG_NODE_UNREF(node); 1345 return (0); 1346 } 1347 1348 /* 1349 * Handle loading and unloading for this node type. 1350 */ 1351 static int 1352 ng_fec_mod_event(module_t mod, int event, void *data) 1353 { 1354 int error = 0; 1355 1356 switch (event) { 1357 case MOD_LOAD: 1358 mtx_init(&ng_fec_mtx, "ng_fec", NULL, MTX_DEF); 1359 break; 1360 case MOD_UNLOAD: 1361 mtx_destroy(&ng_fec_mtx); 1362 break; 1363 default: 1364 error = EOPNOTSUPP; 1365 break; 1366 } 1367 return (error); 1368 } 1369