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