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_rmnode; 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_VERSION, 185 NG_IFACE_NODE_TYPE, 186 NULL, 187 ng_iface_constructor, 188 ng_iface_rcvmsg, 189 ng_iface_rmnode, 190 ng_iface_newhook, 191 NULL, 192 NULL, 193 ng_iface_rcvdata, 194 ng_iface_rcvdata, 195 ng_iface_disconnect, 196 ng_iface_cmds 197 }; 198 NETGRAPH_INIT(iface, &typestruct); 199 200 /* We keep a bitmap indicating which unit numbers are free. 201 One means the unit number is free, zero means it's taken. */ 202 static int *ng_iface_units = NULL; 203 static int ng_iface_units_len = 0; 204 205 #define UNITS_BITSPERWORD (sizeof(*ng_iface_units) * NBBY) 206 207 /************************************************************************ 208 HELPER STUFF 209 ************************************************************************/ 210 211 /* 212 * Get the family descriptor from the family ID 213 */ 214 static __inline__ iffam_p 215 get_iffam_from_af(sa_family_t family) 216 { 217 iffam_p iffam; 218 int k; 219 220 for (k = 0; k < NUM_FAMILIES; k++) { 221 iffam = &gFamilies[k]; 222 if (iffam->family == family) 223 return (iffam); 224 } 225 return (NULL); 226 } 227 228 /* 229 * Get the family descriptor from the hook 230 */ 231 static __inline__ iffam_p 232 get_iffam_from_hook(priv_p priv, hook_p hook) 233 { 234 int k; 235 236 for (k = 0; k < NUM_FAMILIES; k++) 237 if (priv->hooks[k] == hook) 238 return (&gFamilies[k]); 239 return (NULL); 240 } 241 242 /* 243 * Get the hook from the iffam descriptor 244 */ 245 246 static __inline__ hook_p * 247 get_hook_from_iffam(priv_p priv, iffam_p iffam) 248 { 249 return (&priv->hooks[iffam - gFamilies]); 250 } 251 252 /* 253 * Get the iffam descriptor from the name 254 */ 255 static __inline__ iffam_p 256 get_iffam_from_name(const char *name) 257 { 258 iffam_p iffam; 259 int k; 260 261 for (k = 0; k < NUM_FAMILIES; k++) { 262 iffam = &gFamilies[k]; 263 if (!strcmp(iffam->hookname, name)) 264 return (iffam); 265 } 266 return (NULL); 267 } 268 269 /* 270 * Find the first free unit number for a new interface. 271 * Increase the size of the unit bitmap as necessary. 272 */ 273 static __inline__ int 274 ng_iface_get_unit(int *unit) 275 { 276 int index, bit; 277 278 for (index = 0; index < ng_iface_units_len 279 && ng_iface_units[index] == 0; index++); 280 if (index == ng_iface_units_len) { /* extend array */ 281 int i, *newarray, newlen; 282 283 newlen = (2 * ng_iface_units_len) + 4; 284 MALLOC(newarray, int *, newlen * sizeof(*ng_iface_units), 285 M_NETGRAPH, M_NOWAIT); 286 if (newarray == NULL) 287 return (ENOMEM); 288 bcopy(ng_iface_units, newarray, 289 ng_iface_units_len * sizeof(*ng_iface_units)); 290 for (i = ng_iface_units_len; i < newlen; i++) 291 newarray[i] = ~0; 292 if (ng_iface_units != NULL) 293 FREE(ng_iface_units, M_NETGRAPH); 294 ng_iface_units = newarray; 295 ng_iface_units_len = newlen; 296 } 297 bit = ffs(ng_iface_units[index]) - 1; 298 KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1, 299 ("%s: word=%d bit=%d", __FUNCTION__, ng_iface_units[index], bit)); 300 ng_iface_units[index] &= ~(1 << bit); 301 *unit = (index * UNITS_BITSPERWORD) + bit; 302 return (0); 303 } 304 305 /* 306 * Free a no longer needed unit number. 307 */ 308 static __inline__ void 309 ng_iface_free_unit(int unit) 310 { 311 int index, bit; 312 313 index = unit / UNITS_BITSPERWORD; 314 bit = unit % UNITS_BITSPERWORD; 315 KASSERT(index < ng_iface_units_len, 316 ("%s: unit=%d len=%d", __FUNCTION__, unit, ng_iface_units_len)); 317 KASSERT((ng_iface_units[index] & (1 << bit)) == 0, 318 ("%s: unit=%d is free", __FUNCTION__, unit)); 319 ng_iface_units[index] |= (1 << bit); 320 /* 321 * XXX We could think about reducing the size of ng_iface_units[] 322 * XXX here if the last portion is all ones 323 */ 324 } 325 326 /************************************************************************ 327 INTERFACE STUFF 328 ************************************************************************/ 329 330 /* 331 * Process an ioctl for the virtual interface 332 */ 333 static int 334 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 335 { 336 struct ifreq *const ifr = (struct ifreq *) data; 337 int s, error = 0; 338 339 #ifdef DEBUG 340 ng_iface_print_ioctl(ifp, command, data); 341 #endif 342 s = splimp(); 343 switch (command) { 344 345 /* These two are mostly handled at a higher layer */ 346 case SIOCSIFADDR: 347 ifp->if_flags |= (IFF_UP | IFF_RUNNING); 348 ifp->if_flags &= ~(IFF_OACTIVE); 349 break; 350 case SIOCGIFADDR: 351 break; 352 353 /* Set flags */ 354 case SIOCSIFFLAGS: 355 /* 356 * If the interface is marked up and stopped, then start it. 357 * If it is marked down and running, then stop it. 358 */ 359 if (ifr->ifr_flags & IFF_UP) { 360 if (!(ifp->if_flags & IFF_RUNNING)) { 361 ifp->if_flags &= ~(IFF_OACTIVE); 362 ifp->if_flags |= IFF_RUNNING; 363 } 364 } else { 365 if (ifp->if_flags & IFF_RUNNING) 366 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 367 } 368 break; 369 370 /* Set the interface MTU */ 371 case SIOCSIFMTU: 372 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX 373 || ifr->ifr_mtu < NG_IFACE_MTU_MIN) 374 error = EINVAL; 375 else 376 ifp->if_mtu = ifr->ifr_mtu; 377 break; 378 379 /* Stuff that's not supported */ 380 case SIOCADDMULTI: 381 case SIOCDELMULTI: 382 error = 0; 383 break; 384 case SIOCSIFPHYS: 385 error = EOPNOTSUPP; 386 break; 387 388 default: 389 error = EINVAL; 390 break; 391 } 392 (void) splx(s); 393 return (error); 394 } 395 396 /* 397 * This routine is called to deliver a packet out the interface. 398 * We simply look at the address family and relay the packet to 399 * the corresponding hook, if it exists and is connected. 400 */ 401 402 static int 403 ng_iface_output(struct ifnet *ifp, struct mbuf *m, 404 struct sockaddr *dst, struct rtentry *rt0) 405 { 406 const priv_p priv = (priv_p) ifp->if_softc; 407 const iffam_p iffam = get_iffam_from_af(dst->sa_family); 408 meta_p meta = NULL; 409 int len, error = 0; 410 411 /* Check interface flags */ 412 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 413 m_freem(m); 414 return (ENETDOWN); 415 } 416 417 /* BPF writes need to be handled specially */ 418 if (dst->sa_family == AF_UNSPEC) { 419 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) 420 return (ENOBUFS); 421 dst->sa_family = (sa_family_t)*mtod(m, int32_t *); 422 m->m_data += 4; 423 m->m_len -= 4; 424 m->m_pkthdr.len -= 4; 425 } 426 427 /* Berkeley packet filter */ 428 ng_iface_bpftap(ifp, m, dst->sa_family); 429 430 /* Check address family to determine hook (if known) */ 431 if (iffam == NULL) { 432 m_freem(m); 433 log(LOG_WARNING, "%s%d: can't handle af%d\n", 434 ifp->if_name, ifp->if_unit, (int)dst->sa_family); 435 return (EAFNOSUPPORT); 436 } 437 438 /* Copy length before the mbuf gets invalidated */ 439 len = m->m_pkthdr.len; 440 441 /* Send packet; if hook is not connected, mbuf will get freed. */ 442 NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta); 443 444 /* Update stats */ 445 if (error == 0) { 446 ifp->if_obytes += len; 447 ifp->if_opackets++; 448 } 449 return (error); 450 } 451 452 /* 453 * This routine should never be called 454 */ 455 456 static void 457 ng_iface_start(struct ifnet *ifp) 458 { 459 printf("%s%d: %s called?", ifp->if_name, ifp->if_unit, __FUNCTION__); 460 } 461 462 /* 463 * Flash a packet by the BPF (requires prepending 4 byte AF header) 464 * Note the phoney mbuf; this is OK because BPF treats it read-only. 465 */ 466 static void 467 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family) 468 { 469 int32_t family4 = (int32_t)family; 470 struct mbuf m0; 471 472 KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __FUNCTION__)); 473 if (ifp->if_bpf != NULL) { 474 bzero(&m0, sizeof(m0)); 475 m0.m_next = m; 476 m0.m_len = sizeof(family4); 477 m0.m_data = (char *)&family4; 478 bpf_mtap(ifp, &m0); 479 } 480 } 481 482 #ifdef DEBUG 483 /* 484 * Display an ioctl to the virtual interface 485 */ 486 487 static void 488 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data) 489 { 490 char *str; 491 492 switch (command & IOC_DIRMASK) { 493 case IOC_VOID: 494 str = "IO"; 495 break; 496 case IOC_OUT: 497 str = "IOR"; 498 break; 499 case IOC_IN: 500 str = "IOW"; 501 break; 502 case IOC_INOUT: 503 str = "IORW"; 504 break; 505 default: 506 str = "IO??"; 507 } 508 log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n", 509 ifp->if_name, ifp->if_unit, 510 str, 511 IOCGROUP(command), 512 command & 0xff, 513 IOCPARM_LEN(command)); 514 } 515 #endif /* DEBUG */ 516 517 /************************************************************************ 518 NETGRAPH NODE STUFF 519 ************************************************************************/ 520 521 /* 522 * Constructor for a node 523 */ 524 static int 525 ng_iface_constructor(node_p *nodep) 526 { 527 char ifname[NG_IFACE_IFACE_NAME_MAX + 1]; 528 struct ifnet *ifp; 529 node_p node; 530 priv_p priv; 531 int error = 0; 532 533 /* Allocate node and interface private structures */ 534 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT|M_ZERO); 535 if (priv == NULL) 536 return (ENOMEM); 537 MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH, M_NOWAIT|M_ZERO); 538 if (ifp == NULL) { 539 FREE(priv, M_NETGRAPH); 540 return (ENOMEM); 541 } 542 543 /* Link them together */ 544 ifp->if_softc = priv; 545 priv->ifp = ifp; 546 547 /* Get an interface unit number */ 548 if ((error = ng_iface_get_unit(&priv->unit)) != 0) { 549 FREE(ifp, M_NETGRAPH); 550 FREE(priv, M_NETGRAPH); 551 return (error); 552 } 553 554 /* Call generic node constructor */ 555 if ((error = ng_make_node_common(&typestruct, nodep)) != 0) { 556 ng_iface_free_unit(priv->unit); 557 FREE(ifp, M_NETGRAPH); 558 FREE(priv, M_NETGRAPH); 559 return (error); 560 } 561 node = *nodep; 562 563 /* Link together node and private info */ 564 node->private = priv; 565 priv->node = node; 566 567 /* Initialize interface structure */ 568 ifp->if_name = NG_IFACE_IFACE_NAME; 569 ifp->if_unit = priv->unit; 570 ifp->if_output = ng_iface_output; 571 ifp->if_start = ng_iface_start; 572 ifp->if_ioctl = ng_iface_ioctl; 573 ifp->if_watchdog = NULL; 574 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 575 ifp->if_mtu = NG_IFACE_MTU_DEFAULT; 576 ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST); 577 ifp->if_type = IFT_PROPVIRTUAL; /* XXX */ 578 ifp->if_addrlen = 0; /* XXX */ 579 ifp->if_hdrlen = 0; /* XXX */ 580 ifp->if_baudrate = 64000; /* XXX */ 581 TAILQ_INIT(&ifp->if_addrhead); 582 583 /* Give this node the same name as the interface (if possible) */ 584 bzero(ifname, sizeof(ifname)); 585 snprintf(ifname, sizeof(ifname), "%s%d", ifp->if_name, ifp->if_unit); 586 if (ng_name_node(node, ifname) != 0) 587 log(LOG_WARNING, "%s: can't acquire netgraph name\n", ifname); 588 589 /* Attach the interface */ 590 if_attach(ifp); 591 bpfattach(ifp, DLT_NULL, sizeof(u_int)); 592 593 /* Done */ 594 return (0); 595 } 596 597 /* 598 * Give our ok for a hook to be added 599 */ 600 static int 601 ng_iface_newhook(node_p node, hook_p hook, const char *name) 602 { 603 const iffam_p iffam = get_iffam_from_name(name); 604 hook_p *hookptr; 605 606 if (iffam == NULL) 607 return (EPFNOSUPPORT); 608 hookptr = get_hook_from_iffam((priv_p) node->private, iffam); 609 if (*hookptr != NULL) 610 return (EISCONN); 611 *hookptr = hook; 612 return (0); 613 } 614 615 /* 616 * Receive a control message 617 */ 618 static int 619 ng_iface_rcvmsg(node_p node, struct ng_mesg *msg, 620 const char *retaddr, struct ng_mesg **rptr, hook_p lasthook) 621 { 622 const priv_p priv = node->private; 623 struct ifnet *const ifp = priv->ifp; 624 struct ng_mesg *resp = NULL; 625 int error = 0; 626 627 switch (msg->header.typecookie) { 628 case NGM_IFACE_COOKIE: 629 switch (msg->header.cmd) { 630 case NGM_IFACE_GET_IFNAME: 631 { 632 struct ng_iface_ifname *arg; 633 634 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT); 635 if (resp == NULL) { 636 error = ENOMEM; 637 break; 638 } 639 arg = (struct ng_iface_ifname *)resp->data; 640 snprintf(arg->ngif_name, sizeof(arg->ngif_name), 641 "%s%d", ifp->if_name, ifp->if_unit); 642 break; 643 } 644 645 case NGM_IFACE_POINT2POINT: 646 case NGM_IFACE_BROADCAST: 647 { 648 649 /* Deny request if interface is UP */ 650 if ((ifp->if_flags & IFF_UP) != 0) 651 return (EBUSY); 652 653 /* Change flags */ 654 switch (msg->header.cmd) { 655 case NGM_IFACE_POINT2POINT: 656 ifp->if_flags |= IFF_POINTOPOINT; 657 ifp->if_flags &= ~IFF_BROADCAST; 658 break; 659 case NGM_IFACE_BROADCAST: 660 ifp->if_flags &= ~IFF_POINTOPOINT; 661 ifp->if_flags |= IFF_BROADCAST; 662 break; 663 } 664 break; 665 } 666 667 default: 668 error = EINVAL; 669 break; 670 } 671 break; 672 case NGM_CISCO_COOKIE: 673 switch (msg->header.cmd) { 674 case NGM_CISCO_GET_IPADDR: /* we understand this too */ 675 { 676 struct ifaddr *ifa; 677 678 /* Return the first configured IP address */ 679 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 680 struct ng_cisco_ipaddr *ips; 681 682 if (ifa->ifa_addr->sa_family != AF_INET) 683 continue; 684 NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT); 685 if (resp == NULL) { 686 error = ENOMEM; 687 break; 688 } 689 ips = (struct ng_cisco_ipaddr *)resp->data; 690 ips->ipaddr = ((struct sockaddr_in *) 691 ifa->ifa_addr)->sin_addr; 692 ips->netmask = ((struct sockaddr_in *) 693 ifa->ifa_netmask)->sin_addr; 694 break; 695 } 696 697 /* No IP addresses on this interface? */ 698 if (ifa == NULL) 699 error = EADDRNOTAVAIL; 700 break; 701 } 702 default: 703 error = EINVAL; 704 break; 705 } 706 break; 707 default: 708 error = EINVAL; 709 break; 710 } 711 if (rptr) 712 *rptr = resp; 713 else if (resp) 714 FREE(resp, M_NETGRAPH); 715 FREE(msg, M_NETGRAPH); 716 return (error); 717 } 718 719 /* 720 * Recive data from a hook. Pass the packet to the correct input routine. 721 */ 722 static int 723 ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 724 struct mbuf **ret_m, meta_p *ret_meta) 725 { 726 const priv_p priv = hook->node->private; 727 const iffam_p iffam = get_iffam_from_hook(priv, hook); 728 struct ifnet *const ifp = priv->ifp; 729 730 /* Sanity checks */ 731 KASSERT(iffam != NULL, ("%s: iffam", __FUNCTION__)); 732 KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__)); 733 if (m == NULL) 734 return (EINVAL); 735 if ((ifp->if_flags & IFF_UP) == 0) { 736 NG_FREE_DATA(m, meta); 737 return (ENETDOWN); 738 } 739 740 /* Update interface stats */ 741 ifp->if_ipackets++; 742 ifp->if_ibytes += m->m_pkthdr.len; 743 744 /* Note receiving interface */ 745 m->m_pkthdr.rcvif = ifp; 746 747 /* Berkeley packet filter */ 748 ng_iface_bpftap(ifp, m, iffam->family); 749 750 /* Ignore any meta-data */ 751 NG_FREE_META(meta); 752 753 /* Send packet */ 754 return family_enqueue(iffam->family, m); 755 } 756 757 /* 758 * Shutdown and remove the node and its associated interface. 759 */ 760 static int 761 ng_iface_rmnode(node_p node) 762 { 763 const priv_p priv = node->private; 764 765 ng_cutlinks(node); 766 ng_unname(node); 767 bpfdetach(priv->ifp); 768 if_detach(priv->ifp); 769 priv->ifp = NULL; 770 ng_iface_free_unit(priv->unit); 771 FREE(priv, M_NETGRAPH); 772 node->private = NULL; 773 ng_unref(node); 774 return (0); 775 } 776 777 /* 778 * Hook disconnection. Note that we do *not* shutdown when all 779 * hooks have been disconnected. 780 */ 781 static int 782 ng_iface_disconnect(hook_p hook) 783 { 784 const priv_p priv = hook->node->private; 785 const iffam_p iffam = get_iffam_from_hook(priv, hook); 786 787 if (iffam == NULL) 788 panic(__FUNCTION__); 789 *get_hook_from_iffam(priv, iffam) = NULL; 790 return (0); 791 } 792 793