1 2 /* 3 * ng_iface.c 4 * 5 * Copyright (c) 1996-1999 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 * Author: Archie Cobbs <archie@whistle.com> 38 * 39 * $FreeBSD$ 40 * $Whistle: ng_iface.c,v 1.31 1999/02/02 22:27:28 archie Exp $ 41 */ 42 43 /* 44 * This node is also a system networking interface. It has 45 * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets 46 * are simply relayed between the interface and the hooks. 47 * 48 * Interfaces are named ng0, ng1, .... FreeBSD does not support 49 * the removal of interfaces, so iface nodes are persistent. 50 * 51 * This node also includes Berkeley packet filter support. 52 */ 53 54 #include "opt_inet.h" 55 #include "opt_atalk.h" 56 #include "opt_ipx.h" 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/errno.h> 61 #include <sys/kernel.h> 62 #include <sys/malloc.h> 63 #include <sys/mbuf.h> 64 #include <sys/conf.h> 65 #include <sys/errno.h> 66 #include <sys/sockio.h> 67 #include <sys/socket.h> 68 #include <sys/syslog.h> 69 70 #include <net/route.h> 71 #include <net/if.h> 72 #include <net/if_dl.h> 73 #include <net/if_types.h> 74 #include <net/netisr.h> 75 76 #include <netgraph/ng_message.h> 77 #include <netgraph/netgraph.h> 78 #include <netgraph/ng_iface.h> 79 #include <netgraph/ng_cisco.h> 80 81 #ifdef INET 82 #include <netinet/in.h> 83 #include <netinet/in_systm.h> 84 #include <netinet/in_var.h> 85 #include <netinet/ip.h> 86 #include <netinet/if_ether.h> 87 #include <netinet/in_var.h> 88 #endif 89 90 #ifdef NETATALK 91 #include <netatalk/at.h> 92 #include <netatalk/at_var.h> 93 #include <netatalk/at_extern.h> 94 #endif 95 96 #ifdef IPX 97 #include <netipx/ipx.h> 98 #include <netipx/ipx_if.h> 99 #endif 100 101 #ifdef NS 102 #include <netns/ns.h> 103 #include <netns/ns_if.h> 104 #endif 105 106 #include <net/bpf.h> 107 108 /* This struct describes one address family */ 109 struct iffam { 110 char *hookname; /* Name for hook */ 111 u_char af; /* Family number */ 112 u_char netisr; /* or NETISR_NONE */ 113 union { 114 void *_dummy; /* avoid warning */ 115 struct ifqueue *inq; /* if netisr */ 116 void (*input)(struct mbuf *m); /* if direct input */ 117 } u; 118 }; 119 typedef const struct iffam *iffam_p; 120 121 #define NETISR_NONE 0xff 122 123 /* List of address families supported by our interface. Each address 124 family has a way to input packets to it, either by calling a function 125 directly (such as ip_input()) or by adding the packet to a queue and 126 setting a NETISR bit. */ 127 const static struct iffam gFamilies[] = { 128 #ifdef INET 129 { 130 NG_IFACE_HOOK_INET, 131 AF_INET, 132 NETISR_NONE, 133 { ip_input } 134 }, 135 #endif 136 #ifdef NETATALK 137 { 138 NG_IFACE_HOOK_ATALK, 139 AF_APPLETALK, 140 NETISR_ATALK, 141 { &atintrq2 } 142 }, 143 #endif 144 #ifdef IPX 145 { 146 NG_IFACE_HOOK_IPX, 147 AF_IPX, 148 NETISR_IPX, 149 { &ipxintrq } 150 }, 151 #endif 152 #ifdef NS 153 { 154 NG_IFACE_HOOK_NS, 155 AF_NS, 156 NETISR_NS, 157 { &nsintrq } 158 }, 159 #endif 160 }; 161 #define NUM_FAMILIES (sizeof(gFamilies) / sizeof(*gFamilies)) 162 163 /* Node private data */ 164 struct private { 165 struct ifnet *ifp; /* This interface */ 166 node_p node; /* Our netgraph node */ 167 hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */ 168 struct private *next; /* When hung on the free list */ 169 }; 170 typedef struct private *priv_p; 171 172 /* Interface methods */ 173 static void ng_iface_start(struct ifnet *ifp); 174 static int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 175 static int ng_iface_output(struct ifnet *ifp, struct mbuf *m0, 176 struct sockaddr *dst, struct rtentry *rt0); 177 static void ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af); 178 #ifdef DEBUG 179 static void ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 180 #endif 181 182 /* Netgraph methods */ 183 static int ng_iface_constructor(node_p *nodep); 184 static int ng_iface_rcvmsg(node_p node, struct ng_mesg *msg, 185 const char *retaddr, struct ng_mesg **resp); 186 static int ng_iface_rmnode(node_p node); 187 static int ng_iface_newhook(node_p node, hook_p hook, const char *name); 188 static int ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta); 189 static int ng_iface_disconnect(hook_p hook); 190 191 /* Helper stuff */ 192 static iffam_p get_iffam_from_af(int af); 193 static iffam_p get_iffam_from_hook(priv_p priv, hook_p hook); 194 static iffam_p get_iffam_from_name(const char *name); 195 static hook_p *get_hook_from_iffam(priv_p priv, iffam_p iffam); 196 197 /* Node type descriptor */ 198 static struct ng_type typestruct = { 199 NG_VERSION, 200 NG_IFACE_NODE_TYPE, 201 NULL, 202 ng_iface_constructor, 203 ng_iface_rcvmsg, 204 ng_iface_rmnode, 205 ng_iface_newhook, 206 NULL, 207 NULL, 208 ng_iface_rcvdata, 209 ng_iface_rcvdata, 210 ng_iface_disconnect 211 }; 212 NETGRAPH_INIT(iface, &typestruct); 213 214 static char ng_iface_ifname[] = NG_IFACE_IFACE_NAME; 215 static int ng_iface_next_unit; 216 217 /************************************************************************ 218 HELPER STUFF 219 ************************************************************************/ 220 221 /* 222 * Get the family descriptor from the family ID 223 */ 224 static __inline__ iffam_p 225 get_iffam_from_af(int af) 226 { 227 iffam_p iffam; 228 int k; 229 230 for (k = 0; k < NUM_FAMILIES; k++) { 231 iffam = &gFamilies[k]; 232 if (iffam->af == af) 233 return (iffam); 234 } 235 return (NULL); 236 } 237 238 /* 239 * Get the family descriptor from the hook 240 */ 241 static __inline__ iffam_p 242 get_iffam_from_hook(priv_p priv, hook_p hook) 243 { 244 int k; 245 246 for (k = 0; k < NUM_FAMILIES; k++) 247 if (priv->hooks[k] == hook) 248 return (&gFamilies[k]); 249 return (NULL); 250 } 251 252 /* 253 * Get the hook from the iffam descriptor 254 */ 255 256 static __inline__ hook_p * 257 get_hook_from_iffam(priv_p priv, iffam_p iffam) 258 { 259 return (&priv->hooks[iffam - gFamilies]); 260 } 261 262 /* 263 * Get the iffam descriptor from the name 264 */ 265 static __inline__ iffam_p 266 get_iffam_from_name(const char *name) 267 { 268 iffam_p iffam; 269 int k; 270 271 for (k = 0; k < NUM_FAMILIES; k++) { 272 iffam = &gFamilies[k]; 273 if (!strcmp(iffam->hookname, name)) 274 return (iffam); 275 } 276 return (NULL); 277 } 278 279 /************************************************************************ 280 INTERFACE STUFF 281 ************************************************************************/ 282 283 /* 284 * Process an ioctl for the virtual interface 285 */ 286 static int 287 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 288 { 289 struct ifreq *const ifr = (struct ifreq *) data; 290 int s, error = 0; 291 292 #ifdef DEBUG 293 ng_iface_print_ioctl(ifp, command, data); 294 #endif 295 s = splimp(); 296 switch (command) { 297 298 /* These two are mostly handled at a higher layer */ 299 case SIOCSIFADDR: 300 ifp->if_flags |= (IFF_UP | IFF_RUNNING); 301 ifp->if_flags &= ~(IFF_OACTIVE); 302 break; 303 case SIOCGIFADDR: 304 break; 305 306 /* Set flags */ 307 case SIOCSIFFLAGS: 308 /* 309 * If the interface is marked up and stopped, then start it. 310 * If it is marked down and running, then stop it. 311 */ 312 if (ifr->ifr_flags & IFF_UP) { 313 if (!(ifp->if_flags & IFF_RUNNING)) { 314 ifp->if_flags &= ~(IFF_OACTIVE); 315 ifp->if_flags |= IFF_RUNNING; 316 } 317 } else { 318 if (ifp->if_flags & IFF_RUNNING) 319 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 320 } 321 break; 322 323 /* Set the interface MTU */ 324 case SIOCSIFMTU: 325 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX 326 || ifr->ifr_mtu < NG_IFACE_MTU_MIN) 327 error = EINVAL; 328 else 329 ifp->if_mtu = ifr->ifr_mtu; 330 break; 331 332 /* Stuff that's not supported */ 333 case SIOCADDMULTI: 334 case SIOCDELMULTI: 335 case SIOCSIFPHYS: 336 error = EOPNOTSUPP; 337 break; 338 339 default: 340 error = EINVAL; 341 break; 342 } 343 (void) splx(s); 344 return (error); 345 } 346 347 /* 348 * This routine is called to deliver a packet out the interface. 349 * We simply look at the address family and relay the packet to 350 * the corresponding hook, if it exists and is connected. 351 */ 352 353 static int 354 ng_iface_output(struct ifnet *ifp, struct mbuf *m, 355 struct sockaddr *dst, struct rtentry *rt0) 356 { 357 const priv_p priv = (priv_p) ifp->if_softc; 358 const iffam_p iffam = get_iffam_from_af(dst->sa_family); 359 meta_p meta = NULL; 360 int len, error = 0; 361 362 /* Check interface flags */ 363 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 364 m_freem(m); 365 return (ENETDOWN); 366 } 367 368 /* Berkeley packet filter */ 369 ng_iface_bpftap(ifp, m, dst->sa_family); 370 371 /* Check address family to determine hook (if known) */ 372 if (iffam == NULL) { 373 m_freem(m); 374 log(LOG_WARNING, "%s%d: can't handle af%d\n", 375 ifp->if_name, ifp->if_unit, dst->sa_family); 376 return (EAFNOSUPPORT); 377 } 378 379 /* Copy length before the mbuf gets invalidated */ 380 len = m->m_pkthdr.len; 381 382 /* Send packet; if hook is not connected, mbuf will get freed. */ 383 NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta); 384 385 /* Update stats */ 386 if (error == 0) { 387 ifp->if_obytes += len; 388 ifp->if_opackets++; 389 } 390 return (error); 391 } 392 393 /* 394 * This routine should never be called 395 */ 396 397 static void 398 ng_iface_start(struct ifnet *ifp) 399 { 400 printf("%s%d: %s called?", ifp->if_name, ifp->if_unit, __FUNCTION__); 401 } 402 403 /* 404 * Flash a packet by the BPF (requires prepending 4 byte AF header) 405 * Note the phoney mbuf; this is OK because BPF treats it read-only. 406 */ 407 static void 408 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af) 409 { 410 struct mbuf m2; 411 412 if (ifp->if_bpf) { 413 if (af == AF_UNSPEC) { 414 af = *(mtod(m, int *)); 415 m->m_len -= sizeof(int); 416 m->m_pkthdr.len -= sizeof(int); 417 m->m_data += sizeof(int); 418 } 419 if (!ifp->if_bpf) 420 return; 421 m2.m_next = m; 422 m2.m_len = 4; 423 m2.m_data = (char *) ⁡ 424 bpf_mtap(ifp, &m2); 425 } 426 } 427 428 #ifdef DEBUG 429 /* 430 * Display an ioctl to the virtual interface 431 */ 432 433 static void 434 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data) 435 { 436 char *str; 437 438 switch (command & IOC_DIRMASK) { 439 case IOC_VOID: 440 str = "IO"; 441 break; 442 case IOC_OUT: 443 str = "IOR"; 444 break; 445 case IOC_IN: 446 str = "IOW"; 447 break; 448 case IOC_INOUT: 449 str = "IORW"; 450 break; 451 default: 452 str = "IO??"; 453 } 454 log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n", 455 ifp->if_name, ifp->if_unit, 456 str, 457 IOCGROUP(command), 458 command & 0xff, 459 IOCPARM_LEN(command)); 460 } 461 #endif /* DEBUG */ 462 463 /************************************************************************ 464 NETGRAPH NODE STUFF 465 ************************************************************************/ 466 467 /* 468 * Constructor for a node 469 */ 470 static int 471 ng_iface_constructor(node_p *nodep) 472 { 473 char ifname[NG_IFACE_IFACE_NAME_MAX + 1]; 474 struct ifnet *ifp; 475 node_p node; 476 priv_p priv; 477 int error = 0; 478 479 /* Allocate node and interface private structures */ 480 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK); 481 if (priv == NULL) 482 return (ENOMEM); 483 bzero(priv, sizeof(*priv)); 484 MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH, M_WAITOK); 485 if (ifp == NULL) { 486 FREE(priv, M_NETGRAPH); 487 return (ENOMEM); 488 } 489 bzero(ifp, sizeof(*ifp)); 490 491 /* Link them together */ 492 ifp->if_softc = priv; 493 priv->ifp = ifp; 494 495 /* Call generic node constructor */ 496 if ((error = ng_make_node_common(&typestruct, nodep))) { 497 FREE(priv, M_NETGRAPH); 498 FREE(ifp, M_NETGRAPH); 499 return (error); 500 } 501 node = *nodep; 502 503 /* Link together node and private info */ 504 node->private = priv; 505 priv->node = node; 506 507 /* Initialize interface structure */ 508 ifp->if_name = ng_iface_ifname; 509 ifp->if_unit = ng_iface_next_unit++; 510 ifp->if_output = ng_iface_output; 511 ifp->if_start = ng_iface_start; 512 ifp->if_ioctl = ng_iface_ioctl; 513 ifp->if_watchdog = NULL; 514 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 515 ifp->if_mtu = NG_IFACE_MTU_DEFAULT; 516 ifp->if_flags = (IFF_SIMPLEX | IFF_POINTOPOINT | IFF_NOARP); 517 ifp->if_type = IFT_PROPVIRTUAL; /* XXX */ 518 ifp->if_addrlen = 0; /* XXX */ 519 ifp->if_hdrlen = 0; /* XXX */ 520 ifp->if_baudrate = 64000; /* XXX */ 521 TAILQ_INIT(&ifp->if_addrhead); 522 523 /* Give this node the same name as the interface (if possible) */ 524 bzero(ifname, sizeof(ifname)); 525 sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); 526 (void) ng_name_node(node, ifname); 527 528 /* Attach the interface */ 529 if_attach(ifp); 530 bpfattach(ifp, DLT_NULL, sizeof(u_int)); 531 532 /* Done */ 533 return (0); 534 } 535 536 /* 537 * Give our ok for a hook to be added 538 */ 539 static int 540 ng_iface_newhook(node_p node, hook_p hook, const char *name) 541 { 542 const iffam_p iffam = get_iffam_from_name(name); 543 hook_p *hookptr; 544 545 if (iffam == NULL) 546 return (EPFNOSUPPORT); 547 hookptr = get_hook_from_iffam((priv_p) node->private, iffam); 548 if (*hookptr != NULL) 549 return (EISCONN); 550 *hookptr = hook; 551 return (0); 552 } 553 554 /* 555 * Receive a control message 556 */ 557 static int 558 ng_iface_rcvmsg(node_p node, struct ng_mesg *msg, 559 const char *retaddr, struct ng_mesg **rptr) 560 { 561 const priv_p priv = node->private; 562 struct ifnet *const ifp = priv->ifp; 563 struct ng_mesg *resp = NULL; 564 int error = 0; 565 566 switch (msg->header.typecookie) { 567 case NGM_IFACE_COOKIE: 568 switch (msg->header.cmd) { 569 case NGM_IFACE_GET_IFNAME: 570 { 571 struct ng_iface_ifname *arg; 572 573 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 574 if (resp == NULL) { 575 error = ENOMEM; 576 break; 577 } 578 arg = (struct ng_iface_ifname *) resp->data; 579 sprintf(arg->ngif_name, 580 "%s%d", ifp->if_name, ifp->if_unit); 581 break; 582 } 583 584 case NGM_IFACE_GET_IFADDRS: 585 { 586 struct ifaddr *ifa; 587 caddr_t ptr; 588 int buflen; 589 590 #define SA_SIZE(s) ((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len) 591 592 /* Determine size of response and allocate it */ 593 buflen = 0; 594 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 595 buflen += SA_SIZE(ifa->ifa_addr); 596 NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT); 597 if (resp == NULL) { 598 error = ENOMEM; 599 break; 600 } 601 602 /* Add addresses */ 603 ptr = resp->data; 604 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 605 const int len = SA_SIZE(ifa->ifa_addr); 606 607 if (buflen < len) { 608 log(LOG_ERR, "%s%d: len changed?\n", 609 ifp->if_name, ifp->if_unit); 610 break; 611 } 612 bcopy(ifa->ifa_addr, ptr, len); 613 ptr += len; 614 buflen -= len; 615 } 616 break; 617 #undef SA_SIZE 618 } 619 620 default: 621 error = EINVAL; 622 break; 623 } 624 break; 625 case NGM_CISCO_COOKIE: 626 switch (msg->header.cmd) { 627 case NGM_CISCO_GET_IPADDR: /* we understand this too */ 628 { 629 struct ifaddr *ifa; 630 631 /* Return the first configured IP address */ 632 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 633 struct in_addr *ips; 634 635 if (ifa->ifa_addr->sa_family != AF_INET) 636 continue; 637 NG_MKRESPONSE(resp, msg, 638 2 * sizeof(*ips), M_NOWAIT); 639 if (resp == NULL) { 640 error = ENOMEM; 641 break; 642 } 643 ips = (struct in_addr *) resp->data; 644 ips[0] = ((struct sockaddr_in *) 645 ifa->ifa_addr)->sin_addr; 646 ips[1] = ((struct sockaddr_in *) 647 ifa->ifa_netmask)->sin_addr; 648 break; 649 } 650 651 /* No IP addresses on this interface? */ 652 if (ifa == NULL) 653 error = EADDRNOTAVAIL; 654 break; 655 } 656 default: 657 error = EINVAL; 658 break; 659 } 660 break; 661 default: 662 error = EINVAL; 663 break; 664 } 665 if (rptr) 666 *rptr = resp; 667 else if (resp) 668 FREE(resp, M_NETGRAPH); 669 FREE(msg, M_NETGRAPH); 670 return (error); 671 } 672 673 /* 674 * Recive data from a hook. Pass the packet to the correct input routine. 675 */ 676 static int 677 ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 678 { 679 const priv_p priv = hook->node->private; 680 const iffam_p iffam = get_iffam_from_hook(priv, hook); 681 struct ifnet *const ifp = priv->ifp; 682 int s, error = 0; 683 684 /* Sanity checks */ 685 #ifdef DIAGNOSTIC 686 if (iffam == NULL) 687 panic(__FUNCTION__); 688 if ((m->m_flags & M_PKTHDR) == 0) 689 panic(__FUNCTION__); 690 #endif 691 if (m == NULL) 692 return (EINVAL); 693 if ((ifp->if_flags & IFF_UP) == 0) { 694 NG_FREE_DATA(m, meta); 695 return (ENETDOWN); 696 } 697 698 /* Update interface stats */ 699 ifp->if_ipackets++; 700 ifp->if_ibytes += m->m_pkthdr.len; 701 702 /* Note receiving interface */ 703 m->m_pkthdr.rcvif = ifp; 704 705 /* Berkeley packet filter */ 706 ng_iface_bpftap(ifp, m, iffam->af); 707 708 /* Ignore any meta-data */ 709 NG_FREE_META(meta); 710 711 /* Send packet, either by NETISR or use a direct input function */ 712 switch (iffam->netisr) { 713 case NETISR_NONE: 714 (*iffam->u.input)(m); 715 break; 716 default: 717 s = splimp(); 718 schednetisr(iffam->netisr); 719 if (IF_QFULL(iffam->u.inq)) { 720 IF_DROP(iffam->u.inq); 721 m_freem(m); 722 error = ENOBUFS; 723 } else 724 IF_ENQUEUE(iffam->u.inq, m); 725 splx(s); 726 break; 727 } 728 729 /* Done */ 730 return (error); 731 } 732 733 /* 734 * Because the BSD networking code doesn't support the removal of 735 * networking interfaces, iface nodes (once created) are persistent. 736 * So this method breaks all connections and marks the interface 737 * down, but does not remove the node. 738 */ 739 static int 740 ng_iface_rmnode(node_p node) 741 { 742 const priv_p priv = node->private; 743 struct ifnet *const ifp = priv->ifp; 744 745 ng_cutlinks(node); 746 node->flags &= ~NG_INVALID; 747 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_OACTIVE); 748 return (0); 749 } 750 751 /* 752 * Hook disconnection 753 */ 754 static int 755 ng_iface_disconnect(hook_p hook) 756 { 757 const priv_p priv = hook->node->private; 758 const iffam_p iffam = get_iffam_from_hook(priv, hook); 759 760 if (iffam == NULL) 761 panic(__FUNCTION__); 762 *get_hook_from_iffam(priv, iffam) = NULL; 763 return (0); 764 } 765 766