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