xref: /freebsd/contrib/bsnmp/snmp_mibII/mibII.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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