1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7310903Sngie * 8133211Sharti * Redistribution and use in source and binary forms, with or without 9133211Sharti * modification, are permitted provided that the following conditions 10133211Sharti * are met: 11133211Sharti * 1. Redistributions of source code must retain the above copyright 12133211Sharti * notice, this list of conditions and the following disclaimer. 13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 14122394Sharti * notice, this list of conditions and the following disclaimer in the 15122394Sharti * documentation and/or other materials provided with the distribution. 16310903Sngie * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28122394Sharti * 29163799Sharti * $Begemot: mibII.c 516 2006-10-27 15:54:02Z brandt_h $ 30122394Sharti * 31122394Sharti * Implementation of the standard interfaces and ip MIB. 32122394Sharti */ 33122394Sharti#include "mibII.h" 34122394Sharti#include "mibII_oid.h" 35163799Sharti#include <net/if.h> 36122394Sharti#include <net/if_types.h> 37122394Sharti 38122394Sharti 39122394Sharti/*****************************/ 40122394Sharti 41122394Sharti/* our module */ 42122394Shartistatic struct lmodule *module; 43122394Sharti 44122394Sharti/* routing socket */ 45122394Shartistatic int route; 46122394Shartistatic void *route_fd; 47122394Sharti 48122394Sharti/* if-index allocator */ 49133211Shartistatic uint32_t next_if_index = 1; 50122394Sharti 51186119Sqingli/* currently fetching the arp table */ 52122394Shartistatic int in_update_arp; 53122394Sharti 54122394Sharti/* OR registrations */ 55122394Shartistatic u_int ifmib_reg; 56122394Shartistatic u_int ipmib_reg; 57122394Shartistatic u_int tcpmib_reg; 58122394Shartistatic u_int udpmib_reg; 59122394Shartistatic u_int ipForward_reg; 60122394Sharti 61122394Sharti/*****************************/ 62122394Sharti 63122394Sharti/* list of all IP addresses */ 64122394Shartistruct mibifa_list mibifa_list = TAILQ_HEAD_INITIALIZER(mibifa_list); 65122394Sharti 66122394Sharti/* list of all interfaces */ 67122394Shartistruct mibif_list mibif_list = TAILQ_HEAD_INITIALIZER(mibif_list); 68122394Sharti 69122394Sharti/* list of dynamic interface names */ 70122394Shartistruct mibdynif_list mibdynif_list = SLIST_HEAD_INITIALIZER(mibdynif_list); 71122394Sharti 72122394Sharti/* list of all interface index mappings */ 73122394Shartistruct mibindexmap_list mibindexmap_list = STAILQ_HEAD_INITIALIZER(mibindexmap_list); 74122394Sharti 75122394Sharti/* list of all stacking entries */ 76122394Shartistruct mibifstack_list mibifstack_list = TAILQ_HEAD_INITIALIZER(mibifstack_list); 77122394Sharti 78122394Sharti/* list of all receive addresses */ 79122394Shartistruct mibrcvaddr_list mibrcvaddr_list = TAILQ_HEAD_INITIALIZER(mibrcvaddr_list); 80122394Sharti 81122394Sharti/* list of all NetToMedia entries */ 82122394Shartistruct mibarp_list mibarp_list = TAILQ_HEAD_INITIALIZER(mibarp_list); 83122394Sharti 84122394Sharti/* number of interfaces */ 85122394Shartiint32_t mib_if_number; 86122394Sharti 87122394Sharti/* last change of table */ 88146525Shartiuint64_t mib_iftable_last_change; 89122394Sharti 90122394Sharti/* last change of stack table */ 91146525Shartiuint64_t mib_ifstack_last_change; 92122394Sharti 93122394Sharti/* if this is set, one of our lists may be bad. refresh them when idle */ 94122394Shartiint mib_iflist_bad; 95122394Sharti 96122394Sharti/* network socket */ 97122394Shartiint mib_netsock; 98122394Sharti 99122394Sharti/* last time refreshed */ 100146525Shartiuint64_t mibarpticks; 101122394Sharti 102122394Sharti/* info on system clocks */ 103122394Shartistruct clockinfo clockinfo; 104122394Sharti 105122394Sharti/* list of all New if registrations */ 106122394Shartistatic struct newifreg_list newifreg_list = TAILQ_HEAD_INITIALIZER(newifreg_list); 107122394Sharti 108155602Sharti/* baud rate of fastest interface */ 109155602Shartiuint64_t mibif_maxspeed; 110155602Sharti 111155602Sharti/* user-forced update interval */ 112155602Shartiu_int mibif_force_hc_update_interval; 113155602Sharti 114155602Sharti/* current update interval */ 115155602Shartiu_int mibif_hc_update_interval; 116155602Sharti 117155602Sharti/* HC update timer handle */ 118155602Shartistatic void *hc_update_timer; 119155602Sharti 120200063Ssyrinx/* Idle poll timer */ 121200063Ssyrinxstatic void *mibII_poll_timer; 122200063Ssyrinx 123200063Ssyrinx/* interfaces' data poll interval */ 124200063Ssyrinxu_int mibII_poll_ticks; 125200063Ssyrinx 126200063Ssyrinx/* Idle poll hook */ 127200063Ssyrinxstatic void mibII_idle(void *arg __unused); 128200063Ssyrinx 129122394Sharti/*****************************/ 130122394Sharti 131122394Shartistatic const struct asn_oid oid_ifMIB = OIDX_ifMIB; 132122394Shartistatic const struct asn_oid oid_ipMIB = OIDX_ipMIB; 133122394Shartistatic const struct asn_oid oid_tcpMIB = OIDX_tcpMIB; 134122394Shartistatic const struct asn_oid oid_udpMIB = OIDX_udpMIB; 135122394Shartistatic const struct asn_oid oid_ipForward = OIDX_ipForward; 136122394Shartistatic const struct asn_oid oid_linkDown = OIDX_linkDown; 137122394Shartistatic const struct asn_oid oid_linkUp = OIDX_linkUp; 138122394Shartistatic const struct asn_oid oid_ifIndex = OIDX_ifIndex; 139122394Sharti 140122394Sharti/*****************************/ 141122394Sharti 142122394Sharti/* 143122394Sharti * Find an interface 144122394Sharti */ 145122394Shartistruct mibif * 146122394Shartimib_find_if(u_int idx) 147122394Sharti{ 148122394Sharti struct mibif *ifp; 149122394Sharti 150122394Sharti TAILQ_FOREACH(ifp, &mibif_list, link) 151122394Sharti if (ifp->index == idx) 152122394Sharti return (ifp); 153122394Sharti return (NULL); 154122394Sharti} 155122394Sharti 156122394Shartistruct mibif * 157122394Shartimib_find_if_sys(u_int sysindex) 158122394Sharti{ 159122394Sharti struct mibif *ifp; 160122394Sharti 161122394Sharti TAILQ_FOREACH(ifp, &mibif_list, link) 162122394Sharti if (ifp->sysindex == sysindex) 163122394Sharti return (ifp); 164122394Sharti return (NULL); 165122394Sharti} 166122394Sharti 167122394Shartistruct mibif * 168122394Shartimib_find_if_name(const char *name) 169122394Sharti{ 170122394Sharti struct mibif *ifp; 171122394Sharti 172122394Sharti TAILQ_FOREACH(ifp, &mibif_list, link) 173122394Sharti if (strcmp(ifp->name, name) == 0) 174122394Sharti return (ifp); 175122394Sharti return (NULL); 176122394Sharti} 177122394Sharti 178122394Sharti/* 179122394Sharti * Check whether an interface is dynamic. The argument may include the 180122394Sharti * unit number. This assumes, that the name part does NOT contain digits. 181122394Sharti */ 182122394Shartiint 183122394Shartimib_if_is_dyn(const char *name) 184122394Sharti{ 185122394Sharti size_t len; 186122394Sharti struct mibdynif *d; 187122394Sharti 188122394Sharti for (len = 0; name[len] != '\0' && isalpha(name[len]) ; len++) 189122394Sharti ; 190122394Sharti SLIST_FOREACH(d, &mibdynif_list, link) 191122394Sharti if (strlen(d->name) == len && strncmp(d->name, name, len) == 0) 192122394Sharti return (1); 193122394Sharti return (0); 194122394Sharti} 195122394Sharti 196122394Sharti/* set an interface name to dynamic mode */ 197122394Shartivoid 198122394Shartimib_if_set_dyn(const char *name) 199122394Sharti{ 200122394Sharti struct mibdynif *d; 201122394Sharti 202122394Sharti SLIST_FOREACH(d, &mibdynif_list, link) 203122394Sharti if (strcmp(name, d->name) == 0) 204122394Sharti return; 205122394Sharti if ((d = malloc(sizeof(*d))) == NULL) 206122394Sharti err(1, NULL); 207311598Sngie strlcpy(d->name, name, sizeof(d->name)); 208122394Sharti SLIST_INSERT_HEAD(&mibdynif_list, d, link); 209122394Sharti} 210122394Sharti 211122394Sharti/* 212122394Sharti * register for interface creations 213122394Sharti */ 214122394Shartiint 215122394Shartimib_register_newif(int (*func)(struct mibif *), const struct lmodule *mod) 216122394Sharti{ 217122394Sharti struct newifreg *reg; 218122394Sharti 219122394Sharti TAILQ_FOREACH(reg, &newifreg_list, link) 220122394Sharti if (reg->mod == mod) { 221122394Sharti reg->func = func; 222122394Sharti return (0); 223122394Sharti } 224122394Sharti if ((reg = malloc(sizeof(*reg))) == NULL) { 225122394Sharti syslog(LOG_ERR, "newifreg: %m"); 226122394Sharti return (-1); 227122394Sharti } 228122394Sharti reg->mod = mod; 229122394Sharti reg->func = func; 230122394Sharti TAILQ_INSERT_TAIL(&newifreg_list, reg, link); 231122394Sharti 232122394Sharti return (0); 233122394Sharti} 234122394Sharti 235122394Shartivoid 236122394Shartimib_unregister_newif(const struct lmodule *mod) 237122394Sharti{ 238122394Sharti struct newifreg *reg; 239122394Sharti 240122394Sharti TAILQ_FOREACH(reg, &newifreg_list, link) 241122394Sharti if (reg->mod == mod) { 242122394Sharti TAILQ_REMOVE(&newifreg_list, reg, link); 243122394Sharti free(reg); 244122394Sharti return; 245122394Sharti } 246122394Sharti 247122394Sharti} 248122394Sharti 249122394Shartistruct mibif * 250122394Shartimib_first_if(void) 251122394Sharti{ 252122394Sharti return (TAILQ_FIRST(&mibif_list)); 253122394Sharti} 254122394Shartistruct mibif * 255122394Shartimib_next_if(const struct mibif *ifp) 256122394Sharti{ 257122394Sharti return (TAILQ_NEXT(ifp, link)); 258122394Sharti} 259122394Sharti 260122394Sharti/* 261122394Sharti * Change the admin status of an interface 262122394Sharti */ 263122394Shartiint 264122394Shartimib_if_admin(struct mibif *ifp, int up) 265122394Sharti{ 266122394Sharti struct ifreq ifr; 267122394Sharti 268312089Sngie strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); 269122394Sharti if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) { 270122394Sharti syslog(LOG_ERR, "SIOCGIFFLAGS(%s): %m", ifp->name); 271122394Sharti return (-1); 272122394Sharti } 273122394Sharti if (up) 274122394Sharti ifr.ifr_flags |= IFF_UP; 275122394Sharti else 276122394Sharti ifr.ifr_flags &= ~IFF_UP; 277122394Sharti if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { 278122394Sharti syslog(LOG_ERR, "SIOCSIFFLAGS(%s): %m", ifp->name); 279122394Sharti return (-1); 280122394Sharti } 281122394Sharti 282122394Sharti (void)mib_fetch_ifmib(ifp); 283122394Sharti 284122394Sharti return (0); 285122394Sharti} 286122394Sharti 287122394Sharti/* 288122394Sharti * Generate a link up/down trap 289122394Sharti */ 290122394Shartistatic void 291122394Shartilink_trap(struct mibif *ifp, int up) 292122394Sharti{ 293122394Sharti struct snmp_value ifindex; 294122394Sharti 295122394Sharti ifindex.var = oid_ifIndex; 296122394Sharti ifindex.var.subs[ifindex.var.len++] = ifp->index; 297122394Sharti ifindex.syntax = SNMP_SYNTAX_INTEGER; 298122394Sharti ifindex.v.integer = ifp->index; 299122394Sharti 300133211Sharti snmp_send_trap(up ? &oid_linkUp : &oid_linkDown, &ifindex, 301133211Sharti (struct snmp_value *)NULL); 302122394Sharti} 303122394Sharti 304155602Sharti/** 305155602Sharti * Fetch the GENERIC IFMIB and update the HC counters 306122394Sharti */ 307155602Shartistatic int 308155602Shartifetch_generic_mib(struct mibif *ifp, const struct ifmibdata *old) 309122394Sharti{ 310122394Sharti int name[6]; 311122394Sharti size_t len; 312155602Sharti struct mibif_private *p = ifp->private; 313122394Sharti 314122394Sharti name[0] = CTL_NET; 315122394Sharti name[1] = PF_LINK; 316122394Sharti name[2] = NETLINK_GENERIC; 317122394Sharti name[3] = IFMIB_IFDATA; 318122394Sharti name[4] = ifp->sysindex; 319122394Sharti name[5] = IFDATA_GENERAL; 320122394Sharti 321122394Sharti len = sizeof(ifp->mib); 322312045Sngie if (sysctl(name, nitems(name), &ifp->mib, &len, NULL, 0) == -1) { 323122394Sharti if (errno != ENOENT) 324122394Sharti syslog(LOG_WARNING, "sysctl(ifmib, %s) failed %m", 325122394Sharti ifp->name); 326122394Sharti return (-1); 327122394Sharti } 328122394Sharti 329155506Sharti /* 330155602Sharti * Assume that one of the two following compounds is optimized away 331155602Sharti */ 332155602Sharti if (ULONG_MAX >= 0xffffffffffffffffULL) { 333155602Sharti p->hc_inoctets = ifp->mib.ifmd_data.ifi_ibytes; 334155602Sharti p->hc_outoctets = ifp->mib.ifmd_data.ifi_obytes; 335155602Sharti p->hc_omcasts = ifp->mib.ifmd_data.ifi_omcasts; 336155602Sharti p->hc_opackets = ifp->mib.ifmd_data.ifi_opackets; 337155602Sharti p->hc_imcasts = ifp->mib.ifmd_data.ifi_imcasts; 338155602Sharti p->hc_ipackets = ifp->mib.ifmd_data.ifi_ipackets; 339155602Sharti 340155602Sharti } else if (ULONG_MAX >= 0xffffffff) { 341155602Sharti 342155602Sharti#define UPDATE(HC, MIB) \ 343155602Sharti if (old->ifmd_data.MIB > ifp->mib.ifmd_data.MIB) \ 344155602Sharti p->HC += (0x100000000ULL + \ 345155602Sharti ifp->mib.ifmd_data.MIB) - \ 346155602Sharti old->ifmd_data.MIB; \ 347155602Sharti else \ 348155602Sharti p->HC += ifp->mib.ifmd_data.MIB - \ 349155602Sharti old->ifmd_data.MIB; 350155602Sharti 351155602Sharti UPDATE(hc_inoctets, ifi_ibytes) 352155602Sharti UPDATE(hc_outoctets, ifi_obytes) 353155602Sharti UPDATE(hc_omcasts, ifi_omcasts) 354155602Sharti UPDATE(hc_opackets, ifi_opackets) 355155602Sharti UPDATE(hc_imcasts, ifi_imcasts) 356155602Sharti UPDATE(hc_ipackets, ifi_ipackets) 357155602Sharti 358155602Sharti#undef UPDATE 359155602Sharti } else 360155602Sharti abort(); 361155602Sharti return (0); 362155602Sharti} 363155602Sharti 364155602Sharti/** 365155602Sharti * Update the 64-bit interface counters 366155602Sharti */ 367155602Shartistatic void 368155602Shartiupdate_hc_counters(void *arg __unused) 369155602Sharti{ 370155602Sharti struct mibif *ifp; 371155602Sharti struct ifmibdata oldmib; 372155602Sharti 373155602Sharti TAILQ_FOREACH(ifp, &mibif_list, link) { 374155602Sharti oldmib = ifp->mib; 375155602Sharti (void)fetch_generic_mib(ifp, &oldmib); 376155602Sharti } 377155602Sharti} 378155602Sharti 379155602Sharti/** 380155602Sharti * Recompute the poll timer for the HC counters 381155602Sharti */ 382155602Shartivoid 383155602Shartimibif_reset_hc_timer(void) 384155602Sharti{ 385155602Sharti u_int ticks; 386155602Sharti 387155602Sharti if ((ticks = mibif_force_hc_update_interval) == 0) { 388163799Sharti if (mibif_maxspeed <= IF_Mbps(10)) { 389155602Sharti /* at 10Mbps overflow needs 3436 seconds */ 390155602Sharti ticks = 3000 * 100; /* 50 minutes */ 391163799Sharti } else if (mibif_maxspeed <= IF_Mbps(100)) { 392155602Sharti /* at 100Mbps overflow needs 343 seconds */ 393155602Sharti ticks = 300 * 100; /* 5 minutes */ 394163799Sharti } else if (mibif_maxspeed < IF_Mbps(622)) { 395155602Sharti /* at 622Mbps overflow needs 53 seconds */ 396155602Sharti ticks = 40 * 100; /* 40 seconds */ 397163799Sharti } else if (mibif_maxspeed <= IF_Mbps(1000)) { 398155602Sharti /* at 1Gbps overflow needs 34 seconds */ 399155602Sharti ticks = 20 * 100; /* 20 seconds */ 400155602Sharti } else { 401155602Sharti /* at 10Gbps overflow needs 3.4 seconds */ 402155602Sharti ticks = 100; /* 1 seconds */ 403155602Sharti } 404155602Sharti } 405155602Sharti 406155602Sharti if (ticks == mibif_hc_update_interval) 407155602Sharti return; 408155602Sharti 409155602Sharti if (hc_update_timer != NULL) { 410155602Sharti timer_stop(hc_update_timer); 411155602Sharti hc_update_timer = NULL; 412155602Sharti } 413155602Sharti update_hc_counters(NULL); 414155602Sharti if ((hc_update_timer = timer_start_repeat(ticks * 10, ticks * 10, 415155602Sharti update_hc_counters, NULL, module)) == NULL) { 416155602Sharti syslog(LOG_ERR, "timer_start(%u): %m", ticks); 417155602Sharti return; 418155602Sharti } 419155602Sharti mibif_hc_update_interval = ticks; 420155602Sharti} 421155602Sharti 422200063Ssyrinx/** 423200063Ssyrinx * Restart the idle poll timer. 424200063Ssyrinx */ 425200063Ssyrinxvoid 426200063Ssyrinxmibif_restart_mibII_poll_timer(void) 427200063Ssyrinx{ 428200063Ssyrinx if (mibII_poll_timer != NULL) 429200063Ssyrinx timer_stop(mibII_poll_timer); 430200063Ssyrinx 431200063Ssyrinx if ((mibII_poll_timer = timer_start_repeat(mibII_poll_ticks * 10, 432200063Ssyrinx mibII_poll_ticks * 10, mibII_idle, NULL, module)) == NULL) 433200063Ssyrinx syslog(LOG_ERR, "timer_start(%u): %m", mibII_poll_ticks); 434200063Ssyrinx} 435200063Ssyrinx 436155602Sharti/* 437155602Sharti * Fetch new MIB data. 438155602Sharti */ 439155602Shartiint 440155602Shartimib_fetch_ifmib(struct mibif *ifp) 441155602Sharti{ 442338311Seugen static int kmib[2] = { -1, 0 }; /* for sysctl net.ifdescr_maxlen */ 443338311Seugen 444155602Sharti int name[6]; 445338311Seugen size_t kmiblen = nitems(kmib); 446155602Sharti size_t len; 447155602Sharti void *newmib; 448155602Sharti struct ifmibdata oldmib = ifp->mib; 449301663Sngie struct ifreq irr; 450338311Seugen unsigned int alias_maxlen = MIBIF_ALIAS_SIZE_MAX; 451155602Sharti 452155602Sharti if (fetch_generic_mib(ifp, &oldmib) == -1) 453155602Sharti return (-1); 454155602Sharti 455155602Sharti /* 456155506Sharti * Quoting RFC2863, 3.1.15: "... LinkUp and linkDown traps are 457155506Sharti * generated just after ifOperStatus leaves, or just before it 458155506Sharti * enters, the down state, respectively;" 459155506Sharti */ 460155506Sharti if (ifp->trap_enable && ifp->mib.ifmd_data.ifi_link_state != 461155506Sharti oldmib.ifmd_data.ifi_link_state && 462155506Sharti (ifp->mib.ifmd_data.ifi_link_state == LINK_STATE_DOWN || 463155506Sharti oldmib.ifmd_data.ifi_link_state == LINK_STATE_DOWN)) 464155506Sharti link_trap(ifp, ifp->mib.ifmd_data.ifi_link_state == 465155506Sharti LINK_STATE_UP ? 1 : 0); 466122394Sharti 467122394Sharti ifp->flags &= ~(MIBIF_HIGHSPEED | MIBIF_VERYHIGHSPEED); 468122394Sharti if (ifp->mib.ifmd_data.ifi_baudrate > 20000000) { 469122394Sharti ifp->flags |= MIBIF_HIGHSPEED; 470122394Sharti if (ifp->mib.ifmd_data.ifi_baudrate > 650000000) 471122394Sharti ifp->flags |= MIBIF_VERYHIGHSPEED; 472122394Sharti } 473155602Sharti if (ifp->mib.ifmd_data.ifi_baudrate > mibif_maxspeed) { 474155602Sharti mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate; 475155602Sharti mibif_reset_hc_timer(); 476155602Sharti } 477122394Sharti 478122394Sharti /* 479122394Sharti * linkspecific MIB 480122394Sharti */ 481155602Sharti name[0] = CTL_NET; 482155602Sharti name[1] = PF_LINK; 483155602Sharti name[2] = NETLINK_GENERIC; 484155602Sharti name[3] = IFMIB_IFDATA; 485155602Sharti name[4] = ifp->sysindex; 486122394Sharti name[5] = IFDATA_LINKSPECIFIC; 487312045Sngie if (sysctl(name, nitems(name), NULL, &len, NULL, 0) == -1) { 488122394Sharti syslog(LOG_WARNING, "sysctl linkmib estimate (%s): %m", 489122394Sharti ifp->name); 490122394Sharti if (ifp->specmib != NULL) { 491122394Sharti ifp->specmib = NULL; 492122394Sharti ifp->specmiblen = 0; 493122394Sharti } 494122394Sharti goto out; 495122394Sharti } 496122394Sharti if (len == 0) { 497122394Sharti if (ifp->specmib != NULL) { 498122394Sharti ifp->specmib = NULL; 499122394Sharti ifp->specmiblen = 0; 500122394Sharti } 501122394Sharti goto out; 502122394Sharti } 503122394Sharti 504122394Sharti if (ifp->specmiblen != len) { 505122394Sharti if ((newmib = realloc(ifp->specmib, len)) == NULL) { 506122394Sharti ifp->specmib = NULL; 507122394Sharti ifp->specmiblen = 0; 508122394Sharti goto out; 509122394Sharti } 510122394Sharti ifp->specmib = newmib; 511122394Sharti ifp->specmiblen = len; 512122394Sharti } 513312045Sngie if (sysctl(name, nitems(name), ifp->specmib, &len, NULL, 0) == -1) { 514122394Sharti syslog(LOG_WARNING, "sysctl linkmib (%s): %m", ifp->name); 515122394Sharti if (ifp->specmib != NULL) { 516122394Sharti ifp->specmib = NULL; 517122394Sharti ifp->specmiblen = 0; 518122394Sharti } 519122394Sharti } 520122394Sharti 521122394Sharti out: 522338311Seugen 523338311Seugen /* 524338311Seugen * Find sysctl mib for net.ifdescr_maxlen (one time). 525338311Seugen * kmib[0] == -1 at first call to mib_fetch_ifmib(). 526338311Seugen * Then kmib[0] > 0 if we found sysctl mib for net.ifdescr_maxlen. 527338311Seugen * Else, kmib[0] == 0 (unexpected error from a kernel). 528338311Seugen */ 529338311Seugen if (kmib[0] < 0 && 530338311Seugen sysctlnametomib("net.ifdescr_maxlen", kmib, &kmiblen) < 0) { 531338311Seugen kmib[0] = 0; 532338311Seugen syslog(LOG_WARNING, "sysctlnametomib net.ifdescr_maxlen: %m"); 533338311Seugen } 534338311Seugen 535338311Seugen /* 536338311Seugen * Fetch net.ifdescr_maxlen value every time to catch up with changes. 537338311Seugen */ 538338311Seugen len = sizeof(alias_maxlen); 539338311Seugen if (kmib[0] > 0 && sysctl(kmib, 2, &alias_maxlen, &len, NULL, 0) < 0) { 540338311Seugen /* unexpected error from the kernel, use default value */ 541338311Seugen alias_maxlen = MIBIF_ALIAS_SIZE_MAX; 542338311Seugen syslog(LOG_WARNING, "sysctl net.ifdescr_maxlen: %m"); 543338311Seugen } 544338311Seugen 545338311Seugen /* 546338311Seugen * Kernel limit might be decreased after interfaces got 547338311Seugen * their descriptions assigned. Try to obtain them anyway. 548338311Seugen */ 549338311Seugen if (alias_maxlen == 0) 550338311Seugen alias_maxlen = MIBIF_ALIAS_SIZE_MAX; 551338311Seugen 552338311Seugen /* 553338311Seugen * Allocate maximum memory for a buffer and later reallocate 554338311Seugen * to free extra memory. 555338311Seugen */ 556338311Seugen if ((ifp->alias = malloc(alias_maxlen)) == NULL) { 557338311Seugen syslog(LOG_WARNING, "malloc(%d) failed: %m", (int)alias_maxlen); 558338311Seugen goto fin; 559338311Seugen } 560338311Seugen 561312089Sngie strlcpy(irr.ifr_name, ifp->name, sizeof(irr.ifr_name)); 562338311Seugen irr.ifr_buffer.buffer = ifp->alias; 563338311Seugen irr.ifr_buffer.length = alias_maxlen; 564301663Sngie if (ioctl(mib_netsock, SIOCGIFDESCR, &irr) == -1) { 565338311Seugen free(ifp->alias); 566338311Seugen ifp->alias = NULL; 567301663Sngie if (errno != ENOMSG) 568301663Sngie syslog(LOG_WARNING, "SIOCGIFDESCR (%s): %m", ifp->name); 569301663Sngie } else if (irr.ifr_buffer.buffer == NULL) { 570338311Seugen free(ifp->alias); 571338311Seugen ifp->alias = NULL; 572301663Sngie syslog(LOG_WARNING, "SIOCGIFDESCR (%s): too long (%zu)", 573301663Sngie ifp->name, irr.ifr_buffer.length); 574338311Seugen } else { 575338311Seugen ifp->alias_size = strnlen(ifp->alias, alias_maxlen) + 1; 576338311Seugen 577338311Seugen if (ifp->alias_size > MIBIF_ALIAS_SIZE) 578338311Seugen ifp->alias_size = MIBIF_ALIAS_SIZE; 579338311Seugen 580338311Seugen if (ifp->alias_size < alias_maxlen) 581338311Seugen ifp->alias = realloc(ifp->alias, ifp->alias_size); 582301663Sngie } 583338311Seugen 584338311Seugenfin: 585122394Sharti ifp->mibtick = get_ticks(); 586122394Sharti return (0); 587122394Sharti} 588122394Sharti 589122394Sharti/* find first/next address for a given interface */ 590122394Shartistruct mibifa * 591122394Shartimib_first_ififa(const struct mibif *ifp) 592122394Sharti{ 593122394Sharti struct mibifa *ifa; 594122394Sharti 595122394Sharti TAILQ_FOREACH(ifa, &mibifa_list, link) 596122394Sharti if (ifp->index == ifa->ifindex) 597122394Sharti return (ifa); 598122394Sharti return (NULL); 599122394Sharti} 600122394Sharti 601122394Shartistruct mibifa * 602122394Shartimib_next_ififa(struct mibifa *ifa0) 603122394Sharti{ 604122394Sharti struct mibifa *ifa; 605122394Sharti 606122394Sharti ifa = ifa0; 607122394Sharti while ((ifa = TAILQ_NEXT(ifa, link)) != NULL) 608122394Sharti if (ifa->ifindex == ifa0->ifindex) 609122394Sharti return (ifa); 610122394Sharti return (NULL); 611122394Sharti} 612122394Sharti 613122394Sharti/* 614122394Sharti * Allocate a new IFA 615122394Sharti */ 616122394Shartistatic struct mibifa * 617122394Shartialloc_ifa(u_int ifindex, struct in_addr addr) 618122394Sharti{ 619122394Sharti struct mibifa *ifa; 620133211Sharti uint32_t ha; 621122394Sharti 622122394Sharti if ((ifa = malloc(sizeof(struct mibifa))) == NULL) { 623122394Sharti syslog(LOG_ERR, "ifa: %m"); 624122394Sharti return (NULL); 625122394Sharti } 626122394Sharti ifa->inaddr = addr; 627122394Sharti ifa->ifindex = ifindex; 628122394Sharti 629122394Sharti ha = ntohl(ifa->inaddr.s_addr); 630122394Sharti ifa->index.len = 4; 631122394Sharti ifa->index.subs[0] = (ha >> 24) & 0xff; 632122394Sharti ifa->index.subs[1] = (ha >> 16) & 0xff; 633122394Sharti ifa->index.subs[2] = (ha >> 8) & 0xff; 634122394Sharti ifa->index.subs[3] = (ha >> 0) & 0xff; 635122394Sharti 636122394Sharti ifa->flags = 0; 637122394Sharti ifa->inbcast.s_addr = 0; 638122394Sharti ifa->inmask.s_addr = 0xffffffff; 639122394Sharti 640122394Sharti INSERT_OBJECT_OID(ifa, &mibifa_list); 641122394Sharti 642122394Sharti return (ifa); 643122394Sharti} 644122394Sharti 645122394Sharti/* 646122394Sharti * Delete an interface address 647122394Sharti */ 648122394Shartistatic void 649122394Shartidestroy_ifa(struct mibifa *ifa) 650122394Sharti{ 651122394Sharti TAILQ_REMOVE(&mibifa_list, ifa, link); 652122394Sharti free(ifa); 653122394Sharti} 654122394Sharti 655122394Sharti 656122394Sharti/* 657122394Sharti * Helper routine to extract the sockaddr structures from a routing 658122394Sharti * socket message. 659122394Sharti */ 660122394Shartivoid 661122394Shartimib_extract_addrs(int addrs, u_char *info, struct sockaddr **out) 662122394Sharti{ 663122394Sharti u_int i; 664122394Sharti 665122394Sharti for (i = 0; i < RTAX_MAX; i++) { 666122394Sharti if ((addrs & (1 << i)) != 0) { 667146609Sharti *out = (struct sockaddr *)(void *)info; 668122394Sharti info += roundup((*out)->sa_len, sizeof(long)); 669122394Sharti } else 670122394Sharti *out = NULL; 671122394Sharti out++; 672122394Sharti } 673122394Sharti} 674122394Sharti 675122394Sharti/* 676122394Sharti * save the phys address of an interface. Handle receive address entries here. 677122394Sharti */ 678122394Shartistatic void 679122394Shartiget_physaddr(struct mibif *ifp, struct sockaddr_dl *sdl, u_char *ptr) 680122394Sharti{ 681122394Sharti u_char *np; 682122394Sharti struct mibrcvaddr *rcv; 683122394Sharti 684122394Sharti if (sdl->sdl_alen == 0) { 685122394Sharti /* no address */ 686128237Sharti if (ifp->physaddrlen != 0) { 687122394Sharti if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, 688122394Sharti ifp->physaddrlen)) != NULL) 689122394Sharti mib_rcvaddr_delete(rcv); 690122394Sharti free(ifp->physaddr); 691122394Sharti ifp->physaddr = NULL; 692122394Sharti ifp->physaddrlen = 0; 693122394Sharti } 694122394Sharti return; 695122394Sharti } 696122394Sharti 697122394Sharti if (ifp->physaddrlen != sdl->sdl_alen) { 698122394Sharti /* length changed */ 699122394Sharti if (ifp->physaddrlen) { 700122394Sharti /* delete olf receive address */ 701122394Sharti if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, 702122394Sharti ifp->physaddrlen)) != NULL) 703122394Sharti mib_rcvaddr_delete(rcv); 704122394Sharti } 705122394Sharti if ((np = realloc(ifp->physaddr, sdl->sdl_alen)) == NULL) { 706122394Sharti free(ifp->physaddr); 707122394Sharti ifp->physaddr = NULL; 708122394Sharti ifp->physaddrlen = 0; 709122394Sharti return; 710122394Sharti } 711122394Sharti ifp->physaddr = np; 712122394Sharti ifp->physaddrlen = sdl->sdl_alen; 713122394Sharti 714122394Sharti } else if (memcmp(ifp->physaddr, ptr, ifp->physaddrlen) == 0) { 715122394Sharti /* no change */ 716122394Sharti return; 717122394Sharti 718122394Sharti } else { 719122394Sharti /* address changed */ 720122394Sharti 721122394Sharti /* delete olf receive address */ 722122394Sharti if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, 723122394Sharti ifp->physaddrlen)) != NULL) 724122394Sharti mib_rcvaddr_delete(rcv); 725122394Sharti } 726122394Sharti 727122394Sharti memcpy(ifp->physaddr, ptr, ifp->physaddrlen); 728122394Sharti 729122394Sharti /* make new receive address */ 730122394Sharti if ((rcv = mib_rcvaddr_create(ifp, ifp->physaddr, ifp->physaddrlen)) != NULL) 731122394Sharti rcv->flags |= MIBRCVADDR_HW; 732122394Sharti} 733122394Sharti 734122394Sharti/* 735122394Sharti * Free an interface 736122394Sharti */ 737122394Shartistatic void 738122394Shartimibif_free(struct mibif *ifp) 739122394Sharti{ 740155602Sharti struct mibif *ifp1; 741122394Sharti struct mibindexmap *map; 742122394Sharti struct mibifa *ifa, *ifa1; 743122394Sharti struct mibrcvaddr *rcv, *rcv1; 744122394Sharti struct mibarp *at, *at1; 745122394Sharti 746122394Sharti if (ifp->xnotify != NULL) 747122394Sharti (*ifp->xnotify)(ifp, MIBIF_NOTIFY_DESTROY, ifp->xnotify_data); 748122394Sharti 749122394Sharti (void)mib_ifstack_delete(ifp, NULL); 750122394Sharti (void)mib_ifstack_delete(NULL, ifp); 751122394Sharti 752122394Sharti TAILQ_REMOVE(&mibif_list, ifp, link); 753155602Sharti 754155602Sharti /* if this was the fastest interface - recompute this */ 755155602Sharti if (ifp->mib.ifmd_data.ifi_baudrate == mibif_maxspeed) { 756155602Sharti mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate; 757155602Sharti TAILQ_FOREACH(ifp1, &mibif_list, link) 758155602Sharti if (ifp1->mib.ifmd_data.ifi_baudrate > mibif_maxspeed) 759155602Sharti mibif_maxspeed = 760155602Sharti ifp1->mib.ifmd_data.ifi_baudrate; 761155602Sharti mibif_reset_hc_timer(); 762155602Sharti } 763155602Sharti 764338311Seugen if (ifp->alias != NULL) { 765338311Seugen free(ifp->alias); 766338311Seugen ifp->alias = NULL; 767338311Seugen } 768155602Sharti free(ifp->private); 769311468Sngie ifp->private = NULL; 770311468Sngie free(ifp->physaddr); 771311468Sngie ifp->physaddr = NULL; 772311468Sngie free(ifp->specmib); 773311468Sngie ifp->specmib = NULL; 774122394Sharti 775122394Sharti STAILQ_FOREACH(map, &mibindexmap_list, link) 776122394Sharti if (map->mibif == ifp) { 777122394Sharti map->mibif = NULL; 778122394Sharti break; 779122394Sharti } 780122394Sharti 781122394Sharti /* purge interface addresses */ 782122394Sharti ifa = TAILQ_FIRST(&mibifa_list); 783122394Sharti while (ifa != NULL) { 784122394Sharti ifa1 = TAILQ_NEXT(ifa, link); 785122394Sharti if (ifa->ifindex == ifp->index) 786122394Sharti destroy_ifa(ifa); 787122394Sharti ifa = ifa1; 788122394Sharti } 789122394Sharti 790122394Sharti /* purge receive addresses */ 791122394Sharti rcv = TAILQ_FIRST(&mibrcvaddr_list); 792122394Sharti while (rcv != NULL) { 793122394Sharti rcv1 = TAILQ_NEXT(rcv, link); 794122394Sharti if (rcv->ifindex == ifp->index) 795122394Sharti mib_rcvaddr_delete(rcv); 796122394Sharti rcv = rcv1; 797122394Sharti } 798122394Sharti 799122394Sharti /* purge ARP entries */ 800122394Sharti at = TAILQ_FIRST(&mibarp_list); 801122394Sharti while (at != NULL) { 802122394Sharti at1 = TAILQ_NEXT(at, link); 803122394Sharti if (at->index.subs[0] == ifp->index) 804122394Sharti mib_arp_delete(at); 805122394Sharti at = at1; 806122394Sharti } 807122394Sharti 808122394Sharti free(ifp); 809311468Sngie ifp = NULL; 810122394Sharti mib_if_number--; 811122394Sharti mib_iftable_last_change = this_tick; 812122394Sharti} 813122394Sharti 814122394Sharti/* 815122394Sharti * Create a new interface 816122394Sharti */ 817122394Shartistatic struct mibif * 818122394Shartimibif_create(u_int sysindex, const char *name) 819122394Sharti{ 820122394Sharti struct mibif *ifp; 821122394Sharti struct mibindexmap *map; 822122394Sharti 823122394Sharti if ((ifp = malloc(sizeof(*ifp))) == NULL) { 824122394Sharti syslog(LOG_WARNING, "%s: %m", __func__); 825122394Sharti return (NULL); 826122394Sharti } 827122394Sharti memset(ifp, 0, sizeof(*ifp)); 828155602Sharti if ((ifp->private = malloc(sizeof(struct mibif_private))) == NULL) { 829155602Sharti syslog(LOG_WARNING, "%s: %m", __func__); 830155602Sharti free(ifp); 831155602Sharti return (NULL); 832155602Sharti } 833155602Sharti memset(ifp->private, 0, sizeof(struct mibif_private)); 834155602Sharti 835122394Sharti ifp->sysindex = sysindex; 836311598Sngie strlcpy(ifp->name, name, sizeof(ifp->name)); 837311598Sngie strlcpy(ifp->descr, name, sizeof(ifp->descr)); 838142810Sharti ifp->spec_oid = oid_zeroDotZero; 839122394Sharti 840122394Sharti map = NULL; 841122394Sharti if (!mib_if_is_dyn(ifp->name)) { 842122394Sharti /* non-dynamic. look whether we know the interface */ 843122394Sharti STAILQ_FOREACH(map, &mibindexmap_list, link) 844122394Sharti if (strcmp(map->name, ifp->name) == 0) { 845122394Sharti ifp->index = map->ifindex; 846122394Sharti map->mibif = ifp; 847122394Sharti break; 848122394Sharti } 849122394Sharti /* assume it has a connector if it is not dynamic */ 850122394Sharti ifp->has_connector = 1; 851122394Sharti ifp->trap_enable = 1; 852122394Sharti } 853122394Sharti if (map == NULL) { 854122394Sharti /* new interface - get new index */ 855122394Sharti if (next_if_index > 0x7fffffff) 856122394Sharti errx(1, "ifindex wrap"); 857122394Sharti 858122394Sharti if ((map = malloc(sizeof(*map))) == NULL) { 859122394Sharti syslog(LOG_ERR, "ifmap: %m"); 860122394Sharti free(ifp); 861122394Sharti return (NULL); 862122394Sharti } 863122394Sharti map->ifindex = next_if_index++; 864122394Sharti map->sysindex = ifp->sysindex; 865122394Sharti strcpy(map->name, ifp->name); 866122394Sharti map->mibif = ifp; 867122394Sharti STAILQ_INSERT_TAIL(&mibindexmap_list, map, link); 868122394Sharti } else { 869122394Sharti /* re-instantiate. Introduce a counter discontinuity */ 870122394Sharti ifp->counter_disc = get_ticks(); 871122394Sharti } 872122394Sharti ifp->index = map->ifindex; 873155506Sharti ifp->mib.ifmd_data.ifi_link_state = LINK_STATE_UNKNOWN; 874122394Sharti 875122394Sharti INSERT_OBJECT_INT(ifp, &mibif_list); 876122394Sharti mib_if_number++; 877122394Sharti mib_iftable_last_change = this_tick; 878122394Sharti 879122394Sharti /* instantiate default ifStack entries */ 880122394Sharti (void)mib_ifstack_create(ifp, NULL); 881122394Sharti (void)mib_ifstack_create(NULL, ifp); 882122394Sharti 883122394Sharti return (ifp); 884122394Sharti} 885122394Sharti 886122394Sharti/* 887122394Sharti * Inform all interested parties about a new interface 888122394Sharti */ 889122394Shartistatic void 890122394Shartinotify_newif(struct mibif *ifp) 891122394Sharti{ 892122394Sharti struct newifreg *reg; 893122394Sharti 894122394Sharti TAILQ_FOREACH(reg, &newifreg_list, link) 895122394Sharti if ((*reg->func)(ifp)) 896122394Sharti return; 897122394Sharti} 898122394Sharti 899122394Sharti/* 900122394Sharti * This is called for new interfaces after we have fetched the interface 901122394Sharti * MIB. If this is a broadcast interface try to guess the broadcast address 902122394Sharti * depending on the interface type. 903122394Sharti */ 904122394Shartistatic void 905122394Sharticheck_llbcast(struct mibif *ifp) 906122394Sharti{ 907122394Sharti static u_char ether_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 908122394Sharti static u_char arcnet_bcast = 0; 909122394Sharti struct mibrcvaddr *rcv; 910122394Sharti 911122394Sharti if (!(ifp->mib.ifmd_flags & IFF_BROADCAST)) 912122394Sharti return; 913122394Sharti 914122394Sharti switch (ifp->mib.ifmd_data.ifi_type) { 915122394Sharti 916122394Sharti case IFT_ETHER: 917122394Sharti case IFT_FDDI: 918122394Sharti case IFT_ISO88025: 919210946Syongari case IFT_L2VLAN: 920122394Sharti if (mib_find_rcvaddr(ifp->index, ether_bcast, 6) == NULL && 921122394Sharti (rcv = mib_rcvaddr_create(ifp, ether_bcast, 6)) != NULL) 922122394Sharti rcv->flags |= MIBRCVADDR_BCAST; 923122394Sharti break; 924122394Sharti 925122394Sharti case IFT_ARCNET: 926122394Sharti if (mib_find_rcvaddr(ifp->index, &arcnet_bcast, 1) == NULL && 927122394Sharti (rcv = mib_rcvaddr_create(ifp, &arcnet_bcast, 1)) != NULL) 928122394Sharti rcv->flags |= MIBRCVADDR_BCAST; 929122394Sharti break; 930122394Sharti } 931122394Sharti} 932122394Sharti 933122394Sharti 934122394Sharti/* 935122394Sharti * Retrieve the current interface list from the system. 936122394Sharti */ 937122394Shartivoid 938122394Shartimib_refresh_iflist(void) 939122394Sharti{ 940122394Sharti struct mibif *ifp, *ifp1; 941122394Sharti size_t len; 942122394Sharti u_short idx; 943122394Sharti int name[6]; 944122394Sharti int count; 945122394Sharti struct ifmibdata mib; 946122394Sharti 947122394Sharti TAILQ_FOREACH(ifp, &mibif_list, link) 948122394Sharti ifp->flags &= ~MIBIF_FOUND; 949122394Sharti 950122394Sharti len = sizeof(count); 951122394Sharti if (sysctlbyname("net.link.generic.system.ifcount", &count, &len, 952122394Sharti NULL, 0) == -1) { 953122394Sharti syslog(LOG_ERR, "ifcount: %m"); 954122394Sharti return; 955122394Sharti } 956122394Sharti name[0] = CTL_NET; 957122394Sharti name[1] = PF_LINK; 958122394Sharti name[2] = NETLINK_GENERIC; 959122394Sharti name[3] = IFMIB_IFDATA; 960122394Sharti name[5] = IFDATA_GENERAL; 961122394Sharti for (idx = 1; idx <= count; idx++) { 962122394Sharti name[4] = idx; 963122394Sharti len = sizeof(mib); 964312045Sngie if (sysctl(name, nitems(name), &mib, &len, NULL, 0) == -1) { 965122394Sharti if (errno == ENOENT) 966122394Sharti continue; 967122394Sharti syslog(LOG_ERR, "ifmib(%u): %m", idx); 968122394Sharti return; 969122394Sharti } 970122394Sharti if ((ifp = mib_find_if_sys(idx)) != NULL) { 971122394Sharti ifp->flags |= MIBIF_FOUND; 972122394Sharti continue; 973122394Sharti } 974122394Sharti /* Unknown interface - create */ 975122394Sharti if ((ifp = mibif_create(idx, mib.ifmd_name)) != NULL) { 976122394Sharti ifp->flags |= MIBIF_FOUND; 977122394Sharti (void)mib_fetch_ifmib(ifp); 978122394Sharti check_llbcast(ifp); 979122394Sharti notify_newif(ifp); 980122394Sharti } 981122394Sharti } 982122394Sharti 983122394Sharti /* 984122394Sharti * Purge interfaces that disappeared 985122394Sharti */ 986122394Sharti ifp = TAILQ_FIRST(&mibif_list); 987122394Sharti while (ifp != NULL) { 988122394Sharti ifp1 = TAILQ_NEXT(ifp, link); 989122394Sharti if (!(ifp->flags & MIBIF_FOUND)) 990122394Sharti mibif_free(ifp); 991122394Sharti ifp = ifp1; 992122394Sharti } 993122394Sharti} 994122394Sharti 995122394Sharti/* 996122394Sharti * Find an interface address 997122394Sharti */ 998122394Shartistruct mibifa * 999122394Shartimib_find_ifa(struct in_addr addr) 1000122394Sharti{ 1001122394Sharti struct mibifa *ifa; 1002122394Sharti 1003122394Sharti TAILQ_FOREACH(ifa, &mibifa_list, link) 1004122394Sharti if (ifa->inaddr.s_addr == addr.s_addr) 1005122394Sharti return (ifa); 1006122394Sharti return (NULL); 1007122394Sharti} 1008122394Sharti 1009122394Sharti/* 1010249896Sglebius * Process a new ARP entry 1011249896Sglebius */ 1012249896Sglebiusstatic void 1013249896Sglebiusprocess_arp(const struct rt_msghdr *rtm, const struct sockaddr_dl *sdl, 1014249896Sglebius const struct sockaddr_in *sa) 1015249896Sglebius{ 1016249896Sglebius struct mibif *ifp; 1017249896Sglebius struct mibarp *at; 1018249896Sglebius 1019249896Sglebius /* IP arp table entry */ 1020249896Sglebius if (sdl->sdl_alen == 0) 1021249896Sglebius return; 1022249896Sglebius if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) 1023249896Sglebius return; 1024249896Sglebius /* have a valid entry */ 1025249896Sglebius if ((at = mib_find_arp(ifp, sa->sin_addr)) == NULL && 1026249896Sglebius (at = mib_arp_create(ifp, sa->sin_addr, 1027249896Sglebius sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) 1028249896Sglebius return; 1029249896Sglebius 1030249896Sglebius if (rtm->rtm_rmx.rmx_expire == 0) 1031249896Sglebius at->flags |= MIBARP_PERM; 1032249896Sglebius else 1033249896Sglebius at->flags &= ~MIBARP_PERM; 1034249896Sglebius at->flags |= MIBARP_FOUND; 1035249896Sglebius} 1036249896Sglebius 1037249896Sglebius/* 1038122394Sharti * Handle a routing socket message. 1039122394Sharti */ 1040122394Shartistatic void 1041122394Shartihandle_rtmsg(struct rt_msghdr *rtm) 1042122394Sharti{ 1043122394Sharti struct sockaddr *addrs[RTAX_MAX]; 1044122394Sharti struct if_msghdr *ifm; 1045295386Sbz struct ifa_msghdr ifam, *ifamp; 1046122394Sharti struct ifma_msghdr *ifmam; 1047122394Sharti#ifdef RTM_IFANNOUNCE 1048122394Sharti struct if_announcemsghdr *ifan; 1049122394Sharti#endif 1050122394Sharti struct mibif *ifp; 1051122394Sharti struct sockaddr_dl *sdl; 1052122394Sharti struct sockaddr_in *sa; 1053122394Sharti struct mibifa *ifa; 1054122394Sharti struct mibrcvaddr *rcv; 1055122394Sharti u_char *ptr; 1056122394Sharti 1057122394Sharti if (rtm->rtm_version != RTM_VERSION) { 1058122394Sharti syslog(LOG_ERR, "Bogus RTM version %u", rtm->rtm_version); 1059122394Sharti return; 1060122394Sharti } 1061122394Sharti 1062122394Sharti switch (rtm->rtm_type) { 1063122394Sharti 1064122394Sharti case RTM_NEWADDR: 1065295386Sbz ifamp = (struct ifa_msghdr *)rtm; 1066295386Sbz memcpy(&ifam, ifamp, sizeof(ifam)); 1067295386Sbz mib_extract_addrs(ifam.ifam_addrs, (u_char *)(ifamp + 1), addrs); 1068122394Sharti if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL) 1069122394Sharti break; 1070122394Sharti 1071122394Sharti sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; 1072122394Sharti if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) { 1073122394Sharti /* unknown address */ 1074228623Sbz if ((ifp = mib_find_if_sys(ifam.ifam_index)) == NULL) { 1075122394Sharti syslog(LOG_WARNING, "RTM_NEWADDR for unknown " 1076228623Sbz "interface %u", ifam.ifam_index); 1077122394Sharti break; 1078122394Sharti } 1079122394Sharti if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL) 1080122394Sharti break; 1081122394Sharti } 1082122394Sharti sa = (struct sockaddr_in *)(void *)addrs[RTAX_NETMASK]; 1083122394Sharti ifa->inmask = sa->sin_addr; 1084122394Sharti 1085122394Sharti if (addrs[RTAX_BRD] != NULL) { 1086122394Sharti sa = (struct sockaddr_in *)(void *)addrs[RTAX_BRD]; 1087122394Sharti ifa->inbcast = sa->sin_addr; 1088122394Sharti } 1089122394Sharti ifa->flags |= MIBIFA_FOUND; 1090122394Sharti break; 1091122394Sharti 1092122394Sharti case RTM_DELADDR: 1093295386Sbz ifamp = (struct ifa_msghdr *)rtm; 1094295386Sbz memcpy(&ifam, ifamp, sizeof(ifam)); 1095295386Sbz mib_extract_addrs(ifam.ifam_addrs, (u_char *)(ifamp + 1), addrs); 1096122394Sharti if (addrs[RTAX_IFA] == NULL) 1097122394Sharti break; 1098122394Sharti 1099122394Sharti sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; 1100122394Sharti if ((ifa = mib_find_ifa(sa->sin_addr)) != NULL) { 1101122394Sharti ifa->flags |= MIBIFA_FOUND; 1102122394Sharti if (!(ifa->flags & MIBIFA_DESTROYED)) 1103122394Sharti destroy_ifa(ifa); 1104122394Sharti } 1105122394Sharti break; 1106122394Sharti 1107122394Sharti case RTM_NEWMADDR: 1108122394Sharti ifmam = (struct ifma_msghdr *)rtm; 1109122394Sharti mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); 1110122394Sharti if (addrs[RTAX_IFA] == NULL || 1111122394Sharti addrs[RTAX_IFA]->sa_family != AF_LINK) 1112122394Sharti break; 1113122394Sharti sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; 1114122394Sharti if ((rcv = mib_find_rcvaddr(sdl->sdl_index, 1115122394Sharti sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) { 1116122394Sharti /* unknown address */ 1117122394Sharti if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) { 1118122394Sharti syslog(LOG_WARNING, "RTM_NEWMADDR for unknown " 1119122394Sharti "interface %u", sdl->sdl_index); 1120122394Sharti break; 1121122394Sharti } 1122122394Sharti if ((rcv = mib_rcvaddr_create(ifp, 1123122394Sharti sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) 1124122394Sharti break; 1125122394Sharti rcv->flags |= MIBRCVADDR_VOLATILE; 1126122394Sharti } 1127122394Sharti rcv->flags |= MIBRCVADDR_FOUND; 1128122394Sharti break; 1129122394Sharti 1130122394Sharti case RTM_DELMADDR: 1131122394Sharti ifmam = (struct ifma_msghdr *)rtm; 1132122394Sharti mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); 1133122394Sharti if (addrs[RTAX_IFA] == NULL || 1134122394Sharti addrs[RTAX_IFA]->sa_family != AF_LINK) 1135122394Sharti break; 1136122394Sharti sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; 1137122394Sharti if ((rcv = mib_find_rcvaddr(sdl->sdl_index, 1138122394Sharti sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) != NULL) 1139122394Sharti mib_rcvaddr_delete(rcv); 1140122394Sharti break; 1141122394Sharti 1142122394Sharti case RTM_IFINFO: 1143188760Simp ifm = (struct if_msghdr *)(void *)rtm; 1144122394Sharti mib_extract_addrs(ifm->ifm_addrs, (u_char *)(ifm + 1), addrs); 1145122394Sharti if ((ifp = mib_find_if_sys(ifm->ifm_index)) == NULL) 1146122394Sharti break; 1147122394Sharti if (addrs[RTAX_IFP] != NULL && 1148122394Sharti addrs[RTAX_IFP]->sa_family == AF_LINK) { 1149122394Sharti sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFP]; 1150122394Sharti ptr = sdl->sdl_data + sdl->sdl_nlen; 1151122394Sharti get_physaddr(ifp, sdl, ptr); 1152122394Sharti } 1153122394Sharti (void)mib_fetch_ifmib(ifp); 1154122394Sharti break; 1155122394Sharti 1156122394Sharti#ifdef RTM_IFANNOUNCE 1157122394Sharti case RTM_IFANNOUNCE: 1158122394Sharti ifan = (struct if_announcemsghdr *)rtm; 1159122394Sharti ifp = mib_find_if_sys(ifan->ifan_index); 1160122394Sharti 1161122394Sharti switch (ifan->ifan_what) { 1162122394Sharti 1163122394Sharti case IFAN_ARRIVAL: 1164122394Sharti if (ifp == NULL && (ifp = mibif_create(ifan->ifan_index, 1165122394Sharti ifan->ifan_name)) != NULL) { 1166122394Sharti (void)mib_fetch_ifmib(ifp); 1167122394Sharti check_llbcast(ifp); 1168122394Sharti notify_newif(ifp); 1169122394Sharti } 1170122394Sharti break; 1171122394Sharti 1172122394Sharti case IFAN_DEPARTURE: 1173122394Sharti if (ifp != NULL) 1174122394Sharti mibif_free(ifp); 1175122394Sharti break; 1176122394Sharti } 1177122394Sharti break; 1178122394Sharti#endif 1179122394Sharti case RTM_GET: 1180122394Sharti case RTM_ADD: 1181249896Sglebius mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); 1182249896Sglebius if (rtm->rtm_flags & RTF_LLINFO) { 1183249896Sglebius if (addrs[RTAX_DST] == NULL || 1184249896Sglebius addrs[RTAX_GATEWAY] == NULL || 1185249896Sglebius addrs[RTAX_DST]->sa_family != AF_INET || 1186249896Sglebius addrs[RTAX_GATEWAY]->sa_family != AF_LINK) 1187249896Sglebius break; 1188249896Sglebius process_arp(rtm, 1189249896Sglebius (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY], 1190249896Sglebius (struct sockaddr_in *)(void *)addrs[RTAX_DST]); 1191249896Sglebius } else { 1192249896Sglebius if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP)) 1193249896Sglebius mib_sroute_process(rtm, addrs[RTAX_GATEWAY], 1194249896Sglebius addrs[RTAX_DST], addrs[RTAX_NETMASK]); 1195249896Sglebius } 1196249896Sglebius break; 1197249896Sglebius 1198186119Sqingli case RTM_DELETE: 1199122394Sharti mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); 1200150920Sharti 1201186119Sqingli if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP)) 1202150920Sharti mib_sroute_process(rtm, addrs[RTAX_GATEWAY], 1203150920Sharti addrs[RTAX_DST], addrs[RTAX_NETMASK]); 1204150920Sharti break; 1205122394Sharti } 1206122394Sharti} 1207122394Sharti 1208122394Sharti/* 1209150920Sharti * send a routing message 1210150920Sharti */ 1211150920Shartivoid 1212150920Shartimib_send_rtmsg(struct rt_msghdr *rtm, struct sockaddr *gw, 1213150920Sharti struct sockaddr *dst, struct sockaddr *mask) 1214150920Sharti{ 1215150920Sharti size_t len; 1216150920Sharti struct rt_msghdr *msg; 1217150920Sharti char *cp; 1218150920Sharti ssize_t sent; 1219150920Sharti 1220150920Sharti len = sizeof(*rtm) + SA_SIZE(gw) + SA_SIZE(dst) + SA_SIZE(mask); 1221150920Sharti if ((msg = malloc(len)) == NULL) { 1222150920Sharti syslog(LOG_ERR, "%s: %m", __func__); 1223150920Sharti return; 1224150920Sharti } 1225150920Sharti cp = (char *)(msg + 1); 1226150920Sharti 1227150920Sharti memset(msg, 0, sizeof(*msg)); 1228150920Sharti msg->rtm_flags = 0; 1229150920Sharti msg->rtm_version = RTM_VERSION; 1230150920Sharti msg->rtm_addrs = RTA_DST | RTA_GATEWAY; 1231150920Sharti 1232150920Sharti memcpy(cp, dst, SA_SIZE(dst)); 1233150920Sharti cp += SA_SIZE(dst); 1234150920Sharti memcpy(cp, gw, SA_SIZE(gw)); 1235150920Sharti cp += SA_SIZE(gw); 1236150920Sharti if (mask != NULL) { 1237150920Sharti memcpy(cp, mask, SA_SIZE(mask)); 1238150920Sharti cp += SA_SIZE(mask); 1239150920Sharti msg->rtm_addrs |= RTA_NETMASK; 1240150920Sharti } 1241150920Sharti msg->rtm_msglen = cp - (char *)msg; 1242150920Sharti msg->rtm_type = RTM_GET; 1243150920Sharti if ((sent = write(route, msg, msg->rtm_msglen)) == -1) { 1244150920Sharti syslog(LOG_ERR, "%s: write: %m", __func__); 1245150920Sharti free(msg); 1246150920Sharti return; 1247150920Sharti } 1248150920Sharti if (sent != msg->rtm_msglen) { 1249150920Sharti syslog(LOG_ERR, "%s: short write", __func__); 1250150920Sharti free(msg); 1251150920Sharti return; 1252150920Sharti } 1253150920Sharti free(msg); 1254150920Sharti} 1255150920Sharti 1256150920Sharti/* 1257122394Sharti * Fetch the routing table via sysctl 1258122394Sharti */ 1259122394Shartiu_char * 1260122394Shartimib_fetch_rtab(int af, int info, int arg, size_t *lenp) 1261122394Sharti{ 1262122394Sharti int name[6]; 1263154184Sharti u_char *buf, *newbuf; 1264122394Sharti 1265122394Sharti name[0] = CTL_NET; 1266122394Sharti name[1] = PF_ROUTE; 1267122394Sharti name[2] = 0; 1268122394Sharti name[3] = af; 1269122394Sharti name[4] = info; 1270122394Sharti name[5] = arg; 1271122394Sharti 1272124861Sharti *lenp = 0; 1273124861Sharti 1274154184Sharti /* initial estimate */ 1275312045Sngie if (sysctl(name, nitems(name), NULL, lenp, NULL, 0) == -1) { 1276122394Sharti syslog(LOG_ERR, "sysctl estimate (%d,%d,%d,%d,%d,%d): %m", 1277122394Sharti name[0], name[1], name[2], name[3], name[4], name[5]); 1278122394Sharti return (NULL); 1279122394Sharti } 1280124861Sharti if (*lenp == 0) 1281124861Sharti return (NULL); 1282122394Sharti 1283154184Sharti buf = NULL; 1284154184Sharti for (;;) { 1285154184Sharti if ((newbuf = realloc(buf, *lenp)) == NULL) { 1286154184Sharti syslog(LOG_ERR, "sysctl buffer: %m"); 1287154184Sharti free(buf); 1288154184Sharti return (NULL); 1289154184Sharti } 1290154184Sharti buf = newbuf; 1291310903Sngie 1292312045Sngie if (sysctl(name, nitems(name), buf, lenp, NULL, 0) == 0) 1293154184Sharti break; 1294122394Sharti 1295154184Sharti if (errno != ENOMEM) { 1296154184Sharti syslog(LOG_ERR, "sysctl get: %m"); 1297154184Sharti free(buf); 1298154184Sharti return (NULL); 1299154184Sharti } 1300154184Sharti *lenp += *lenp / 8 + 1; 1301122394Sharti } 1302122394Sharti 1303122394Sharti return (buf); 1304122394Sharti} 1305122394Sharti 1306122394Sharti/* 1307122394Sharti * Update the following info: interface, interface addresses, interface 1308122394Sharti * receive addresses, arp-table. 1309122394Sharti * This does not change the interface list itself. 1310122394Sharti */ 1311122394Shartistatic void 1312122394Shartiupdate_ifa_info(void) 1313122394Sharti{ 1314122394Sharti u_char *buf, *next; 1315122394Sharti struct rt_msghdr *rtm; 1316122394Sharti struct mibifa *ifa, *ifa1; 1317122394Sharti struct mibrcvaddr *rcv, *rcv1; 1318122394Sharti size_t needed; 1319122394Sharti static const int infos[][3] = { 1320122394Sharti { 0, NET_RT_IFLIST, 0 }, 1321122394Sharti#ifdef NET_RT_IFMALIST 1322122394Sharti { AF_LINK, NET_RT_IFMALIST, 0 }, 1323122394Sharti#endif 1324122394Sharti }; 1325122394Sharti u_int i; 1326122394Sharti 1327122394Sharti TAILQ_FOREACH(ifa, &mibifa_list, link) 1328122394Sharti ifa->flags &= ~MIBIFA_FOUND; 1329122394Sharti TAILQ_FOREACH(rcv, &mibrcvaddr_list, link) 1330122394Sharti rcv->flags &= ~MIBRCVADDR_FOUND; 1331122394Sharti 1332122394Sharti for (i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) { 1333122394Sharti if ((buf = mib_fetch_rtab(infos[i][0], infos[i][1], infos[i][2], 1334122394Sharti &needed)) == NULL) 1335122394Sharti continue; 1336122394Sharti 1337122394Sharti next = buf; 1338122394Sharti while (next < buf + needed) { 1339122394Sharti rtm = (struct rt_msghdr *)(void *)next; 1340122394Sharti next += rtm->rtm_msglen; 1341122394Sharti handle_rtmsg(rtm); 1342122394Sharti } 1343122394Sharti free(buf); 1344122394Sharti } 1345122394Sharti 1346122394Sharti /* 1347122394Sharti * Purge the address list of unused entries. These may happen for 1348122394Sharti * interface aliases that are on the same subnet. We don't receive 1349122394Sharti * routing socket messages for them. 1350122394Sharti */ 1351122394Sharti ifa = TAILQ_FIRST(&mibifa_list); 1352122394Sharti while (ifa != NULL) { 1353122394Sharti ifa1 = TAILQ_NEXT(ifa, link); 1354122394Sharti if (!(ifa->flags & MIBIFA_FOUND)) 1355122394Sharti destroy_ifa(ifa); 1356122394Sharti ifa = ifa1; 1357122394Sharti } 1358122394Sharti 1359122394Sharti rcv = TAILQ_FIRST(&mibrcvaddr_list); 1360122394Sharti while (rcv != NULL) { 1361122394Sharti rcv1 = TAILQ_NEXT(rcv, link); 1362122394Sharti if (!(rcv->flags & (MIBRCVADDR_FOUND | MIBRCVADDR_BCAST | 1363122394Sharti MIBRCVADDR_HW))) 1364122394Sharti mib_rcvaddr_delete(rcv); 1365122394Sharti rcv = rcv1; 1366122394Sharti } 1367122394Sharti} 1368122394Sharti 1369122394Sharti/* 1370122394Sharti * Update arp table 1371311139Sngie */ 1372122394Shartivoid 1373122394Shartimib_arp_update(void) 1374122394Sharti{ 1375122394Sharti struct mibarp *at, *at1; 1376122394Sharti size_t needed; 1377122394Sharti u_char *buf, *next; 1378122394Sharti struct rt_msghdr *rtm; 1379122394Sharti 1380122394Sharti if (in_update_arp) 1381122394Sharti return; /* Aaargh */ 1382122394Sharti in_update_arp = 1; 1383122394Sharti 1384122394Sharti TAILQ_FOREACH(at, &mibarp_list, link) 1385122394Sharti at->flags &= ~MIBARP_FOUND; 1386122394Sharti 1387186119Sqingli if ((buf = mib_fetch_rtab(AF_INET, NET_RT_FLAGS, 0, &needed)) == NULL) { 1388122394Sharti in_update_arp = 0; 1389122394Sharti return; 1390122394Sharti } 1391310903Sngie 1392122394Sharti next = buf; 1393122394Sharti while (next < buf + needed) { 1394122394Sharti rtm = (struct rt_msghdr *)(void *)next; 1395122394Sharti next += rtm->rtm_msglen; 1396122394Sharti handle_rtmsg(rtm); 1397122394Sharti } 1398122394Sharti free(buf); 1399122394Sharti 1400122394Sharti at = TAILQ_FIRST(&mibarp_list); 1401122394Sharti while (at != NULL) { 1402122394Sharti at1 = TAILQ_NEXT(at, link); 1403122394Sharti if (!(at->flags & MIBARP_FOUND)) 1404122394Sharti mib_arp_delete(at); 1405122394Sharti at = at1; 1406122394Sharti } 1407122394Sharti mibarpticks = get_ticks(); 1408122394Sharti in_update_arp = 0; 1409122394Sharti} 1410122394Sharti 1411122394Sharti 1412122394Sharti/* 1413311139Sngie * Input on the routing socket. 1414122394Sharti */ 1415122394Shartistatic void 1416122394Shartiroute_input(int fd, void *udata __unused) 1417122394Sharti{ 1418122394Sharti u_char buf[1024 * 16]; 1419122394Sharti ssize_t n; 1420122394Sharti struct rt_msghdr *rtm; 1421122394Sharti 1422122394Sharti if ((n = read(fd, buf, sizeof(buf))) == -1) 1423122394Sharti err(1, "read(rt_socket)"); 1424122394Sharti 1425122394Sharti if (n == 0) 1426122394Sharti errx(1, "EOF on rt_socket"); 1427122394Sharti 1428122394Sharti rtm = (struct rt_msghdr *)(void *)buf; 1429122394Sharti if ((size_t)n != rtm->rtm_msglen) 1430122394Sharti errx(1, "n=%zu, rtm_msglen=%u", (size_t)n, rtm->rtm_msglen); 1431122394Sharti 1432122394Sharti handle_rtmsg(rtm); 1433122394Sharti} 1434122394Sharti 1435122394Sharti/* 1436122394Sharti * execute and SIOCAIFADDR 1437122394Sharti */ 1438122394Shartistatic int 1439122394Shartisiocaifaddr(char *ifname, struct in_addr addr, struct in_addr mask, 1440122394Sharti struct in_addr bcast) 1441122394Sharti{ 1442122394Sharti struct ifaliasreq addreq; 1443122394Sharti struct sockaddr_in *sa; 1444122394Sharti 1445122394Sharti memset(&addreq, 0, sizeof(addreq)); 1446312089Sngie strlcpy(addreq.ifra_name, ifname, sizeof(addreq.ifra_name)); 1447122394Sharti 1448122394Sharti sa = (struct sockaddr_in *)(void *)&addreq.ifra_addr; 1449122394Sharti sa->sin_family = AF_INET; 1450122394Sharti sa->sin_len = sizeof(*sa); 1451122394Sharti sa->sin_addr = addr; 1452122394Sharti 1453122394Sharti sa = (struct sockaddr_in *)(void *)&addreq.ifra_mask; 1454122394Sharti sa->sin_family = AF_INET; 1455122394Sharti sa->sin_len = sizeof(*sa); 1456122394Sharti sa->sin_addr = mask; 1457122394Sharti 1458122394Sharti sa = (struct sockaddr_in *)(void *)&addreq.ifra_broadaddr; 1459122394Sharti sa->sin_family = AF_INET; 1460122394Sharti sa->sin_len = sizeof(*sa); 1461122394Sharti sa->sin_addr = bcast; 1462122394Sharti 1463122394Sharti return (ioctl(mib_netsock, SIOCAIFADDR, &addreq)); 1464122394Sharti} 1465122394Sharti 1466122394Sharti/* 1467122394Sharti * Exececute a SIOCDIFADDR 1468122394Sharti */ 1469122394Shartistatic int 1470122394Shartisiocdifaddr(const char *ifname, struct in_addr addr) 1471122394Sharti{ 1472122394Sharti struct ifreq delreq; 1473122394Sharti struct sockaddr_in *sa; 1474122394Sharti 1475122394Sharti memset(&delreq, 0, sizeof(delreq)); 1476312089Sngie strlcpy(delreq.ifr_name, ifname, sizeof(delreq.ifr_name)); 1477122394Sharti sa = (struct sockaddr_in *)(void *)&delreq.ifr_addr; 1478122394Sharti sa->sin_family = AF_INET; 1479122394Sharti sa->sin_len = sizeof(*sa); 1480122394Sharti sa->sin_addr = addr; 1481122394Sharti 1482122394Sharti return (ioctl(mib_netsock, SIOCDIFADDR, &delreq)); 1483122394Sharti} 1484122394Sharti 1485122394Sharti/* 1486122394Sharti * Verify an interface address without fetching the entire list 1487122394Sharti */ 1488122394Shartistatic int 1489122394Shartiverify_ifa(const char *name, struct mibifa *ifa) 1490122394Sharti{ 1491122394Sharti struct ifreq req; 1492122394Sharti struct sockaddr_in *sa; 1493122394Sharti 1494122394Sharti memset(&req, 0, sizeof(req)); 1495312089Sngie strlcpy(req.ifr_name, name, sizeof(req.ifr_name)); 1496122394Sharti sa = (struct sockaddr_in *)(void *)&req.ifr_addr; 1497122394Sharti sa->sin_family = AF_INET; 1498122394Sharti sa->sin_len = sizeof(*sa); 1499122394Sharti sa->sin_addr = ifa->inaddr; 1500122394Sharti 1501122394Sharti if (ioctl(mib_netsock, SIOCGIFADDR, &req) == -1) 1502122394Sharti return (-1); 1503122394Sharti if (ifa->inaddr.s_addr != sa->sin_addr.s_addr) { 1504122394Sharti syslog(LOG_ERR, "%s: address mismatch", __func__); 1505122394Sharti return (-1); 1506122394Sharti } 1507122394Sharti 1508122394Sharti if (ioctl(mib_netsock, SIOCGIFNETMASK, &req) == -1) 1509122394Sharti return (-1); 1510122394Sharti if (ifa->inmask.s_addr != sa->sin_addr.s_addr) { 1511122394Sharti syslog(LOG_ERR, "%s: netmask mismatch", __func__); 1512122394Sharti return (-1); 1513122394Sharti } 1514122394Sharti return (0); 1515122394Sharti} 1516122394Sharti 1517122394Sharti/* 1518122394Sharti * Restore a deleted interface address. Don't wait for the routing socket 1519122394Sharti * to update us. 1520122394Sharti */ 1521122394Shartivoid 1522122394Shartimib_undestroy_ifa(struct mibifa *ifa) 1523122394Sharti{ 1524122394Sharti struct mibif *ifp; 1525122394Sharti 1526122394Sharti if ((ifp = mib_find_if(ifa->ifindex)) == NULL) 1527122394Sharti /* keep it destroyed */ 1528122394Sharti return; 1529122394Sharti 1530122394Sharti if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) 1531122394Sharti /* keep it destroyed */ 1532122394Sharti return; 1533122394Sharti 1534122394Sharti ifa->flags &= ~MIBIFA_DESTROYED; 1535122394Sharti} 1536122394Sharti 1537122394Sharti/* 1538122394Sharti * Destroy an interface address 1539122394Sharti */ 1540122394Shartiint 1541122394Shartimib_destroy_ifa(struct mibifa *ifa) 1542122394Sharti{ 1543122394Sharti struct mibif *ifp; 1544122394Sharti 1545122394Sharti if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1546122394Sharti /* ups. */ 1547122394Sharti mib_iflist_bad = 1; 1548122394Sharti return (-1); 1549122394Sharti } 1550122394Sharti if (siocdifaddr(ifp->name, ifa->inaddr)) { 1551122394Sharti /* ups. */ 1552122394Sharti syslog(LOG_ERR, "SIOCDIFADDR: %m"); 1553122394Sharti mib_iflist_bad = 1; 1554122394Sharti return (-1); 1555122394Sharti } 1556122394Sharti ifa->flags |= MIBIFA_DESTROYED; 1557122394Sharti return (0); 1558122394Sharti} 1559122394Sharti 1560122394Sharti/* 1561122394Sharti * Rollback the modification of an address. Don't bother to wait for 1562122394Sharti * the routing socket. 1563122394Sharti */ 1564122394Shartivoid 1565122394Shartimib_unmodify_ifa(struct mibifa *ifa) 1566122394Sharti{ 1567122394Sharti struct mibif *ifp; 1568122394Sharti 1569122394Sharti if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1570122394Sharti /* ups. */ 1571122394Sharti mib_iflist_bad = 1; 1572122394Sharti return; 1573122394Sharti } 1574122394Sharti 1575122394Sharti if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1576122394Sharti /* ups. */ 1577122394Sharti mib_iflist_bad = 1; 1578122394Sharti return; 1579122394Sharti } 1580122394Sharti} 1581122394Sharti 1582122394Sharti/* 1583310903Sngie * Modify an IFA. 1584122394Sharti */ 1585122394Shartiint 1586122394Shartimib_modify_ifa(struct mibifa *ifa) 1587122394Sharti{ 1588122394Sharti struct mibif *ifp; 1589122394Sharti 1590122394Sharti if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1591122394Sharti /* ups. */ 1592122394Sharti mib_iflist_bad = 1; 1593122394Sharti return (-1); 1594122394Sharti } 1595122394Sharti 1596122394Sharti if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1597122394Sharti /* ups. */ 1598122394Sharti mib_iflist_bad = 1; 1599122394Sharti return (-1); 1600122394Sharti } 1601122394Sharti 1602122394Sharti if (verify_ifa(ifp->name, ifa)) { 1603122394Sharti /* ups. */ 1604122394Sharti mib_iflist_bad = 1; 1605122394Sharti return (-1); 1606122394Sharti } 1607122394Sharti 1608122394Sharti return (0); 1609122394Sharti} 1610122394Sharti 1611122394Sharti/* 1612122394Sharti * Destroy a freshly created interface address. Don't bother to wait for 1613122394Sharti * the routing socket. 1614122394Sharti */ 1615122394Shartivoid 1616122394Shartimib_uncreate_ifa(struct mibifa *ifa) 1617122394Sharti{ 1618122394Sharti struct mibif *ifp; 1619122394Sharti 1620122394Sharti if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { 1621122394Sharti /* ups. */ 1622122394Sharti mib_iflist_bad = 1; 1623122394Sharti return; 1624122394Sharti } 1625122394Sharti if (siocdifaddr(ifp->name, ifa->inaddr)) { 1626122394Sharti /* ups. */ 1627122394Sharti mib_iflist_bad = 1; 1628122394Sharti return; 1629122394Sharti } 1630122394Sharti 1631122394Sharti destroy_ifa(ifa); 1632122394Sharti} 1633122394Sharti 1634122394Sharti/* 1635122394Sharti * Create a new ifa and verify it 1636122394Sharti */ 1637122394Shartistruct mibifa * 1638122394Shartimib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask, 1639122394Sharti struct in_addr bcast) 1640122394Sharti{ 1641122394Sharti struct mibif *ifp; 1642122394Sharti struct mibifa *ifa; 1643122394Sharti 1644122394Sharti if ((ifp = mib_find_if(ifindex)) == NULL) 1645122394Sharti return (NULL); 1646122394Sharti if ((ifa = alloc_ifa(ifindex, addr)) == NULL) 1647122394Sharti return (NULL); 1648122394Sharti ifa->inmask = mask; 1649122394Sharti ifa->inbcast = bcast; 1650122394Sharti 1651122394Sharti if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { 1652122394Sharti syslog(LOG_ERR, "%s: %m", __func__); 1653122394Sharti destroy_ifa(ifa); 1654122394Sharti return (NULL); 1655122394Sharti } 1656122394Sharti if (verify_ifa(ifp->name, ifa)) { 1657122394Sharti destroy_ifa(ifa); 1658122394Sharti return (NULL); 1659122394Sharti } 1660122394Sharti return (ifa); 1661122394Sharti} 1662122394Sharti 1663122394Sharti/* 1664122394Sharti * Get all cloning interfaces and make them dynamic. 1665122394Sharti * Hah! Whe should probably do this on a periodic basis (XXX). 1666122394Sharti */ 1667122394Shartistatic void 1668122394Shartiget_cloners(void) 1669122394Sharti{ 1670122394Sharti struct if_clonereq req; 1671122394Sharti char *buf, *cp; 1672122394Sharti int i; 1673122394Sharti 1674122394Sharti memset(&req, 0, sizeof(req)); 1675122394Sharti if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { 1676122394Sharti syslog(LOG_ERR, "get cloners: %m"); 1677122394Sharti return; 1678122394Sharti } 1679122394Sharti if ((buf = malloc(req.ifcr_total * IFNAMSIZ)) == NULL) { 1680122394Sharti syslog(LOG_ERR, "%m"); 1681122394Sharti return; 1682122394Sharti } 1683122394Sharti req.ifcr_count = req.ifcr_total; 1684122394Sharti req.ifcr_buffer = buf; 1685122394Sharti if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { 1686122394Sharti syslog(LOG_ERR, "get cloners: %m"); 1687122394Sharti free(buf); 1688122394Sharti return; 1689122394Sharti } 1690122394Sharti for (cp = buf, i = 0; i < req.ifcr_total; i++, cp += IFNAMSIZ) 1691122394Sharti mib_if_set_dyn(cp); 1692122394Sharti free(buf); 1693122394Sharti} 1694122394Sharti 1695122394Sharti/* 1696122394Sharti * Idle function 1697122394Sharti */ 1698122394Shartistatic void 1699200063SsyrinxmibII_idle(void *arg __unused) 1700122394Sharti{ 1701122394Sharti struct mibifa *ifa; 1702122394Sharti 1703122394Sharti if (mib_iflist_bad) { 1704122394Sharti TAILQ_FOREACH(ifa, &mibifa_list, link) 1705122394Sharti ifa->flags &= ~MIBIFA_DESTROYED; 1706122394Sharti 1707122394Sharti /* assume, that all cloning interfaces are dynamic */ 1708122394Sharti get_cloners(); 1709122394Sharti 1710122394Sharti mib_refresh_iflist(); 1711122394Sharti update_ifa_info(); 1712122394Sharti mib_arp_update(); 1713122394Sharti mib_iflist_bad = 0; 1714122394Sharti } 1715186119Sqingli 1716186119Sqingli mib_arp_update(); 1717122394Sharti} 1718122394Sharti 1719122394Sharti 1720122394Sharti/* 1721122394Sharti * Start the module 1722122394Sharti */ 1723122394Shartistatic void 1724122394ShartimibII_start(void) 1725122394Sharti{ 1726122394Sharti if ((route_fd = fd_select(route, route_input, NULL, module)) == NULL) { 1727122394Sharti syslog(LOG_ERR, "fd_select(route): %m"); 1728122394Sharti return; 1729122394Sharti } 1730122394Sharti mib_refresh_iflist(); 1731122394Sharti update_ifa_info(); 1732122394Sharti mib_arp_update(); 1733150920Sharti (void)mib_fetch_route(); 1734122394Sharti mib_iftable_last_change = 0; 1735122394Sharti mib_ifstack_last_change = 0; 1736122394Sharti 1737122394Sharti ifmib_reg = or_register(&oid_ifMIB, 1738122394Sharti "The MIB module to describe generic objects for network interface" 1739122394Sharti " sub-layers.", module); 1740122394Sharti 1741122394Sharti ipmib_reg = or_register(&oid_ipMIB, 1742122394Sharti "The MIB module for managing IP and ICMP implementations, but " 1743122394Sharti "excluding their management of IP routes.", module); 1744122394Sharti 1745122394Sharti tcpmib_reg = or_register(&oid_tcpMIB, 1746122394Sharti "The MIB module for managing TCP implementations.", module); 1747122394Sharti 1748122394Sharti udpmib_reg = or_register(&oid_udpMIB, 1749122394Sharti "The MIB module for managing UDP implementations.", module); 1750122394Sharti 1751122394Sharti ipForward_reg = or_register(&oid_ipForward, 1752122394Sharti "The MIB module for the display of CIDR multipath IP Routes.", 1753122394Sharti module); 1754200063Ssyrinx 1755200063Ssyrinx mibII_poll_timer = NULL; 1756200063Ssyrinx mibII_poll_ticks = MIBII_POLL_TICKS; 1757200063Ssyrinx mibif_restart_mibII_poll_timer(); 1758122394Sharti} 1759122394Sharti 1760122394Sharti/* 1761122394Sharti * Initialize the module 1762122394Sharti */ 1763122394Shartistatic int 1764122394ShartimibII_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) 1765122394Sharti{ 1766122394Sharti size_t len; 1767122394Sharti 1768122394Sharti module = mod; 1769122394Sharti 1770122394Sharti len = sizeof(clockinfo); 1771122394Sharti if (sysctlbyname("kern.clockrate", &clockinfo, &len, NULL, 0) == -1) { 1772122394Sharti syslog(LOG_ERR, "kern.clockrate: %m"); 1773122394Sharti return (-1); 1774122394Sharti } 1775122394Sharti if (len != sizeof(clockinfo)) { 1776122394Sharti syslog(LOG_ERR, "kern.clockrate: wrong size"); 1777122394Sharti return (-1); 1778122394Sharti } 1779122394Sharti 1780122394Sharti if ((route = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) { 1781122394Sharti syslog(LOG_ERR, "PF_ROUTE: %m"); 1782122394Sharti return (-1); 1783122394Sharti } 1784122394Sharti 1785122394Sharti if ((mib_netsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 1786122394Sharti syslog(LOG_ERR, "PF_INET: %m"); 1787122394Sharti (void)close(route); 1788122394Sharti return (-1); 1789122394Sharti } 1790122394Sharti (void)shutdown(mib_netsock, SHUT_RDWR); 1791122394Sharti 1792122394Sharti /* assume, that all cloning interfaces are dynamic */ 1793122394Sharti get_cloners(); 1794122394Sharti 1795122394Sharti return (0); 1796122394Sharti} 1797122394Sharti 1798122394Shartistatic int 1799122394ShartimibII_fini(void) 1800122394Sharti{ 1801200063Ssyrinx if (mibII_poll_timer != NULL ) { 1802200063Ssyrinx timer_stop(mibII_poll_timer); 1803200063Ssyrinx mibII_poll_timer = NULL; 1804200063Ssyrinx } 1805200063Ssyrinx 1806122394Sharti if (route_fd != NULL) 1807122394Sharti fd_deselect(route_fd); 1808122394Sharti if (route != -1) 1809122394Sharti (void)close(route); 1810122394Sharti if (mib_netsock != -1) 1811122394Sharti (void)close(mib_netsock); 1812122394Sharti /* XXX free memory */ 1813122394Sharti 1814122394Sharti or_unregister(ipForward_reg); 1815122394Sharti or_unregister(udpmib_reg); 1816122394Sharti or_unregister(tcpmib_reg); 1817122394Sharti or_unregister(ipmib_reg); 1818122394Sharti or_unregister(ifmib_reg); 1819122394Sharti 1820122394Sharti return (0); 1821122394Sharti} 1822122394Sharti 1823122394Shartistatic void 1824122394ShartimibII_loading(const struct lmodule *mod, int loaded) 1825122394Sharti{ 1826122394Sharti struct mibif *ifp; 1827122394Sharti 1828122394Sharti if (loaded == 1) 1829122394Sharti return; 1830122394Sharti 1831122394Sharti TAILQ_FOREACH(ifp, &mibif_list, link) 1832122394Sharti if (ifp->xnotify_mod == mod) { 1833122394Sharti ifp->xnotify_mod = NULL; 1834122394Sharti ifp->xnotify_data = NULL; 1835122394Sharti ifp->xnotify = NULL; 1836122394Sharti } 1837122394Sharti 1838122394Sharti mib_unregister_newif(mod); 1839122394Sharti} 1840122394Sharti 1841122394Sharticonst struct snmp_module config = { 1842122394Sharti "This module implements the interface and ip groups.", 1843122394Sharti mibII_init, 1844122394Sharti mibII_fini, 1845200063Ssyrinx NULL, /* idle */ 1846122394Sharti NULL, /* dump */ 1847122394Sharti NULL, /* config */ 1848122394Sharti mibII_start, 1849122394Sharti NULL, 1850122394Sharti mibII_ctree, 1851122394Sharti mibII_CTREE_SIZE, 1852122394Sharti mibII_loading 1853122394Sharti}; 1854122394Sharti 1855122394Sharti/* 1856122394Sharti * Should have a list of these attached to each interface. 1857122394Sharti */ 1858122394Shartivoid * 1859122394Shartimibif_notify(struct mibif *ifp, const struct lmodule *mod, 1860122394Sharti mibif_notify_f func, void *data) 1861122394Sharti{ 1862122394Sharti ifp->xnotify = func; 1863122394Sharti ifp->xnotify_data = data; 1864122394Sharti ifp->xnotify_mod = mod; 1865122394Sharti 1866122394Sharti return (ifp); 1867122394Sharti} 1868122394Sharti 1869122394Shartivoid 1870122394Shartimibif_unnotify(void *arg) 1871122394Sharti{ 1872122394Sharti struct mibif *ifp = arg; 1873122394Sharti 1874122394Sharti ifp->xnotify = NULL; 1875122394Sharti ifp->xnotify_data = NULL; 1876122394Sharti ifp->xnotify_mod = NULL; 1877122394Sharti} 1878