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@freebsd.org> 38 * 39 * $FreeBSD$ 40 * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian 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, etc. New nodes take the 49 * first available interface name. 50 * 51 * This node also includes Berkeley packet filter support. 52 */ 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/errno.h> 57 #include <sys/kernel.h> 58 #include <sys/malloc.h> 59 #include <sys/mbuf.h> 60 #include <sys/errno.h> 61 #include <sys/sockio.h> 62 #include <sys/socket.h> 63 #include <sys/syslog.h> 64 #include <sys/libkern.h> 65 66 #include <net/if.h> 67 #include <net/if_types.h> 68 #include <net/intrq.h> 69 #include <net/bpf.h> 70 71 #include <netinet/in.h> 72 73 #include <netgraph/ng_message.h> 74 #include <netgraph/netgraph.h> 75 #include <netgraph/ng_parse.h> 76 #include <netgraph/ng_iface.h> 77 #include <netgraph/ng_cisco.h> 78 79 /* This struct describes one address family */ 80 struct iffam { 81 sa_family_t family; /* Address family */ 82 const char *hookname; /* Name for hook */ 83 }; 84 typedef const struct iffam *iffam_p; 85 86 /* List of address families supported by our interface */ 87 const static struct iffam gFamilies[] = { 88 { AF_INET, NG_IFACE_HOOK_INET }, 89 { AF_INET6, NG_IFACE_HOOK_INET6 }, 90 { AF_APPLETALK, NG_IFACE_HOOK_ATALK }, 91 { AF_IPX, NG_IFACE_HOOK_IPX }, 92 { AF_ATM, NG_IFACE_HOOK_ATM }, 93 { AF_NATM, NG_IFACE_HOOK_NATM }, 94 { AF_NS, NG_IFACE_HOOK_NS }, 95 }; 96 #define NUM_FAMILIES (sizeof(gFamilies) / sizeof(*gFamilies)) 97 98 /* Node private data */ 99 struct ng_iface_private { 100 struct ifnet *ifp; /* Our interface */ 101 int unit; /* Interface unit number */ 102 node_p node; /* Our netgraph node */ 103 hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */ 104 }; 105 typedef struct ng_iface_private *priv_p; 106 107 /* Interface methods */ 108 static void ng_iface_start(struct ifnet *ifp); 109 static int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 110 static int ng_iface_output(struct ifnet *ifp, struct mbuf *m0, 111 struct sockaddr *dst, struct rtentry *rt0); 112 static void ng_iface_bpftap(struct ifnet *ifp, 113 struct mbuf *m, sa_family_t family); 114 #ifdef DEBUG 115 static void ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data); 116 #endif 117 118 /* Netgraph methods */ 119 static ng_constructor_t ng_iface_constructor; 120 static ng_rcvmsg_t ng_iface_rcvmsg; 121 static ng_shutdown_t ng_iface_shutdown; 122 static ng_newhook_t ng_iface_newhook; 123 static ng_rcvdata_t ng_iface_rcvdata; 124 static ng_disconnect_t ng_iface_disconnect; 125 126 /* Helper stuff */ 127 static iffam_p get_iffam_from_af(sa_family_t family); 128 static iffam_p get_iffam_from_hook(priv_p priv, hook_p hook); 129 static iffam_p get_iffam_from_name(const char *name); 130 static hook_p *get_hook_from_iffam(priv_p priv, iffam_p iffam); 131 132 /* Parse type for struct ng_iface_ifname */ 133 static const struct ng_parse_fixedstring_info ng_iface_ifname_info = { 134 NG_IFACE_IFACE_NAME_MAX + 1 135 }; 136 static const struct ng_parse_type ng_iface_ifname_type = { 137 &ng_parse_fixedstring_type, 138 &ng_iface_ifname_info 139 }; 140 141 /* Parse type for struct ng_cisco_ipaddr */ 142 static const struct ng_parse_struct_info 143 ng_cisco_ipaddr_type_info = NG_CISCO_IPADDR_TYPE_INFO; 144 static const struct ng_parse_type ng_cisco_ipaddr_type = { 145 &ng_parse_struct_type, 146 &ng_cisco_ipaddr_type_info 147 }; 148 149 /* List of commands and how to convert arguments to/from ASCII */ 150 static const struct ng_cmdlist ng_iface_cmds[] = { 151 { 152 NGM_IFACE_COOKIE, 153 NGM_IFACE_GET_IFNAME, 154 "getifname", 155 NULL, 156 &ng_iface_ifname_type 157 }, 158 { 159 NGM_IFACE_COOKIE, 160 NGM_IFACE_POINT2POINT, 161 "point2point", 162 NULL, 163 NULL 164 }, 165 { 166 NGM_IFACE_COOKIE, 167 NGM_IFACE_BROADCAST, 168 "broadcast", 169 NULL, 170 NULL 171 }, 172 { 173 NGM_CISCO_COOKIE, 174 NGM_CISCO_GET_IPADDR, 175 "getipaddr", 176 NULL, 177 &ng_cisco_ipaddr_type 178 }, 179 { 0 } 180 }; 181 182 /* Node type descriptor */ 183 static struct ng_type typestruct = { 184 NG_ABI_VERSION, 185 NG_IFACE_NODE_TYPE, 186 NULL, 187 ng_iface_constructor, 188 ng_iface_rcvmsg, 189 ng_iface_shutdown, 190 ng_iface_newhook, 191 NULL, 192 NULL, 193 ng_iface_rcvdata, 194 ng_iface_disconnect, 195 ng_iface_cmds 196 }; 197 NETGRAPH_INIT(iface, &typestruct); 198 199 /* We keep a bitmap indicating which unit numbers are free. 200 One means the unit number is free, zero means it's taken. */ 201 static int *ng_iface_units = NULL; 202 static int ng_iface_units_len = 0; 203 204 #define UNITS_BITSPERWORD (sizeof(*ng_iface_units) * NBBY) 205 206 /************************************************************************ 207 HELPER STUFF 208 ************************************************************************/ 209 210 /* 211 * Get the family descriptor from the family ID 212 */ 213 static __inline__ iffam_p 214 get_iffam_from_af(sa_family_t family) 215 { 216 iffam_p iffam; 217 int k; 218 219 for (k = 0; k < NUM_FAMILIES; k++) { 220 iffam = &gFamilies[k]; 221 if (iffam->family == family) 222 return (iffam); 223 } 224 return (NULL); 225 } 226 227 /* 228 * Get the family descriptor from the hook 229 */ 230 static __inline__ iffam_p 231 get_iffam_from_hook(priv_p priv, hook_p hook) 232 { 233 int k; 234 235 for (k = 0; k < NUM_FAMILIES; k++) 236 if (priv->hooks[k] == hook) 237 return (&gFamilies[k]); 238 return (NULL); 239 } 240 241 /* 242 * Get the hook from the iffam descriptor 243 */ 244 245 static __inline__ hook_p * 246 get_hook_from_iffam(priv_p priv, iffam_p iffam) 247 { 248 return (&priv->hooks[iffam - gFamilies]); 249 } 250 251 /* 252 * Get the iffam descriptor from the name 253 */ 254 static __inline__ iffam_p 255 get_iffam_from_name(const char *name) 256 { 257 iffam_p iffam; 258 int k; 259 260 for (k = 0; k < NUM_FAMILIES; k++) { 261 iffam = &gFamilies[k]; 262 if (!strcmp(iffam->hookname, name)) 263 return (iffam); 264 } 265 return (NULL); 266 } 267 268 /* 269 * Find the first free unit number for a new interface. 270 * Increase the size of the unit bitmap as necessary. 271 */ 272 static __inline__ int 273 ng_iface_get_unit(int *unit) 274 { 275 int index, bit; 276 277 for (index = 0; index < ng_iface_units_len 278 && ng_iface_units[index] == 0; index++); 279 if (index == ng_iface_units_len) { /* extend array */ 280 int i, *newarray, newlen; 281 282 newlen = (2 * ng_iface_units_len) + 4; 283 MALLOC(newarray, int *, newlen * sizeof(*ng_iface_units), 284 M_NETGRAPH, M_NOWAIT); 285 if (newarray == NULL) 286 return (ENOMEM); 287 bcopy(ng_iface_units, newarray, 288 ng_iface_units_len * sizeof(*ng_iface_units)); 289 for (i = ng_iface_units_len; i < newlen; i++) 290 newarray[i] = ~0; 291 if (ng_iface_units != NULL) 292 FREE(ng_iface_units, M_NETGRAPH); 293 ng_iface_units = newarray; 294 ng_iface_units_len = newlen; 295 } 296 bit = ffs(ng_iface_units[index]) - 1; 297 KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1, 298 ("%s: word=%d bit=%d", __FUNCTION__, ng_iface_units[index], bit)); 299 ng_iface_units[index] &= ~(1 << bit); 300 *unit = (index * UNITS_BITSPERWORD) + bit; 301 return (0); 302 } 303 304 /* 305 * Free a no longer needed unit number. 306 */ 307 static __inline__ void 308 ng_iface_free_unit(int unit) 309 { 310 int index, bit; 311 312 index = unit / UNITS_BITSPERWORD; 313 bit = unit % UNITS_BITSPERWORD; 314 KASSERT(index < ng_iface_units_len, 315 ("%s: unit=%d len=%d", __FUNCTION__, unit, ng_iface_units_len)); 316 KASSERT((ng_iface_units[index] & (1 << bit)) == 0, 317 ("%s: unit=%d is free", __FUNCTION__, unit)); 318 ng_iface_units[index] |= (1 << bit); 319 /* 320 * XXX We could think about reducing the size of ng_iface_units[] 321 * XXX here if the last portion is all ones 322 */ 323 } 324 325 /************************************************************************ 326 INTERFACE STUFF 327 ************************************************************************/ 328 329 /* 330 * Process an ioctl for the virtual interface 331 */ 332 static int 333 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 334 { 335 struct ifreq *const ifr = (struct ifreq *) data; 336 int s, error = 0; 337 338 #ifdef DEBUG 339 ng_iface_print_ioctl(ifp, command, data); 340 #endif 341 s = splimp(); 342 switch (command) { 343 344 /* These two are mostly handled at a higher layer */ 345 case SIOCSIFADDR: 346 ifp->if_flags |= (IFF_UP | IFF_RUNNING); 347 ifp->if_flags &= ~(IFF_OACTIVE); 348 break; 349 case SIOCGIFADDR: 350 break; 351 352 /* Set flags */ 353 case SIOCSIFFLAGS: 354 /* 355 * If the interface is marked up and stopped, then start it. 356 * If it is marked down and running, then stop it. 357 */ 358 if (ifr->ifr_flags & IFF_UP) { 359 if (!(ifp->if_flags & IFF_RUNNING)) { 360 ifp->if_flags &= ~(IFF_OACTIVE); 361 ifp->if_flags |= IFF_RUNNING; 362 } 363 } else { 364 if (ifp->if_flags & IFF_RUNNING) 365 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 366 } 367 break; 368 369 /* Set the interface MTU */ 370 case SIOCSIFMTU: 371 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX 372 || ifr->ifr_mtu < NG_IFACE_MTU_MIN) 373 error = EINVAL; 374 else 375 ifp->if_mtu = ifr->ifr_mtu; 376 break; 377 378 /* Stuff that's not supported */ 379 case SIOCADDMULTI: 380 case SIOCDELMULTI: 381 error = 0; 382 break; 383 case SIOCSIFPHYS: 384 error = EOPNOTSUPP; 385 break; 386 387 default: 388 error = EINVAL; 389 break; 390 } 391 (void) splx(s); 392 return (error); 393 } 394 395 /* 396 * This routine is called to deliver a packet out the interface. 397 * We simply look at the address family and relay the packet to 398 * the corresponding hook, if it exists and is connected. 399 */ 400 401 static int 402 ng_iface_output(struct ifnet *ifp, struct mbuf *m, 403 struct sockaddr *dst, struct rtentry *rt0) 404 { 405 const priv_p priv = (priv_p) ifp->if_softc; 406 const iffam_p iffam = get_iffam_from_af(dst->sa_family); 407 meta_p meta = NULL; 408 int len, error = 0; 409 410 /* Check interface flags */ 411 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 412 m_freem(m); 413 return (ENETDOWN); 414 } 415 416 /* BPF writes need to be handled specially */ 417 if (dst->sa_family == AF_UNSPEC) { 418 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) 419 return (ENOBUFS); 420 dst->sa_family = (sa_family_t)*mtod(m, int32_t *); 421 m->m_data += 4; 422 m->m_len -= 4; 423 m->m_pkthdr.len -= 4; 424 } 425 426 /* Berkeley packet filter */ 427 ng_iface_bpftap(ifp, m, dst->sa_family); 428 429 /* Check address family to determine hook (if known) */ 430 if (iffam == NULL) { 431 m_freem(m); 432 log(LOG_WARNING, "%s%d: can't handle af%d\n", 433 ifp->if_name, ifp->if_unit, (int)dst->sa_family); 434 return (EAFNOSUPPORT); 435 } 436 437 /* Copy length before the mbuf gets invalidated */ 438 len = m->m_pkthdr.len; 439 440 /* Send packet; if hook is not connected, mbuf will get freed. */ 441 NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta); 442 443 /* Update stats */ 444 if (error == 0) { 445 ifp->if_obytes += len; 446 ifp->if_opackets++; 447 } 448 return (error); 449 } 450 451 /* 452 * This routine should never be called 453 */ 454 455 static void 456 ng_iface_start(struct ifnet *ifp) 457 { 458 printf("%s%d: %s called?", ifp->if_name, ifp->if_unit, __FUNCTION__); 459 } 460 461 /* 462 * Flash a packet by the BPF (requires prepending 4 byte AF header) 463 * Note the phoney mbuf; this is OK because BPF treats it read-only. 464 */ 465 static void 466 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family) 467 { 468 int32_t family4 = (int32_t)family; 469 struct mbuf m0; 470 471 KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __FUNCTION__)); 472 if (ifp->if_bpf != NULL) { 473 bzero(&m0, sizeof(m0)); 474 m0.m_next = m; 475 m0.m_len = sizeof(family4); 476 m0.m_data = (char *)&family4; 477 bpf_mtap(ifp, &m0); 478 } 479 } 480 481 #ifdef DEBUG 482 /* 483 * Display an ioctl to the virtual interface 484 */ 485 486 static void 487 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data) 488 { 489 char *str; 490 491 switch (command & IOC_DIRMASK) { 492 case IOC_VOID: 493 str = "IO"; 494 break; 495 case IOC_OUT: 496 str = "IOR"; 497 break; 498 case IOC_IN: 499 str = "IOW"; 500 break; 501 case IOC_INOUT: 502 str = "IORW"; 503 break; 504 default: 505 str = "IO??"; 506 } 507 log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n", 508 ifp->if_name, ifp->if_unit, 509 str, 510 IOCGROUP(command), 511 command & 0xff, 512 IOCPARM_LEN(command)); 513 } 514 #endif /* DEBUG */ 515 516 /************************************************************************ 517 NETGRAPH NODE STUFF 518 ************************************************************************/ 519 520 /* 521 * Constructor for a node 522 */ 523 static int 524 ng_iface_constructor(node_p node) 525 { 526 char ifname[NG_IFACE_IFACE_NAME_MAX + 1]; 527 struct ifnet *ifp; 528 priv_p priv; 529 int error = 0; 530 531 /* Allocate node and interface private structures */ 532 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT|M_ZERO); 533 if (priv == NULL) 534 return (ENOMEM); 535 MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH, M_NOWAIT|M_ZERO); 536 if (ifp == NULL) { 537 FREE(priv, M_NETGRAPH); 538 return (ENOMEM); 539 } 540 541 /* Link them together */ 542 ifp->if_softc = priv; 543 priv->ifp = ifp; 544 545 /* Get an interface unit number */ 546 if ((error = ng_iface_get_unit(&priv->unit)) != 0) { 547 FREE(ifp, M_NETGRAPH); 548 FREE(priv, M_NETGRAPH); 549 return (error); 550 } 551 552 /* Link together node and private info */ 553 node->private = priv; 554 priv->node = node; 555 556 /* Initialize interface structure */ 557 ifp->if_name = NG_IFACE_IFACE_NAME; 558 ifp->if_unit = priv->unit; 559 ifp->if_output = ng_iface_output; 560 ifp->if_start = ng_iface_start; 561 ifp->if_ioctl = ng_iface_ioctl; 562 ifp->if_watchdog = NULL; 563 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 564 ifp->if_mtu = NG_IFACE_MTU_DEFAULT; 565 ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST); 566 ifp->if_type = IFT_PROPVIRTUAL; /* XXX */ 567 ifp->if_addrlen = 0; /* XXX */ 568 ifp->if_hdrlen = 0; /* XXX */ 569 ifp->if_baudrate = 64000; /* XXX */ 570 TAILQ_INIT(&ifp->if_addrhead); 571 572 /* Give this node the same name as the interface (if possible) */ 573 bzero(ifname, sizeof(ifname)); 574 snprintf(ifname, sizeof(ifname), "%s%d", ifp->if_name, ifp->if_unit); 575 if (ng_name_node(node, ifname) != 0) 576 log(LOG_WARNING, "%s: can't acquire netgraph name\n", ifname); 577 578 /* Attach the interface */ 579 if_attach(ifp); 580 bpfattach(ifp, DLT_NULL, sizeof(u_int)); 581 582 /* Done */ 583 return (0); 584 } 585 586 /* 587 * Give our ok for a hook to be added 588 */ 589 static int 590 ng_iface_newhook(node_p node, hook_p hook, const char *name) 591 { 592 const iffam_p iffam = get_iffam_from_name(name); 593 hook_p *hookptr; 594 595 if (iffam == NULL) 596 return (EPFNOSUPPORT); 597 hookptr = get_hook_from_iffam((priv_p) node->private, iffam); 598 if (*hookptr != NULL) 599 return (EISCONN); 600 *hookptr = hook; 601 return (0); 602 } 603 604 /* 605 * Receive a control message 606 */ 607 static int 608 ng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook) 609 { 610 const priv_p priv = node->private; 611 struct ifnet *const ifp = priv->ifp; 612 struct ng_mesg *resp = NULL; 613 int error = 0; 614 struct ng_mesg *msg; 615 616 NGI_GET_MSG(item, msg); 617 switch (msg->header.typecookie) { 618 case NGM_IFACE_COOKIE: 619 switch (msg->header.cmd) { 620 case NGM_IFACE_GET_IFNAME: 621 { 622 struct ng_iface_ifname *arg; 623 624 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 625 if (resp == NULL) { 626 error = ENOMEM; 627 break; 628 } 629 arg = (struct ng_iface_ifname *)resp->data; 630 snprintf(arg->ngif_name, sizeof(arg->ngif_name), 631 "%s%d", ifp->if_name, ifp->if_unit); 632 break; 633 } 634 635 case NGM_IFACE_POINT2POINT: 636 case NGM_IFACE_BROADCAST: 637 { 638 639 /* Deny request if interface is UP */ 640 if ((ifp->if_flags & IFF_UP) != 0) 641 return (EBUSY); 642 643 /* Change flags */ 644 switch (msg->header.cmd) { 645 case NGM_IFACE_POINT2POINT: 646 ifp->if_flags |= IFF_POINTOPOINT; 647 ifp->if_flags &= ~IFF_BROADCAST; 648 break; 649 case NGM_IFACE_BROADCAST: 650 ifp->if_flags &= ~IFF_POINTOPOINT; 651 ifp->if_flags |= IFF_BROADCAST; 652 break; 653 } 654 break; 655 } 656 657 default: 658 error = EINVAL; 659 break; 660 } 661 break; 662 case NGM_CISCO_COOKIE: 663 switch (msg->header.cmd) { 664 case NGM_CISCO_GET_IPADDR: /* we understand this too */ 665 { 666 struct ifaddr *ifa; 667 668 /* Return the first configured IP address */ 669 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 670 struct ng_cisco_ipaddr *ips; 671 672 if (ifa->ifa_addr->sa_family != AF_INET) 673 continue; 674 NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT); 675 if (resp == NULL) { 676 error = ENOMEM; 677 break; 678 } 679 ips = (struct ng_cisco_ipaddr *)resp->data; 680 ips->ipaddr = ((struct sockaddr_in *) 681 ifa->ifa_addr)->sin_addr; 682 ips->netmask = ((struct sockaddr_in *) 683 ifa->ifa_netmask)->sin_addr; 684 break; 685 } 686 687 /* No IP addresses on this interface? */ 688 if (ifa == NULL) 689 error = EADDRNOTAVAIL; 690 break; 691 } 692 default: 693 error = EINVAL; 694 break; 695 } 696 break; 697 default: 698 error = EINVAL; 699 break; 700 } 701 NG_RESPOND_MSG(error, node, item, resp); 702 NG_FREE_MSG(msg); 703 return (error); 704 } 705 706 /* 707 * Recive data from a hook. Pass the packet to the correct input routine. 708 */ 709 static int 710 ng_iface_rcvdata(hook_p hook, item_p item) 711 { 712 const priv_p priv = hook->node->private; 713 const iffam_p iffam = get_iffam_from_hook(priv, hook); 714 struct ifnet *const ifp = priv->ifp; 715 struct mbuf *m; 716 717 NGI_GET_M(item, m); 718 NG_FREE_ITEM(item); 719 /* Sanity checks */ 720 KASSERT(iffam != NULL, ("%s: iffam", __FUNCTION__)); 721 KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__)); 722 if (m == NULL) 723 return (EINVAL); 724 if ((ifp->if_flags & IFF_UP) == 0) { 725 NG_FREE_M(m); 726 return (ENETDOWN); 727 } 728 729 /* Update interface stats */ 730 ifp->if_ipackets++; 731 ifp->if_ibytes += m->m_pkthdr.len; 732 733 /* Note receiving interface */ 734 m->m_pkthdr.rcvif = ifp; 735 736 /* Berkeley packet filter */ 737 ng_iface_bpftap(ifp, m, iffam->family); 738 739 /* Send packet */ 740 return family_enqueue(iffam->family, m); 741 } 742 743 /* 744 * Shutdown and remove the node and its associated interface. 745 */ 746 static int 747 ng_iface_shutdown(node_p node) 748 { 749 const priv_p priv = node->private; 750 751 bpfdetach(priv->ifp); 752 if_detach(priv->ifp); 753 priv->ifp = NULL; 754 ng_iface_free_unit(priv->unit); 755 FREE(priv, M_NETGRAPH); 756 node->private = NULL; 757 ng_unref(node); 758 return (0); 759 } 760 761 /* 762 * Hook disconnection. Note that we do *not* shutdown when all 763 * hooks have been disconnected. 764 */ 765 static int 766 ng_iface_disconnect(hook_p hook) 767 { 768 const priv_p priv = hook->node->private; 769 const iffam_p iffam = get_iffam_from_hook(priv, hook); 770 771 if (iffam == NULL) 772 panic(__FUNCTION__); 773 *get_hook_from_iffam(priv, iffam) = NULL; 774 return (0); 775 } 776 777