1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Redistribution of this software and documentation and use in source and 9 * binary forms, with or without modification, are permitted provided that 10 * the following conditions are met: 11 * 12 * 1. Redistributions of source code or documentation must retain the above 13 * copyright notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $Begemot: bsnmp/snmp_mibII/mibII.c,v 1.18 2004/04/13 14:58:46 novo Exp $ 34 * 35 * Implementation of the standard interfaces and ip MIB. 36 */ 37 #include "mibII.h" 38 #include "mibII_oid.h" 39 #include <net/if_types.h> 40 41 42 /*****************************/ 43 44 /* our module */ 45 static struct lmodule *module; 46 47 /* routing socket */ 48 static int route; 49 static void *route_fd; 50 51 /* if-index allocator */ 52 static u_int32_t next_if_index = 1; 53 54 /* re-fetch arp table */ 55 static int update_arp; 56 static int in_update_arp; 57 58 /* OR registrations */ 59 static u_int ifmib_reg; 60 static u_int ipmib_reg; 61 static u_int tcpmib_reg; 62 static u_int udpmib_reg; 63 static u_int ipForward_reg; 64 65 /*****************************/ 66 67 /* list of all IP addresses */ 68 struct mibifa_list mibifa_list = TAILQ_HEAD_INITIALIZER(mibifa_list); 69 70 /* list of all interfaces */ 71 struct mibif_list mibif_list = TAILQ_HEAD_INITIALIZER(mibif_list); 72 73 /* list of dynamic interface names */ 74 struct mibdynif_list mibdynif_list = SLIST_HEAD_INITIALIZER(mibdynif_list); 75 76 /* list of all interface index mappings */ 77 struct mibindexmap_list mibindexmap_list = STAILQ_HEAD_INITIALIZER(mibindexmap_list); 78 79 /* list of all stacking entries */ 80 struct mibifstack_list mibifstack_list = TAILQ_HEAD_INITIALIZER(mibifstack_list); 81 82 /* list of all receive addresses */ 83 struct mibrcvaddr_list mibrcvaddr_list = TAILQ_HEAD_INITIALIZER(mibrcvaddr_list); 84 85 /* list of all NetToMedia entries */ 86 struct mibarp_list mibarp_list = TAILQ_HEAD_INITIALIZER(mibarp_list); 87 88 /* number of interfaces */ 89 int32_t mib_if_number; 90 91 /* last change of table */ 92 u_int32_t mib_iftable_last_change; 93 94 /* last change of stack table */ 95 u_int32_t mib_ifstack_last_change; 96 97 /* if this is set, one of our lists may be bad. refresh them when idle */ 98 int mib_iflist_bad; 99 100 /* network socket */ 101 int mib_netsock; 102 103 /* last time refreshed */ 104 u_int32_t mibarpticks; 105 106 /* info on system clocks */ 107 struct clockinfo clockinfo; 108 109 /* list of all New if registrations */ 110 static struct newifreg_list newifreg_list = TAILQ_HEAD_INITIALIZER(newifreg_list); 111 112 /*****************************/ 113 114 static const struct asn_oid oid_ifMIB = OIDX_ifMIB; 115 static const struct asn_oid oid_ipMIB = OIDX_ipMIB; 116 static const struct asn_oid oid_tcpMIB = OIDX_tcpMIB; 117 static const struct asn_oid oid_udpMIB = OIDX_udpMIB; 118 static const struct asn_oid oid_ipForward = OIDX_ipForward; 119 static const struct asn_oid oid_linkDown = OIDX_linkDown; 120 static const struct asn_oid oid_linkUp = OIDX_linkUp; 121 static const struct asn_oid oid_ifIndex = OIDX_ifIndex; 122 123 /*****************************/ 124 125 /* 126 * Find an interface 127 */ 128 struct mibif * 129 mib_find_if(u_int idx) 130 { 131 struct mibif *ifp; 132 133 TAILQ_FOREACH(ifp, &mibif_list, link) 134 if (ifp->index == idx) 135 return (ifp); 136 return (NULL); 137 } 138 139 struct mibif * 140 mib_find_if_sys(u_int sysindex) 141 { 142 struct mibif *ifp; 143 144 TAILQ_FOREACH(ifp, &mibif_list, link) 145 if (ifp->sysindex == sysindex) 146 return (ifp); 147 return (NULL); 148 } 149 150 struct mibif * 151 mib_find_if_name(const char *name) 152 { 153 struct mibif *ifp; 154 155 TAILQ_FOREACH(ifp, &mibif_list, link) 156 if (strcmp(ifp->name, name) == 0) 157 return (ifp); 158 return (NULL); 159 } 160 161 /* 162 * Check whether an interface is dynamic. The argument may include the 163 * unit number. This assumes, that the name part does NOT contain digits. 164 */ 165 int 166 mib_if_is_dyn(const char *name) 167 { 168 size_t len; 169 struct mibdynif *d; 170 171 for (len = 0; name[len] != '\0' && isalpha(name[len]) ; len++) 172 ; 173 SLIST_FOREACH(d, &mibdynif_list, link) 174 if (strlen(d->name) == len && strncmp(d->name, name, len) == 0) 175 return (1); 176 return (0); 177 } 178 179 /* set an interface name to dynamic mode */ 180 void 181 mib_if_set_dyn(const char *name) 182 { 183 struct mibdynif *d; 184 185 SLIST_FOREACH(d, &mibdynif_list, link) 186 if (strcmp(name, d->name) == 0) 187 return; 188 if ((d = malloc(sizeof(*d))) == NULL) 189 err(1, NULL); 190 strcpy(d->name, name); 191 SLIST_INSERT_HEAD(&mibdynif_list, d, link); 192 } 193 194 /* 195 * register for interface creations 196 */ 197 int 198 mib_register_newif(int (*func)(struct mibif *), const struct lmodule *mod) 199 { 200 struct newifreg *reg; 201 202 TAILQ_FOREACH(reg, &newifreg_list, link) 203 if (reg->mod == mod) { 204 reg->func = func; 205 return (0); 206 } 207 if ((reg = malloc(sizeof(*reg))) == NULL) { 208 syslog(LOG_ERR, "newifreg: %m"); 209 return (-1); 210 } 211 reg->mod = mod; 212 reg->func = func; 213 TAILQ_INSERT_TAIL(&newifreg_list, reg, link); 214 215 return (0); 216 } 217 218 void 219 mib_unregister_newif(const struct lmodule *mod) 220 { 221 struct newifreg *reg; 222 223 TAILQ_FOREACH(reg, &newifreg_list, link) 224 if (reg->mod == mod) { 225 TAILQ_REMOVE(&newifreg_list, reg, link); 226 free(reg); 227 return; 228 } 229 230 } 231 232 struct mibif * 233 mib_first_if(void) 234 { 235 return (TAILQ_FIRST(&mibif_list)); 236 } 237 struct mibif * 238 mib_next_if(const struct mibif *ifp) 239 { 240 return (TAILQ_NEXT(ifp, link)); 241 } 242 243 /* 244 * Change the admin status of an interface 245 */ 246 int 247 mib_if_admin(struct mibif *ifp, int up) 248 { 249 struct ifreq ifr; 250 251 strncpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 252 if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) { 253 syslog(LOG_ERR, "SIOCGIFFLAGS(%s): %m", ifp->name); 254 return (-1); 255 } 256 if (up) 257 ifr.ifr_flags |= IFF_UP; 258 else 259 ifr.ifr_flags &= ~IFF_UP; 260 if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { 261 syslog(LOG_ERR, "SIOCSIFFLAGS(%s): %m", ifp->name); 262 return (-1); 263 } 264 265 (void)mib_fetch_ifmib(ifp); 266 267 return (0); 268 } 269 270 /* 271 * Generate a link up/down trap 272 */ 273 static void 274 link_trap(struct mibif *ifp, int up) 275 { 276 struct snmp_value ifindex; 277 278 ifindex.var = oid_ifIndex; 279 ifindex.var.subs[ifindex.var.len++] = ifp->index; 280 ifindex.syntax = SNMP_SYNTAX_INTEGER; 281 ifindex.v.integer = ifp->index; 282 283 snmp_send_trap(up ? &oid_linkUp : &oid_linkDown, &ifindex, NULL); 284 } 285 286 /* 287 * Fetch new MIB data. 288 */ 289 int 290 mib_fetch_ifmib(struct mibif *ifp) 291 { 292 int name[6]; 293 size_t len; 294 void *newmib; 295 struct ifmibdata oldmib = ifp->mib; 296 297 name[0] = CTL_NET; 298 name[1] = PF_LINK; 299 name[2] = NETLINK_GENERIC; 300 name[3] = IFMIB_IFDATA; 301 name[4] = ifp->sysindex; 302 name[5] = IFDATA_GENERAL; 303 304 len = sizeof(ifp->mib); 305 if (sysctl(name, 6, &ifp->mib, &len, NULL, 0) == -1) { 306 if (errno != ENOENT) 307 syslog(LOG_WARNING, "sysctl(ifmib, %s) failed %m", 308 ifp->name); 309 return (-1); 310 } 311 312 if (ifp->trap_enable) { 313 if (!(oldmib.ifmd_flags & IFF_UP)) { 314 if (ifp->mib.ifmd_flags & IFF_UP) 315 link_trap(ifp, 1); 316 } else { 317 if (!(ifp->mib.ifmd_flags & IFF_UP)) 318 link_trap(ifp, 0); 319 } 320 } 321 322 ifp->flags &= ~(MIBIF_HIGHSPEED | MIBIF_VERYHIGHSPEED); 323 if (ifp->mib.ifmd_data.ifi_baudrate > 20000000) { 324 ifp->flags |= MIBIF_HIGHSPEED; 325 if (ifp->mib.ifmd_data.ifi_baudrate > 650000000) 326 ifp->flags |= MIBIF_VERYHIGHSPEED; 327 } 328 329 /* 330 * linkspecific MIB 331 */ 332 name[5] = IFDATA_LINKSPECIFIC; 333 if (sysctl(name, 6, NULL, &len, NULL, 0) == -1) { 334 syslog(LOG_WARNING, "sysctl linkmib estimate (%s): %m", 335 ifp->name); 336 if (ifp->specmib != NULL) { 337 ifp->specmib = NULL; 338 ifp->specmiblen = 0; 339 } 340 goto out; 341 } 342 if (len == 0) { 343 if (ifp->specmib != NULL) { 344 ifp->specmib = NULL; 345 ifp->specmiblen = 0; 346 } 347 goto out; 348 } 349 350 if (ifp->specmiblen != len) { 351 if ((newmib = realloc(ifp->specmib, len)) == NULL) { 352 ifp->specmib = NULL; 353 ifp->specmiblen = 0; 354 goto out; 355 } 356 ifp->specmib = newmib; 357 ifp->specmiblen = len; 358 } 359 if (sysctl(name, 6, ifp->specmib, &len, NULL, 0) == -1) { 360 syslog(LOG_WARNING, "sysctl linkmib (%s): %m", ifp->name); 361 if (ifp->specmib != NULL) { 362 ifp->specmib = NULL; 363 ifp->specmiblen = 0; 364 } 365 } 366 367 out: 368 ifp->mibtick = get_ticks(); 369 return (0); 370 } 371 372 /* find first/next address for a given interface */ 373 struct mibifa * 374 mib_first_ififa(const struct mibif *ifp) 375 { 376 struct mibifa *ifa; 377 378 TAILQ_FOREACH(ifa, &mibifa_list, link) 379 if (ifp->index == ifa->ifindex) 380 return (ifa); 381 return (NULL); 382 } 383 384 struct mibifa * 385 mib_next_ififa(struct mibifa *ifa0) 386 { 387 struct mibifa *ifa; 388 389 ifa = ifa0; 390 while ((ifa = TAILQ_NEXT(ifa, link)) != NULL) 391 if (ifa->ifindex == ifa0->ifindex) 392 return (ifa); 393 return (NULL); 394 } 395 396 /* 397 * Allocate a new IFA 398 */ 399 static struct mibifa * 400 alloc_ifa(u_int ifindex, struct in_addr addr) 401 { 402 struct mibifa *ifa; 403 u_int32_t ha; 404 405 if ((ifa = malloc(sizeof(struct mibifa))) == NULL) { 406 syslog(LOG_ERR, "ifa: %m"); 407 return (NULL); 408 } 409 ifa->inaddr = addr; 410 ifa->ifindex = ifindex; 411 412 ha = ntohl(ifa->inaddr.s_addr); 413 ifa->index.len = 4; 414 ifa->index.subs[0] = (ha >> 24) & 0xff; 415 ifa->index.subs[1] = (ha >> 16) & 0xff; 416 ifa->index.subs[2] = (ha >> 8) & 0xff; 417 ifa->index.subs[3] = (ha >> 0) & 0xff; 418 419 ifa->flags = 0; 420 ifa->inbcast.s_addr = 0; 421 ifa->inmask.s_addr = 0xffffffff; 422 423 INSERT_OBJECT_OID(ifa, &mibifa_list); 424 425 return (ifa); 426 } 427 428 /* 429 * Delete an interface address 430 */ 431 static void 432 destroy_ifa(struct mibifa *ifa) 433 { 434 TAILQ_REMOVE(&mibifa_list, ifa, link); 435 free(ifa); 436 } 437 438 439 /* 440 * Helper routine to extract the sockaddr structures from a routing 441 * socket message. 442 */ 443 void 444 mib_extract_addrs(int addrs, u_char *info, struct sockaddr **out) 445 { 446 u_int i; 447 448 for (i = 0; i < RTAX_MAX; i++) { 449 if ((addrs & (1 << i)) != 0) { 450 *out = (struct sockaddr *)info; 451 info += roundup((*out)->sa_len, sizeof(long)); 452 } else 453 *out = NULL; 454 out++; 455 } 456 } 457 458 /* 459 * save the phys address of an interface. Handle receive address entries here. 460 */ 461 static void 462 get_physaddr(struct mibif *ifp, struct sockaddr_dl *sdl, u_char *ptr) 463 { 464 u_char *np; 465 struct mibrcvaddr *rcv; 466 467 if (sdl->sdl_alen == 0) { 468 /* no address */ 469 if (ifp->physaddrlen != 0) { 470 if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, 471 ifp->physaddrlen)) != NULL) 472 mib_rcvaddr_delete(rcv); 473 free(ifp->physaddr); 474 ifp->physaddr = NULL; 475 ifp->physaddrlen = 0; 476 } 477 return; 478 } 479 480 if (ifp->physaddrlen != sdl->sdl_alen) { 481 /* length changed */ 482 if (ifp->physaddrlen) { 483 /* delete olf receive address */ 484 if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, 485 ifp->physaddrlen)) != NULL) 486 mib_rcvaddr_delete(rcv); 487 } 488 if ((np = realloc(ifp->physaddr, sdl->sdl_alen)) == NULL) { 489 free(ifp->physaddr); 490 ifp->physaddr = NULL; 491 ifp->physaddrlen = 0; 492 return; 493 } 494 ifp->physaddr = np; 495 ifp->physaddrlen = sdl->sdl_alen; 496 497 } else if (memcmp(ifp->physaddr, ptr, ifp->physaddrlen) == 0) { 498 /* no change */ 499 return; 500 501 } else { 502 /* address changed */ 503 504 /* delete olf receive address */ 505 if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, 506 ifp->physaddrlen)) != NULL) 507 mib_rcvaddr_delete(rcv); 508 } 509 510 memcpy(ifp->physaddr, ptr, ifp->physaddrlen); 511 512 /* make new receive address */ 513 if ((rcv = mib_rcvaddr_create(ifp, ifp->physaddr, ifp->physaddrlen)) != NULL) 514 rcv->flags |= MIBRCVADDR_HW; 515 } 516 517 /* 518 * Free an interface 519 */ 520 static void 521 mibif_free(struct mibif *ifp) 522 { 523 struct mibindexmap *map; 524 struct mibifa *ifa, *ifa1; 525 struct mibrcvaddr *rcv, *rcv1; 526 struct mibarp *at, *at1; 527 528 if (ifp->xnotify != NULL) 529 (*ifp->xnotify)(ifp, MIBIF_NOTIFY_DESTROY, ifp->xnotify_data); 530 531 (void)mib_ifstack_delete(ifp, NULL); 532 (void)mib_ifstack_delete(NULL, ifp); 533 534 TAILQ_REMOVE(&mibif_list, ifp, link); 535 if (ifp->physaddr != NULL) 536 free(ifp->physaddr); 537 if (ifp->specmib != NULL) 538 free(ifp->specmib); 539 540 STAILQ_FOREACH(map, &mibindexmap_list, link) 541 if (map->mibif == ifp) { 542 map->mibif = NULL; 543 break; 544 } 545 546 /* purge interface addresses */ 547 ifa = TAILQ_FIRST(&mibifa_list); 548 while (ifa != NULL) { 549 ifa1 = TAILQ_NEXT(ifa, link); 550 if (ifa->ifindex == ifp->index) 551 destroy_ifa(ifa); 552 ifa = ifa1; 553 } 554 555 /* purge receive addresses */ 556 rcv = TAILQ_FIRST(&mibrcvaddr_list); 557 while (rcv != NULL) { 558 rcv1 = TAILQ_NEXT(rcv, link); 559 if (rcv->ifindex == ifp->index) 560 mib_rcvaddr_delete(rcv); 561 rcv = rcv1; 562 } 563 564 /* purge ARP entries */ 565 at = TAILQ_FIRST(&mibarp_list); 566 while (at != NULL) { 567 at1 = TAILQ_NEXT(at, link); 568 if (at->index.subs[0] == ifp->index) 569 mib_arp_delete(at); 570 at = at1; 571 } 572 573 574 free(ifp); 575 mib_if_number--; 576 mib_iftable_last_change = this_tick; 577 } 578 579 /* 580 * Create a new interface 581 */ 582 static struct mibif * 583 mibif_create(u_int sysindex, const char *name) 584 { 585 struct mibif *ifp; 586 struct mibindexmap *map; 587 588 if ((ifp = malloc(sizeof(*ifp))) == NULL) { 589 syslog(LOG_WARNING, "%s: %m", __func__); 590 return (NULL); 591 } 592 memset(ifp, 0, sizeof(*ifp)); 593 ifp->sysindex = sysindex; 594 strcpy(ifp->name, name); 595 strcpy(ifp->descr, name); 596 597 map = NULL; 598 if (!mib_if_is_dyn(ifp->name)) { 599 /* non-dynamic. look whether we know the interface */ 600 STAILQ_FOREACH(map, &mibindexmap_list, link) 601 if (strcmp(map->name, ifp->name) == 0) { 602 ifp->index = map->ifindex; 603 map->mibif = ifp; 604 break; 605 } 606 /* assume it has a connector if it is not dynamic */ 607 ifp->has_connector = 1; 608 ifp->trap_enable = 1; 609 } 610 if (map == NULL) { 611 /* new interface - get new index */ 612 if (next_if_index > 0x7fffffff) 613 errx(1, "ifindex wrap"); 614 615 if ((map = malloc(sizeof(*map))) == NULL) { 616 syslog(LOG_ERR, "ifmap: %m"); 617 free(ifp); 618 return (NULL); 619 } 620 map->ifindex = next_if_index++; 621 map->sysindex = ifp->sysindex; 622 strcpy(map->name, ifp->name); 623 map->mibif = ifp; 624 STAILQ_INSERT_TAIL(&mibindexmap_list, map, link); 625 } else { 626 /* re-instantiate. Introduce a counter discontinuity */ 627 ifp->counter_disc = get_ticks(); 628 } 629 ifp->index = map->ifindex; 630 631 INSERT_OBJECT_INT(ifp, &mibif_list); 632 mib_if_number++; 633 mib_iftable_last_change = this_tick; 634 635 /* instantiate default ifStack entries */ 636 (void)mib_ifstack_create(ifp, NULL); 637 (void)mib_ifstack_create(NULL, ifp); 638 639 return (ifp); 640 } 641 642 /* 643 * Inform all interested parties about a new interface 644 */ 645 static void 646 notify_newif(struct mibif *ifp) 647 { 648 struct newifreg *reg; 649 650 TAILQ_FOREACH(reg, &newifreg_list, link) 651 if ((*reg->func)(ifp)) 652 return; 653 } 654 655 /* 656 * This is called for new interfaces after we have fetched the interface 657 * MIB. If this is a broadcast interface try to guess the broadcast address 658 * depending on the interface type. 659 */ 660 static void 661 check_llbcast(struct mibif *ifp) 662 { 663 static u_char ether_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 664 static u_char arcnet_bcast = 0; 665 struct mibrcvaddr *rcv; 666 667 if (!(ifp->mib.ifmd_flags & IFF_BROADCAST)) 668 return; 669 670 switch (ifp->mib.ifmd_data.ifi_type) { 671 672 case IFT_ETHER: 673 case IFT_FDDI: 674 case IFT_ISO88025: 675 if (mib_find_rcvaddr(ifp->index, ether_bcast, 6) == NULL && 676 (rcv = mib_rcvaddr_create(ifp, ether_bcast, 6)) != NULL) 677 rcv->flags |= MIBRCVADDR_BCAST; 678 break; 679 680 case IFT_ARCNET: 681 if (mib_find_rcvaddr(ifp->index, &arcnet_bcast, 1) == NULL && 682 (rcv = mib_rcvaddr_create(ifp, &arcnet_bcast, 1)) != NULL) 683 rcv->flags |= MIBRCVADDR_BCAST; 684 break; 685 } 686 } 687 688 689 /* 690 * Retrieve the current interface list from the system. 691 */ 692 void 693 mib_refresh_iflist(void) 694 { 695 struct mibif *ifp, *ifp1; 696 size_t len; 697 u_short idx; 698 int name[6]; 699 int count; 700 struct ifmibdata mib; 701 702 TAILQ_FOREACH(ifp, &mibif_list, link) 703 ifp->flags &= ~MIBIF_FOUND; 704 705 len = sizeof(count); 706 if (sysctlbyname("net.link.generic.system.ifcount", &count, &len, 707 NULL, 0) == -1) { 708 syslog(LOG_ERR, "ifcount: %m"); 709 return; 710 } 711 name[0] = CTL_NET; 712 name[1] = PF_LINK; 713 name[2] = NETLINK_GENERIC; 714 name[3] = IFMIB_IFDATA; 715 name[5] = IFDATA_GENERAL; 716 for (idx = 1; idx <= count; idx++) { 717 name[4] = idx; 718 len = sizeof(mib); 719 if (sysctl(name, 6, &mib, &len, NULL, 0) == -1) { 720 if (errno == ENOENT) 721 continue; 722 syslog(LOG_ERR, "ifmib(%u): %m", idx); 723 return; 724 } 725 if ((ifp = mib_find_if_sys(idx)) != NULL) { 726 ifp->flags |= MIBIF_FOUND; 727 continue; 728 } 729 /* Unknown interface - create */ 730 if ((ifp = mibif_create(idx, mib.ifmd_name)) != NULL) { 731 ifp->flags |= MIBIF_FOUND; 732 (void)mib_fetch_ifmib(ifp); 733 check_llbcast(ifp); 734 notify_newif(ifp); 735 } 736 } 737 738 /* 739 * Purge interfaces that disappeared 740 */ 741 ifp = TAILQ_FIRST(&mibif_list); 742 while (ifp != NULL) { 743 ifp1 = TAILQ_NEXT(ifp, link); 744 if (!(ifp->flags & MIBIF_FOUND)) 745 mibif_free(ifp); 746 ifp = ifp1; 747 } 748 } 749 750 /* 751 * Find an interface address 752 */ 753 struct mibifa * 754 mib_find_ifa(struct in_addr addr) 755 { 756 struct mibifa *ifa; 757 758 TAILQ_FOREACH(ifa, &mibifa_list, link) 759 if (ifa->inaddr.s_addr == addr.s_addr) 760 return (ifa); 761 return (NULL); 762 } 763 764 /* 765 * Process a new ARP entry 766 */ 767 static void 768 process_arp(const struct rt_msghdr *rtm, const struct sockaddr_dl *sdl, 769 const struct sockaddr_in *sa) 770 { 771 struct mibif *ifp; 772 struct mibarp *at; 773 774 /* IP arp table entry */ 775 if (sdl->sdl_alen == 0) { 776 update_arp = 1; 777 return; 778 } 779 if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) 780 return; 781 /* have a valid entry */ 782 if ((at = mib_find_arp(ifp, sa->sin_addr)) == NULL && 783 (at = mib_arp_create(ifp, sa->sin_addr, 784 sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) 785 return; 786 787 if (rtm->rtm_rmx.rmx_expire == 0) 788 at->flags |= MIBARP_PERM; 789 else 790 at->flags &= ~MIBARP_PERM; 791 at->flags |= MIBARP_FOUND; 792 } 793 794 /* 795 * Handle a routing socket message. 796 */ 797 static void 798 handle_rtmsg(struct rt_msghdr *rtm) 799 { 800 struct sockaddr *addrs[RTAX_MAX]; 801 struct if_msghdr *ifm; 802 struct ifa_msghdr *ifam; 803 struct ifma_msghdr *ifmam; 804 #ifdef RTM_IFANNOUNCE 805 struct if_announcemsghdr *ifan; 806 #endif 807 struct mibif *ifp; 808 struct sockaddr_dl *sdl; 809 struct sockaddr_in *sa; 810 struct mibifa *ifa; 811 struct mibrcvaddr *rcv; 812 u_char *ptr; 813 814 if (rtm->rtm_version != RTM_VERSION) { 815 syslog(LOG_ERR, "Bogus RTM version %u", rtm->rtm_version); 816 return; 817 } 818 819 switch (rtm->rtm_type) { 820 821 case RTM_NEWADDR: 822 ifam = (struct ifa_msghdr *)rtm; 823 mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs); 824 if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL) 825 break; 826 827 sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; 828 if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) { 829 /* unknown address */ 830 if ((ifp = mib_find_if_sys(ifam->ifam_index)) == NULL) { 831 syslog(LOG_WARNING, "RTM_NEWADDR for unknown " 832 "interface %u", ifam->ifam_index); 833 break; 834 } 835 if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL) 836 break; 837 } 838 sa = (struct sockaddr_in *)(void *)addrs[RTAX_NETMASK]; 839 ifa->inmask = sa->sin_addr; 840 841 if (addrs[RTAX_BRD] != NULL) { 842 sa = (struct sockaddr_in *)(void *)addrs[RTAX_BRD]; 843 ifa->inbcast = sa->sin_addr; 844 } 845 ifa->flags |= MIBIFA_FOUND; 846 break; 847 848 case RTM_DELADDR: 849 ifam = (struct ifa_msghdr *)rtm; 850 mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs); 851 if (addrs[RTAX_IFA] == NULL) 852 break; 853 854 sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; 855 if ((ifa = mib_find_ifa(sa->sin_addr)) != NULL) { 856 ifa->flags |= MIBIFA_FOUND; 857 if (!(ifa->flags & MIBIFA_DESTROYED)) 858 destroy_ifa(ifa); 859 } 860 break; 861 862 case RTM_NEWMADDR: 863 ifmam = (struct ifma_msghdr *)rtm; 864 mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); 865 if (addrs[RTAX_IFA] == NULL || 866 addrs[RTAX_IFA]->sa_family != AF_LINK) 867 break; 868 sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; 869 if ((rcv = mib_find_rcvaddr(sdl->sdl_index, 870 sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) { 871 /* unknown address */ 872 if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) { 873 syslog(LOG_WARNING, "RTM_NEWMADDR for unknown " 874 "interface %u", sdl->sdl_index); 875 break; 876 } 877 if ((rcv = mib_rcvaddr_create(ifp, 878 sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) 879 break; 880 rcv->flags |= MIBRCVADDR_VOLATILE; 881 } 882 rcv->flags |= MIBRCVADDR_FOUND; 883 break; 884 885 case RTM_DELMADDR: 886 ifmam = (struct ifma_msghdr *)rtm; 887 mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); 888 if (addrs[RTAX_IFA] == NULL || 889 addrs[RTAX_IFA]->sa_family != AF_LINK) 890 break; 891 sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; 892 if ((rcv = mib_find_rcvaddr(sdl->sdl_index, 893 sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) != NULL) 894 mib_rcvaddr_delete(rcv); 895 break; 896 897 case RTM_IFINFO: 898 ifm = (struct if_msghdr *)rtm; 899 mib_extract_addrs(ifm->ifm_addrs, (u_char *)(ifm + 1), addrs); 900 if ((ifp = mib_find_if_sys(ifm->ifm_index)) == NULL) 901 break; 902 if (addrs[RTAX_IFP] != NULL && 903 addrs[RTAX_IFP]->sa_family == AF_LINK) { 904 sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFP]; 905 ptr = sdl->sdl_data + sdl->sdl_nlen; 906 get_physaddr(ifp, sdl, ptr); 907 } 908 (void)mib_fetch_ifmib(ifp); 909 break; 910 911 #ifdef RTM_IFANNOUNCE 912 case RTM_IFANNOUNCE: 913 ifan = (struct if_announcemsghdr *)rtm; 914 ifp = mib_find_if_sys(ifan->ifan_index); 915 916 switch (ifan->ifan_what) { 917 918 case IFAN_ARRIVAL: 919 if (ifp == NULL && (ifp = mibif_create(ifan->ifan_index, 920 ifan->ifan_name)) != NULL) { 921 (void)mib_fetch_ifmib(ifp); 922 check_llbcast(ifp); 923 notify_newif(ifp); 924 } 925 break; 926 927 case IFAN_DEPARTURE: 928 if (ifp != NULL) 929 mibif_free(ifp); 930 break; 931 } 932 break; 933 #endif 934 935 case RTM_GET: 936 mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); 937 if (rtm->rtm_flags & RTF_LLINFO) { 938 if (addrs[RTAX_DST] == NULL || 939 addrs[RTAX_GATEWAY] == NULL || 940 addrs[RTAX_DST]->sa_family != AF_INET || 941 addrs[RTAX_GATEWAY]->sa_family != AF_LINK) 942 break; 943 process_arp(rtm, 944 (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY], 945 (struct sockaddr_in *)(void *)addrs[RTAX_DST]); 946 } 947 break; 948 949 case RTM_ADD: 950 mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); 951 if (rtm->rtm_flags & RTF_LLINFO) { 952 if (addrs[RTAX_DST] == NULL || 953 addrs[RTAX_GATEWAY] == NULL || 954 addrs[RTAX_DST]->sa_family != AF_INET || 955 addrs[RTAX_GATEWAY]->sa_family != AF_LINK) 956 break; 957 process_arp(rtm, 958 (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY], 959 (struct sockaddr_in *)(void *)addrs[RTAX_DST]); 960 } 961 break; 962 } 963 } 964 965 /* 966 * Fetch the routing table via sysctl 967 */ 968 u_char * 969 mib_fetch_rtab(int af, int info, int arg, size_t *lenp) 970 { 971 int name[6]; 972 u_char *buf; 973 974 name[0] = CTL_NET; 975 name[1] = PF_ROUTE; 976 name[2] = 0; 977 name[3] = af; 978 name[4] = info; 979 name[5] = arg; 980 981 *lenp = 0; 982 983 if (sysctl(name, 6, NULL, lenp, NULL, 0) == -1) { 984 syslog(LOG_ERR, "sysctl estimate (%d,%d,%d,%d,%d,%d): %m", 985 name[0], name[1], name[2], name[3], name[4], name[5]); 986 return (NULL); 987 } 988 if (*lenp == 0) 989 return (NULL); 990 991 if ((buf = malloc(*lenp)) == NULL) { 992 syslog(LOG_ERR, "sysctl buffer: %m"); 993 return (NULL); 994 } 995 996 if (sysctl(name, 6, buf, lenp, NULL, 0) == -1) { 997 syslog(LOG_ERR, "sysctl get: %m"); 998 free(buf); 999 return (NULL); 1000 } 1001 1002 return (buf); 1003 } 1004 1005 /* 1006 * Update the following info: interface, interface addresses, interface 1007 * receive addresses, arp-table. 1008 * This does not change the interface list itself. 1009 */ 1010 static void 1011 update_ifa_info(void) 1012 { 1013 u_char *buf, *next; 1014 struct rt_msghdr *rtm; 1015 struct mibifa *ifa, *ifa1; 1016 struct mibrcvaddr *rcv, *rcv1; 1017 size_t needed; 1018 static const int infos[][3] = { 1019 { 0, NET_RT_IFLIST, 0 }, 1020 #ifdef NET_RT_IFMALIST 1021 { AF_LINK, NET_RT_IFMALIST, 0 }, 1022 #endif 1023 }; 1024 u_int i; 1025 1026 TAILQ_FOREACH(ifa, &mibifa_list, link) 1027 ifa->flags &= ~MIBIFA_FOUND; 1028 TAILQ_FOREACH(rcv, &mibrcvaddr_list, link) 1029 rcv->flags &= ~MIBRCVADDR_FOUND; 1030 1031 for (i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) { 1032 if ((buf = mib_fetch_rtab(infos[i][0], infos[i][1], infos[i][2], 1033 &needed)) == NULL) 1034 continue; 1035 1036 next = buf; 1037 while (next < buf + needed) { 1038 rtm = (struct rt_msghdr *)(void *)next; 1039 next += rtm->rtm_msglen; 1040 handle_rtmsg(rtm); 1041 } 1042 free(buf); 1043 } 1044 1045 /* 1046 * Purge the address list of unused entries. These may happen for 1047 * interface aliases that are on the same subnet. We don't receive 1048 * routing socket messages for them. 1049 */ 1050 ifa = TAILQ_FIRST(&mibifa_list); 1051 while (ifa != NULL) { 1052 ifa1 = TAILQ_NEXT(ifa, link); 1053 if (!(ifa->flags & MIBIFA_FOUND)) 1054 destroy_ifa(ifa); 1055 ifa = ifa1; 1056 } 1057 1058 rcv = TAILQ_FIRST(&mibrcvaddr_list); 1059 while (rcv != NULL) { 1060 rcv1 = TAILQ_NEXT(rcv, link); 1061 if (!(rcv->flags & (MIBRCVADDR_FOUND | MIBRCVADDR_BCAST | 1062 MIBRCVADDR_HW))) 1063 mib_rcvaddr_delete(rcv); 1064 rcv = rcv1; 1065 } 1066 } 1067 1068 /* 1069 * Update arp table 1070 */ 1071 void 1072 mib_arp_update(void) 1073 { 1074 struct mibarp *at, *at1; 1075 size_t needed; 1076 u_char *buf, *next; 1077 struct rt_msghdr *rtm; 1078 1079 if (in_update_arp) 1080 return; /* Aaargh */ 1081 in_update_arp = 1; 1082 1083 TAILQ_FOREACH(at, &mibarp_list, link) 1084 at->flags &= ~MIBARP_FOUND; 1085 1086 if ((buf = mib_fetch_rtab(AF_INET, NET_RT_FLAGS, RTF_LLINFO, &needed)) == NULL) { 1087 in_update_arp = 0; 1088 return; 1089 } 1090 1091 next = buf; 1092 while (next < buf + needed) { 1093 rtm = (struct rt_msghdr *)(void *)next; 1094 next += rtm->rtm_msglen; 1095 handle_rtmsg(rtm); 1096 } 1097 free(buf); 1098 1099 at = TAILQ_FIRST(&mibarp_list); 1100 while (at != NULL) { 1101 at1 = TAILQ_NEXT(at, link); 1102 if (!(at->flags & MIBARP_FOUND)) 1103 mib_arp_delete(at); 1104 at = at1; 1105 } 1106 mibarpticks = get_ticks(); 1107 update_arp = 0; 1108 in_update_arp = 0; 1109 } 1110 1111 1112 /* 1113 * Intput on the routing socket. 1114 */ 1115 static void 1116 route_input(int fd, void *udata __unused) 1117 { 1118 u_char buf[1024 * 16]; 1119 ssize_t n; 1120 struct rt_msghdr *rtm; 1121 1122 if ((n = read(fd, buf, sizeof(buf))) == -1) 1123 err(1, "read(rt_socket)"); 1124 1125 if (n == 0) 1126 errx(1, "EOF on rt_socket"); 1127 1128 rtm = (struct rt_msghdr *)(void *)buf; 1129 if ((size_t)n != rtm->rtm_msglen) 1130 errx(1, "n=%zu, rtm_msglen=%u", (size_t)n, rtm->rtm_msglen); 1131 1132 handle_rtmsg(rtm); 1133 } 1134 1135 /* 1136 * execute and SIOCAIFADDR 1137 */ 1138 static int 1139 siocaifaddr(char *ifname, struct in_addr addr, struct in_addr mask, 1140 struct in_addr bcast) 1141 { 1142 struct ifaliasreq addreq; 1143 struct sockaddr_in *sa; 1144 1145 memset(&addreq, 0, sizeof(addreq)); 1146 strncpy(addreq.ifra_name, ifname, sizeof(addreq.ifra_name)); 1147 1148 sa = (struct sockaddr_in *)(void *)&addreq.ifra_addr; 1149 sa->sin_family = AF_INET; 1150 sa->sin_len = sizeof(*sa); 1151 sa->sin_addr = addr; 1152 1153 sa = (struct sockaddr_in *)(void *)&addreq.ifra_mask; 1154 sa->sin_family = AF_INET; 1155 sa->sin_len = sizeof(*sa); 1156 sa->sin_addr = mask; 1157 1158 sa = (struct sockaddr_in *)(void *)&addreq.ifra_broadaddr; 1159 sa->sin_family = AF_INET; 1160 sa->sin_len = sizeof(*sa); 1161 sa->sin_addr = bcast; 1162 1163 return (ioctl(mib_netsock, SIOCAIFADDR, &addreq)); 1164 } 1165 1166 /* 1167 * Exececute a SIOCDIFADDR 1168 */ 1169 static int 1170 siocdifaddr(const char *ifname, struct in_addr addr) 1171 { 1172 struct ifreq delreq; 1173 struct sockaddr_in *sa; 1174 1175 memset(&delreq, 0, sizeof(delreq)); 1176 strncpy(delreq.ifr_name, ifname, sizeof(delreq.ifr_name)); 1177 sa = (struct sockaddr_in *)(void *)&delreq.ifr_addr; 1178 sa->sin_family = AF_INET; 1179 sa->sin_len = sizeof(*sa); 1180 sa->sin_addr = addr; 1181 1182 return (ioctl(mib_netsock, SIOCDIFADDR, &delreq)); 1183 } 1184 1185 /* 1186 * Verify an interface address without fetching the entire list 1187 */ 1188 static int 1189 verify_ifa(const char *name, struct mibifa *ifa) 1190 { 1191 struct ifreq req; 1192 struct sockaddr_in *sa; 1193 1194 memset(&req, 0, sizeof(req)); 1195 strncpy(req.ifr_name, name, sizeof(req.ifr_name)); 1196 sa = (struct sockaddr_in *)(void *)&req.ifr_addr; 1197 sa->sin_family = AF_INET; 1198 sa->sin_len = sizeof(*sa); 1199 sa->sin_addr = ifa->inaddr; 1200 1201 if (ioctl(mib_netsock, SIOCGIFADDR, &req) == -1) 1202 return (-1); 1203 if (ifa->inaddr.s_addr != sa->sin_addr.s_addr) { 1204 syslog(LOG_ERR, "%s: address mismatch", __func__); 1205 return (-1); 1206 } 1207 1208 if (ioctl(mib_netsock, SIOCGIFNETMASK, &req) == -1) 1209 return (-1); 1210 if (ifa->inmask.s_addr != sa->sin_addr.s_addr) { 1211 syslog(LOG_ERR, "%s: netmask mismatch", __func__); 1212 return (-1); 1213 } 1214 return (0); 1215 } 1216 1217 /* 1218 * Restore a deleted interface address. Don't wait for the routing socket 1219 * to update us. 1220 */ 1221 void 1222 mib_undestroy_ifa(struct mibifa *ifa) 1223 { 1224 struct mibif *ifp; 1225 1226 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) 1227 /* keep it destroyed */ 1228 return; 1229 1230 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) 1231 /* keep it destroyed */ 1232 return; 1233 1234 ifa->flags &= ~MIBIFA_DESTROYED; 1235 } 1236 1237 /* 1238 * Destroy an interface address 1239 */ 1240 int 1241 mib_destroy_ifa(struct mibifa *ifa) 1242 { 1243 struct mibif *ifp; 1244 1245 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1246 /* ups. */ 1247 mib_iflist_bad = 1; 1248 return (-1); 1249 } 1250 if (siocdifaddr(ifp->name, ifa->inaddr)) { 1251 /* ups. */ 1252 syslog(LOG_ERR, "SIOCDIFADDR: %m"); 1253 mib_iflist_bad = 1; 1254 return (-1); 1255 } 1256 ifa->flags |= MIBIFA_DESTROYED; 1257 return (0); 1258 } 1259 1260 /* 1261 * Rollback the modification of an address. Don't bother to wait for 1262 * the routing socket. 1263 */ 1264 void 1265 mib_unmodify_ifa(struct mibifa *ifa) 1266 { 1267 struct mibif *ifp; 1268 1269 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1270 /* ups. */ 1271 mib_iflist_bad = 1; 1272 return; 1273 } 1274 1275 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1276 /* ups. */ 1277 mib_iflist_bad = 1; 1278 return; 1279 } 1280 } 1281 1282 /* 1283 * Modify an IFA. 1284 */ 1285 int 1286 mib_modify_ifa(struct mibifa *ifa) 1287 { 1288 struct mibif *ifp; 1289 1290 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1291 /* ups. */ 1292 mib_iflist_bad = 1; 1293 return (-1); 1294 } 1295 1296 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1297 /* ups. */ 1298 mib_iflist_bad = 1; 1299 return (-1); 1300 } 1301 1302 if (verify_ifa(ifp->name, ifa)) { 1303 /* ups. */ 1304 mib_iflist_bad = 1; 1305 return (-1); 1306 } 1307 1308 return (0); 1309 } 1310 1311 /* 1312 * Destroy a freshly created interface address. Don't bother to wait for 1313 * the routing socket. 1314 */ 1315 void 1316 mib_uncreate_ifa(struct mibifa *ifa) 1317 { 1318 struct mibif *ifp; 1319 1320 if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1321 /* ups. */ 1322 mib_iflist_bad = 1; 1323 return; 1324 } 1325 if (siocdifaddr(ifp->name, ifa->inaddr)) { 1326 /* ups. */ 1327 mib_iflist_bad = 1; 1328 return; 1329 } 1330 1331 destroy_ifa(ifa); 1332 } 1333 1334 /* 1335 * Create a new ifa and verify it 1336 */ 1337 struct mibifa * 1338 mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask, 1339 struct in_addr bcast) 1340 { 1341 struct mibif *ifp; 1342 struct mibifa *ifa; 1343 1344 if ((ifp = mib_find_if(ifindex)) == NULL) 1345 return (NULL); 1346 if ((ifa = alloc_ifa(ifindex, addr)) == NULL) 1347 return (NULL); 1348 ifa->inmask = mask; 1349 ifa->inbcast = bcast; 1350 1351 if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1352 syslog(LOG_ERR, "%s: %m", __func__); 1353 destroy_ifa(ifa); 1354 return (NULL); 1355 } 1356 if (verify_ifa(ifp->name, ifa)) { 1357 destroy_ifa(ifa); 1358 return (NULL); 1359 } 1360 return (ifa); 1361 } 1362 1363 /* 1364 * Get all cloning interfaces and make them dynamic. 1365 * Hah! Whe should probably do this on a periodic basis (XXX). 1366 */ 1367 static void 1368 get_cloners(void) 1369 { 1370 struct if_clonereq req; 1371 char *buf, *cp; 1372 int i; 1373 1374 memset(&req, 0, sizeof(req)); 1375 if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { 1376 syslog(LOG_ERR, "get cloners: %m"); 1377 return; 1378 } 1379 if ((buf = malloc(req.ifcr_total * IFNAMSIZ)) == NULL) { 1380 syslog(LOG_ERR, "%m"); 1381 return; 1382 } 1383 req.ifcr_count = req.ifcr_total; 1384 req.ifcr_buffer = buf; 1385 if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { 1386 syslog(LOG_ERR, "get cloners: %m"); 1387 free(buf); 1388 return; 1389 } 1390 for (cp = buf, i = 0; i < req.ifcr_total; i++, cp += IFNAMSIZ) 1391 mib_if_set_dyn(cp); 1392 free(buf); 1393 } 1394 1395 /* 1396 * Idle function 1397 */ 1398 static void 1399 mibII_idle(void) 1400 { 1401 struct mibifa *ifa; 1402 1403 if (mib_iflist_bad) { 1404 TAILQ_FOREACH(ifa, &mibifa_list, link) 1405 ifa->flags &= ~MIBIFA_DESTROYED; 1406 1407 /* assume, that all cloning interfaces are dynamic */ 1408 get_cloners(); 1409 1410 mib_refresh_iflist(); 1411 update_ifa_info(); 1412 mib_arp_update(); 1413 mib_iflist_bad = 0; 1414 } 1415 if (update_arp) 1416 mib_arp_update(); 1417 } 1418 1419 1420 /* 1421 * Start the module 1422 */ 1423 static void 1424 mibII_start(void) 1425 { 1426 if ((route_fd = fd_select(route, route_input, NULL, module)) == NULL) { 1427 syslog(LOG_ERR, "fd_select(route): %m"); 1428 return; 1429 } 1430 mib_refresh_iflist(); 1431 update_ifa_info(); 1432 mib_arp_update(); 1433 mib_iftable_last_change = 0; 1434 mib_ifstack_last_change = 0; 1435 1436 ifmib_reg = or_register(&oid_ifMIB, 1437 "The MIB module to describe generic objects for network interface" 1438 " sub-layers.", module); 1439 1440 ipmib_reg = or_register(&oid_ipMIB, 1441 "The MIB module for managing IP and ICMP implementations, but " 1442 "excluding their management of IP routes.", module); 1443 1444 tcpmib_reg = or_register(&oid_tcpMIB, 1445 "The MIB module for managing TCP implementations.", module); 1446 1447 udpmib_reg = or_register(&oid_udpMIB, 1448 "The MIB module for managing UDP implementations.", module); 1449 1450 ipForward_reg = or_register(&oid_ipForward, 1451 "The MIB module for the display of CIDR multipath IP Routes.", 1452 module); 1453 } 1454 1455 /* 1456 * Initialize the module 1457 */ 1458 static int 1459 mibII_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) 1460 { 1461 size_t len; 1462 1463 module = mod; 1464 1465 len = sizeof(clockinfo); 1466 if (sysctlbyname("kern.clockrate", &clockinfo, &len, NULL, 0) == -1) { 1467 syslog(LOG_ERR, "kern.clockrate: %m"); 1468 return (-1); 1469 } 1470 if (len != sizeof(clockinfo)) { 1471 syslog(LOG_ERR, "kern.clockrate: wrong size"); 1472 return (-1); 1473 } 1474 1475 if ((route = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) { 1476 syslog(LOG_ERR, "PF_ROUTE: %m"); 1477 return (-1); 1478 } 1479 (void)shutdown(route, SHUT_WR); 1480 1481 if ((mib_netsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 1482 syslog(LOG_ERR, "PF_INET: %m"); 1483 (void)close(route); 1484 return (-1); 1485 } 1486 (void)shutdown(mib_netsock, SHUT_RDWR); 1487 1488 /* assume, that all cloning interfaces are dynamic */ 1489 get_cloners(); 1490 1491 return (0); 1492 } 1493 1494 static int 1495 mibII_fini(void) 1496 { 1497 if (route_fd != NULL) 1498 fd_deselect(route_fd); 1499 if (route != -1) 1500 (void)close(route); 1501 if (mib_netsock != -1) 1502 (void)close(mib_netsock); 1503 /* XXX free memory */ 1504 1505 or_unregister(ipForward_reg); 1506 or_unregister(udpmib_reg); 1507 or_unregister(tcpmib_reg); 1508 or_unregister(ipmib_reg); 1509 or_unregister(ifmib_reg); 1510 1511 return (0); 1512 } 1513 1514 static void 1515 mibII_loading(const struct lmodule *mod, int loaded) 1516 { 1517 struct mibif *ifp; 1518 1519 if (loaded == 1) 1520 return; 1521 1522 TAILQ_FOREACH(ifp, &mibif_list, link) 1523 if (ifp->xnotify_mod == mod) { 1524 ifp->xnotify_mod = NULL; 1525 ifp->xnotify_data = NULL; 1526 ifp->xnotify = NULL; 1527 } 1528 1529 mib_unregister_newif(mod); 1530 } 1531 1532 const struct snmp_module config = { 1533 "This module implements the interface and ip groups.", 1534 mibII_init, 1535 mibII_fini, 1536 mibII_idle, /* idle */ 1537 NULL, /* dump */ 1538 NULL, /* config */ 1539 mibII_start, 1540 NULL, 1541 mibII_ctree, 1542 mibII_CTREE_SIZE, 1543 mibII_loading 1544 }; 1545 1546 /* 1547 * Should have a list of these attached to each interface. 1548 */ 1549 void * 1550 mibif_notify(struct mibif *ifp, const struct lmodule *mod, 1551 mibif_notify_f func, void *data) 1552 { 1553 ifp->xnotify = func; 1554 ifp->xnotify_data = data; 1555 ifp->xnotify_mod = mod; 1556 1557 return (ifp); 1558 } 1559 1560 void 1561 mibif_unnotify(void *arg) 1562 { 1563 struct mibif *ifp = arg; 1564 1565 ifp->xnotify = NULL; 1566 ifp->xnotify_data = NULL; 1567 ifp->xnotify_mod = NULL; 1568 } 1569