xref: /freebsd/contrib/bsnmp/snmp_mibII/mibII.c (revision 262e143bd46171a6415a5b28af260a5efa2a3db8)
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.23 2005/06/09 12:36:52 brandt_h 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 uint64_t mib_iftable_last_change;
89 
90 /* last change of stack table */
91 uint64_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 uint64_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 *)(void *)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 	ifp->spec_oid = oid_zeroDotZero;
594 
595 	map = NULL;
596 	if (!mib_if_is_dyn(ifp->name)) {
597 		/* non-dynamic. look whether we know the interface */
598 		STAILQ_FOREACH(map, &mibindexmap_list, link)
599 			if (strcmp(map->name, ifp->name) == 0) {
600 				ifp->index = map->ifindex;
601 				map->mibif = ifp;
602 				break;
603 			}
604 		/* assume it has a connector if it is not dynamic */
605 		ifp->has_connector = 1;
606 		ifp->trap_enable = 1;
607 	}
608 	if (map == NULL) {
609 		/* new interface - get new index */
610 		if (next_if_index > 0x7fffffff)
611 			errx(1, "ifindex wrap");
612 
613 		if ((map = malloc(sizeof(*map))) == NULL) {
614 			syslog(LOG_ERR, "ifmap: %m");
615 			free(ifp);
616 			return (NULL);
617 		}
618 		map->ifindex = next_if_index++;
619 		map->sysindex = ifp->sysindex;
620 		strcpy(map->name, ifp->name);
621 		map->mibif = ifp;
622 		STAILQ_INSERT_TAIL(&mibindexmap_list, map, link);
623 	} else {
624 		/* re-instantiate. Introduce a counter discontinuity */
625 		ifp->counter_disc = get_ticks();
626 	}
627 	ifp->index = map->ifindex;
628 
629 	INSERT_OBJECT_INT(ifp, &mibif_list);
630 	mib_if_number++;
631 	mib_iftable_last_change = this_tick;
632 
633 	/* instantiate default ifStack entries */
634 	(void)mib_ifstack_create(ifp, NULL);
635 	(void)mib_ifstack_create(NULL, ifp);
636 
637 	return (ifp);
638 }
639 
640 /*
641  * Inform all interested parties about a new interface
642  */
643 static void
644 notify_newif(struct mibif *ifp)
645 {
646 	struct newifreg *reg;
647 
648 	TAILQ_FOREACH(reg, &newifreg_list, link)
649 		if ((*reg->func)(ifp))
650 			return;
651 }
652 
653 /*
654  * This is called for new interfaces after we have fetched the interface
655  * MIB. If this is a broadcast interface try to guess the broadcast address
656  * depending on the interface type.
657  */
658 static void
659 check_llbcast(struct mibif *ifp)
660 {
661 	static u_char ether_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
662 	static u_char arcnet_bcast = 0;
663 	struct mibrcvaddr *rcv;
664 
665 	if (!(ifp->mib.ifmd_flags & IFF_BROADCAST))
666 		return;
667 
668 	switch (ifp->mib.ifmd_data.ifi_type) {
669 
670 	  case IFT_ETHER:
671 	  case IFT_FDDI:
672 	  case IFT_ISO88025:
673 		if (mib_find_rcvaddr(ifp->index, ether_bcast, 6) == NULL &&
674 		    (rcv = mib_rcvaddr_create(ifp, ether_bcast, 6)) != NULL)
675 			rcv->flags |= MIBRCVADDR_BCAST;
676 		break;
677 
678 	  case IFT_ARCNET:
679 		if (mib_find_rcvaddr(ifp->index, &arcnet_bcast, 1) == NULL &&
680 		    (rcv = mib_rcvaddr_create(ifp, &arcnet_bcast, 1)) != NULL)
681 			rcv->flags |= MIBRCVADDR_BCAST;
682 		break;
683 	}
684 }
685 
686 
687 /*
688  * Retrieve the current interface list from the system.
689  */
690 void
691 mib_refresh_iflist(void)
692 {
693 	struct mibif *ifp, *ifp1;
694 	size_t len;
695 	u_short idx;
696 	int name[6];
697 	int count;
698 	struct ifmibdata mib;
699 
700 	TAILQ_FOREACH(ifp, &mibif_list, link)
701 		ifp->flags &= ~MIBIF_FOUND;
702 
703 	len = sizeof(count);
704 	if (sysctlbyname("net.link.generic.system.ifcount", &count, &len,
705 	    NULL, 0) == -1) {
706 		syslog(LOG_ERR, "ifcount: %m");
707 		return;
708 	}
709 	name[0] = CTL_NET;
710 	name[1] = PF_LINK;
711 	name[2] = NETLINK_GENERIC;
712 	name[3] = IFMIB_IFDATA;
713 	name[5] = IFDATA_GENERAL;
714 	for (idx = 1; idx <= count; idx++) {
715 		name[4] = idx;
716 		len = sizeof(mib);
717 		if (sysctl(name, 6, &mib, &len, NULL, 0) == -1) {
718 			if (errno == ENOENT)
719 				continue;
720 			syslog(LOG_ERR, "ifmib(%u): %m", idx);
721 			return;
722 		}
723 		if ((ifp = mib_find_if_sys(idx)) != NULL) {
724 			ifp->flags |= MIBIF_FOUND;
725 			continue;
726 		}
727 		/* Unknown interface - create */
728 		if ((ifp = mibif_create(idx, mib.ifmd_name)) != NULL) {
729 			ifp->flags |= MIBIF_FOUND;
730 			(void)mib_fetch_ifmib(ifp);
731 			check_llbcast(ifp);
732 			notify_newif(ifp);
733 		}
734 	}
735 
736 	/*
737 	 * Purge interfaces that disappeared
738 	 */
739 	ifp = TAILQ_FIRST(&mibif_list);
740 	while (ifp != NULL) {
741 		ifp1 = TAILQ_NEXT(ifp, link);
742 		if (!(ifp->flags & MIBIF_FOUND))
743 			mibif_free(ifp);
744 		ifp = ifp1;
745 	}
746 }
747 
748 /*
749  * Find an interface address
750  */
751 struct mibifa *
752 mib_find_ifa(struct in_addr addr)
753 {
754 	struct mibifa *ifa;
755 
756 	TAILQ_FOREACH(ifa, &mibifa_list, link)
757 		if (ifa->inaddr.s_addr == addr.s_addr)
758 			return (ifa);
759 	return (NULL);
760 }
761 
762 /*
763  * Process a new ARP entry
764  */
765 static void
766 process_arp(const struct rt_msghdr *rtm, const struct sockaddr_dl *sdl,
767     const struct sockaddr_in *sa)
768 {
769 	struct mibif *ifp;
770 	struct mibarp *at;
771 
772 	/* IP arp table entry */
773 	if (sdl->sdl_alen == 0) {
774 		update_arp = 1;
775 		return;
776 	}
777 	if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL)
778 		return;
779 	/* have a valid entry */
780 	if ((at = mib_find_arp(ifp, sa->sin_addr)) == NULL &&
781 	    (at = mib_arp_create(ifp, sa->sin_addr,
782 	    sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL)
783 		return;
784 
785 	if (rtm->rtm_rmx.rmx_expire == 0)
786 		at->flags |= MIBARP_PERM;
787 	else
788 		at->flags &= ~MIBARP_PERM;
789 	at->flags |= MIBARP_FOUND;
790 }
791 
792 /*
793  * Handle a routing socket message.
794  */
795 static void
796 handle_rtmsg(struct rt_msghdr *rtm)
797 {
798 	struct sockaddr *addrs[RTAX_MAX];
799 	struct if_msghdr *ifm;
800 	struct ifa_msghdr *ifam;
801 	struct ifma_msghdr *ifmam;
802 #ifdef RTM_IFANNOUNCE
803 	struct if_announcemsghdr *ifan;
804 #endif
805 	struct mibif *ifp;
806 	struct sockaddr_dl *sdl;
807 	struct sockaddr_in *sa;
808 	struct mibifa *ifa;
809 	struct mibrcvaddr *rcv;
810 	u_char *ptr;
811 
812 	if (rtm->rtm_version != RTM_VERSION) {
813 		syslog(LOG_ERR, "Bogus RTM version %u", rtm->rtm_version);
814 		return;
815 	}
816 
817 	switch (rtm->rtm_type) {
818 
819 	  case RTM_NEWADDR:
820 		ifam = (struct ifa_msghdr *)rtm;
821 		mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs);
822 		if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL)
823 			break;
824 
825 		sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA];
826 		if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) {
827 			/* unknown address */
828 		    	if ((ifp = mib_find_if_sys(ifam->ifam_index)) == NULL) {
829 				syslog(LOG_WARNING, "RTM_NEWADDR for unknown "
830 				    "interface %u", ifam->ifam_index);
831 				break;
832 			}
833 		     	if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL)
834 				break;
835 		}
836 		sa = (struct sockaddr_in *)(void *)addrs[RTAX_NETMASK];
837 		ifa->inmask = sa->sin_addr;
838 
839 		if (addrs[RTAX_BRD] != NULL) {
840 			sa = (struct sockaddr_in *)(void *)addrs[RTAX_BRD];
841 			ifa->inbcast = sa->sin_addr;
842 		}
843 		ifa->flags |= MIBIFA_FOUND;
844 		break;
845 
846 	  case RTM_DELADDR:
847 		ifam = (struct ifa_msghdr *)rtm;
848 		mib_extract_addrs(ifam->ifam_addrs, (u_char *)(ifam + 1), addrs);
849 		if (addrs[RTAX_IFA] == NULL)
850 			break;
851 
852 		sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA];
853 		if ((ifa = mib_find_ifa(sa->sin_addr)) != NULL) {
854 			ifa->flags |= MIBIFA_FOUND;
855 			if (!(ifa->flags & MIBIFA_DESTROYED))
856 				destroy_ifa(ifa);
857 		}
858 		break;
859 
860 	  case RTM_NEWMADDR:
861 		ifmam = (struct ifma_msghdr *)rtm;
862 		mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs);
863 		if (addrs[RTAX_IFA] == NULL ||
864 		    addrs[RTAX_IFA]->sa_family != AF_LINK)
865 			break;
866 		sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA];
867 		if ((rcv = mib_find_rcvaddr(sdl->sdl_index,
868 		    sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) {
869 			/* unknown address */
870 		    	if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) {
871 				syslog(LOG_WARNING, "RTM_NEWMADDR for unknown "
872 				    "interface %u", sdl->sdl_index);
873 				break;
874 			}
875 		     	if ((rcv = mib_rcvaddr_create(ifp,
876 			    sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL)
877 				break;
878 			rcv->flags |= MIBRCVADDR_VOLATILE;
879 		}
880 		rcv->flags |= MIBRCVADDR_FOUND;
881 		break;
882 
883 	  case RTM_DELMADDR:
884 		ifmam = (struct ifma_msghdr *)rtm;
885 		mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs);
886 		if (addrs[RTAX_IFA] == NULL ||
887 		    addrs[RTAX_IFA]->sa_family != AF_LINK)
888 			break;
889 		sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA];
890 		if ((rcv = mib_find_rcvaddr(sdl->sdl_index,
891 		    sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) != NULL)
892 			mib_rcvaddr_delete(rcv);
893 		break;
894 
895 	  case RTM_IFINFO:
896 		ifm = (struct if_msghdr *)rtm;
897 		mib_extract_addrs(ifm->ifm_addrs, (u_char *)(ifm + 1), addrs);
898 		if ((ifp = mib_find_if_sys(ifm->ifm_index)) == NULL)
899 			break;
900 		if (addrs[RTAX_IFP] != NULL &&
901 		    addrs[RTAX_IFP]->sa_family == AF_LINK) {
902 			sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFP];
903 			ptr = sdl->sdl_data + sdl->sdl_nlen;
904 			get_physaddr(ifp, sdl, ptr);
905 		}
906 		(void)mib_fetch_ifmib(ifp);
907 		break;
908 
909 #ifdef RTM_IFANNOUNCE
910 	  case RTM_IFANNOUNCE:
911 		ifan = (struct if_announcemsghdr *)rtm;
912 		ifp = mib_find_if_sys(ifan->ifan_index);
913 
914 		switch (ifan->ifan_what) {
915 
916 		  case IFAN_ARRIVAL:
917 			if (ifp == NULL && (ifp = mibif_create(ifan->ifan_index,
918 			    ifan->ifan_name)) != NULL) {
919 				(void)mib_fetch_ifmib(ifp);
920 				check_llbcast(ifp);
921 				notify_newif(ifp);
922 			}
923 			break;
924 
925 		  case IFAN_DEPARTURE:
926 			if (ifp != NULL)
927 				mibif_free(ifp);
928 			break;
929 		}
930 		break;
931 #endif
932 
933 	  case RTM_GET:
934 		mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
935 		if (rtm->rtm_flags & RTF_LLINFO) {
936 			if (addrs[RTAX_DST] == NULL ||
937 			    addrs[RTAX_GATEWAY] == NULL ||
938 			    addrs[RTAX_DST]->sa_family != AF_INET ||
939 			    addrs[RTAX_GATEWAY]->sa_family != AF_LINK)
940 				break;
941 			process_arp(rtm,
942 			    (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY],
943 			    (struct sockaddr_in *)(void *)addrs[RTAX_DST]);
944 		} else {
945 			if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP))
946 				mib_sroute_process(rtm, addrs[RTAX_GATEWAY],
947 				    addrs[RTAX_DST], addrs[RTAX_NETMASK]);
948 		}
949 		break;
950 
951 	  case RTM_ADD:
952 		mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
953 		if (rtm->rtm_flags & RTF_LLINFO) {
954 			if (addrs[RTAX_DST] == NULL ||
955 			    addrs[RTAX_GATEWAY] == NULL ||
956 			    addrs[RTAX_DST]->sa_family != AF_INET ||
957 			    addrs[RTAX_GATEWAY]->sa_family != AF_LINK)
958 				break;
959 			process_arp(rtm,
960 			    (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY],
961 			    (struct sockaddr_in *)(void *)addrs[RTAX_DST]);
962 		} else {
963 			if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP))
964 				mib_sroute_process(rtm, addrs[RTAX_GATEWAY],
965 				    addrs[RTAX_DST], addrs[RTAX_NETMASK]);
966 		}
967 		break;
968 
969 	  case RTM_DELETE:
970 		mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
971 		if (rtm->rtm_errno == 0 && !(rtm->rtm_flags & RTF_LLINFO))
972 			mib_sroute_process(rtm, addrs[RTAX_GATEWAY],
973 			    addrs[RTAX_DST], addrs[RTAX_NETMASK]);
974 		break;
975 	}
976 }
977 
978 /*
979  * send a routing message
980  */
981 void
982 mib_send_rtmsg(struct rt_msghdr *rtm, struct sockaddr *gw,
983     struct sockaddr *dst, struct sockaddr *mask)
984 {
985 	size_t len;
986 	struct rt_msghdr *msg;
987 	char *cp;
988 	ssize_t sent;
989 
990 	len = sizeof(*rtm) + SA_SIZE(gw) + SA_SIZE(dst) + SA_SIZE(mask);
991 	if ((msg = malloc(len)) == NULL) {
992 		syslog(LOG_ERR, "%s: %m", __func__);
993 		return;
994 	}
995 	cp = (char *)(msg + 1);
996 
997 	memset(msg, 0, sizeof(*msg));
998 	msg->rtm_flags = 0;
999 	msg->rtm_version = RTM_VERSION;
1000 	msg->rtm_addrs = RTA_DST | RTA_GATEWAY;
1001 
1002 	memcpy(cp, dst, SA_SIZE(dst));
1003 	cp += SA_SIZE(dst);
1004 	memcpy(cp, gw, SA_SIZE(gw));
1005 	cp += SA_SIZE(gw);
1006 	if (mask != NULL) {
1007 		memcpy(cp, mask, SA_SIZE(mask));
1008 		cp += SA_SIZE(mask);
1009 		msg->rtm_addrs |= RTA_NETMASK;
1010 	}
1011 	msg->rtm_msglen = cp - (char *)msg;
1012 	msg->rtm_type = RTM_GET;
1013 	if ((sent = write(route, msg, msg->rtm_msglen)) == -1) {
1014 		syslog(LOG_ERR, "%s: write: %m", __func__);
1015 		free(msg);
1016 		return;
1017 	}
1018 	if (sent != msg->rtm_msglen) {
1019 		syslog(LOG_ERR, "%s: short write", __func__);
1020 		free(msg);
1021 		return;
1022 	}
1023 	free(msg);
1024 }
1025 
1026 /*
1027  * Fetch the routing table via sysctl
1028  */
1029 u_char *
1030 mib_fetch_rtab(int af, int info, int arg, size_t *lenp)
1031 {
1032 	int name[6];
1033 	u_char *buf;
1034 
1035 	name[0] = CTL_NET;
1036 	name[1] = PF_ROUTE;
1037 	name[2] = 0;
1038 	name[3] = af;
1039 	name[4] = info;
1040 	name[5] = arg;
1041 
1042 	*lenp = 0;
1043 
1044 	if (sysctl(name, 6, NULL, lenp, NULL, 0) == -1) {
1045 		syslog(LOG_ERR, "sysctl estimate (%d,%d,%d,%d,%d,%d): %m",
1046 		    name[0], name[1], name[2], name[3], name[4], name[5]);
1047 		return (NULL);
1048 	}
1049 	if (*lenp == 0)
1050 		return (NULL);
1051 
1052 	if ((buf = malloc(*lenp)) == NULL) {
1053 		syslog(LOG_ERR, "sysctl buffer: %m");
1054 		return (NULL);
1055 	}
1056 
1057 	if (sysctl(name, 6, buf, lenp, NULL, 0) == -1) {
1058 		syslog(LOG_ERR, "sysctl get: %m");
1059 		free(buf);
1060 		return (NULL);
1061 	}
1062 
1063 	return (buf);
1064 }
1065 
1066 /*
1067  * Update the following info: interface, interface addresses, interface
1068  * receive addresses, arp-table.
1069  * This does not change the interface list itself.
1070  */
1071 static void
1072 update_ifa_info(void)
1073 {
1074 	u_char *buf, *next;
1075 	struct rt_msghdr *rtm;
1076 	struct mibifa *ifa, *ifa1;
1077 	struct mibrcvaddr *rcv, *rcv1;
1078 	size_t needed;
1079 	static const int infos[][3] = {
1080 		{ 0, NET_RT_IFLIST, 0 },
1081 #ifdef NET_RT_IFMALIST
1082 		{ AF_LINK, NET_RT_IFMALIST, 0 },
1083 #endif
1084 	};
1085 	u_int i;
1086 
1087 	TAILQ_FOREACH(ifa, &mibifa_list, link)
1088 		ifa->flags &= ~MIBIFA_FOUND;
1089 	TAILQ_FOREACH(rcv, &mibrcvaddr_list, link)
1090 		rcv->flags &= ~MIBRCVADDR_FOUND;
1091 
1092 	for (i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) {
1093 		if ((buf = mib_fetch_rtab(infos[i][0], infos[i][1], infos[i][2],
1094 		   &needed)) == NULL)
1095 			continue;
1096 
1097 		next = buf;
1098 		while (next < buf + needed) {
1099 			rtm = (struct rt_msghdr *)(void *)next;
1100 			next += rtm->rtm_msglen;
1101 			handle_rtmsg(rtm);
1102 		}
1103 		free(buf);
1104 	}
1105 
1106 	/*
1107 	 * Purge the address list of unused entries. These may happen for
1108 	 * interface aliases that are on the same subnet. We don't receive
1109 	 * routing socket messages for them.
1110 	 */
1111 	ifa = TAILQ_FIRST(&mibifa_list);
1112 	while (ifa != NULL) {
1113 		ifa1 = TAILQ_NEXT(ifa, link);
1114 		if (!(ifa->flags & MIBIFA_FOUND))
1115 			destroy_ifa(ifa);
1116 		ifa = ifa1;
1117 	}
1118 
1119 	rcv = TAILQ_FIRST(&mibrcvaddr_list);
1120 	while (rcv != NULL) {
1121 		rcv1 = TAILQ_NEXT(rcv, link);
1122 		if (!(rcv->flags & (MIBRCVADDR_FOUND | MIBRCVADDR_BCAST |
1123 		    MIBRCVADDR_HW)))
1124 			mib_rcvaddr_delete(rcv);
1125 		rcv = rcv1;
1126 	}
1127 }
1128 
1129 /*
1130  * Update arp table
1131  */
1132 void
1133 mib_arp_update(void)
1134 {
1135 	struct mibarp *at, *at1;
1136 	size_t needed;
1137 	u_char *buf, *next;
1138 	struct rt_msghdr *rtm;
1139 
1140 	if (in_update_arp)
1141 		return;		/* Aaargh */
1142 	in_update_arp = 1;
1143 
1144 	TAILQ_FOREACH(at, &mibarp_list, link)
1145 		at->flags &= ~MIBARP_FOUND;
1146 
1147 	if ((buf = mib_fetch_rtab(AF_INET, NET_RT_FLAGS, RTF_LLINFO, &needed)) == NULL) {
1148 		in_update_arp = 0;
1149 		return;
1150 	}
1151 
1152 	next = buf;
1153 	while (next < buf + needed) {
1154 		rtm = (struct rt_msghdr *)(void *)next;
1155 		next += rtm->rtm_msglen;
1156 		handle_rtmsg(rtm);
1157 	}
1158 	free(buf);
1159 
1160 	at = TAILQ_FIRST(&mibarp_list);
1161 	while (at != NULL) {
1162 		at1 = TAILQ_NEXT(at, link);
1163 		if (!(at->flags & MIBARP_FOUND))
1164 			mib_arp_delete(at);
1165 		at = at1;
1166 	}
1167 	mibarpticks = get_ticks();
1168 	update_arp = 0;
1169 	in_update_arp = 0;
1170 }
1171 
1172 
1173 /*
1174  * Intput on the routing socket.
1175  */
1176 static void
1177 route_input(int fd, void *udata __unused)
1178 {
1179 	u_char	buf[1024 * 16];
1180 	ssize_t n;
1181 	struct rt_msghdr *rtm;
1182 
1183 	if ((n = read(fd, buf, sizeof(buf))) == -1)
1184 		err(1, "read(rt_socket)");
1185 
1186 	if (n == 0)
1187 		errx(1, "EOF on rt_socket");
1188 
1189 	rtm = (struct rt_msghdr *)(void *)buf;
1190 	if ((size_t)n != rtm->rtm_msglen)
1191 		errx(1, "n=%zu, rtm_msglen=%u", (size_t)n, rtm->rtm_msglen);
1192 
1193 	handle_rtmsg(rtm);
1194 }
1195 
1196 /*
1197  * execute and SIOCAIFADDR
1198  */
1199 static int
1200 siocaifaddr(char *ifname, struct in_addr addr, struct in_addr mask,
1201     struct in_addr bcast)
1202 {
1203 	struct ifaliasreq addreq;
1204 	struct sockaddr_in *sa;
1205 
1206 	memset(&addreq, 0, sizeof(addreq));
1207 	strncpy(addreq.ifra_name, ifname, sizeof(addreq.ifra_name));
1208 
1209 	sa = (struct sockaddr_in *)(void *)&addreq.ifra_addr;
1210 	sa->sin_family = AF_INET;
1211 	sa->sin_len = sizeof(*sa);
1212 	sa->sin_addr = addr;
1213 
1214 	sa = (struct sockaddr_in *)(void *)&addreq.ifra_mask;
1215 	sa->sin_family = AF_INET;
1216 	sa->sin_len = sizeof(*sa);
1217 	sa->sin_addr = mask;
1218 
1219 	sa = (struct sockaddr_in *)(void *)&addreq.ifra_broadaddr;
1220 	sa->sin_family = AF_INET;
1221 	sa->sin_len = sizeof(*sa);
1222 	sa->sin_addr = bcast;
1223 
1224 	return (ioctl(mib_netsock, SIOCAIFADDR, &addreq));
1225 }
1226 
1227 /*
1228  * Exececute a SIOCDIFADDR
1229  */
1230 static int
1231 siocdifaddr(const char *ifname, struct in_addr addr)
1232 {
1233 	struct ifreq delreq;
1234 	struct sockaddr_in *sa;
1235 
1236 	memset(&delreq, 0, sizeof(delreq));
1237 	strncpy(delreq.ifr_name, ifname, sizeof(delreq.ifr_name));
1238 	sa = (struct sockaddr_in *)(void *)&delreq.ifr_addr;
1239 	sa->sin_family = AF_INET;
1240 	sa->sin_len = sizeof(*sa);
1241 	sa->sin_addr = addr;
1242 
1243 	return (ioctl(mib_netsock, SIOCDIFADDR, &delreq));
1244 }
1245 
1246 /*
1247  * Verify an interface address without fetching the entire list
1248  */
1249 static int
1250 verify_ifa(const char *name, struct mibifa *ifa)
1251 {
1252 	struct ifreq req;
1253 	struct sockaddr_in *sa;
1254 
1255 	memset(&req, 0, sizeof(req));
1256 	strncpy(req.ifr_name, name, sizeof(req.ifr_name));
1257 	sa = (struct sockaddr_in *)(void *)&req.ifr_addr;
1258 	sa->sin_family = AF_INET;
1259 	sa->sin_len = sizeof(*sa);
1260 	sa->sin_addr = ifa->inaddr;
1261 
1262 	if (ioctl(mib_netsock, SIOCGIFADDR, &req) == -1)
1263 		return (-1);
1264 	if (ifa->inaddr.s_addr != sa->sin_addr.s_addr) {
1265 		syslog(LOG_ERR, "%s: address mismatch", __func__);
1266 		return (-1);
1267 	}
1268 
1269 	if (ioctl(mib_netsock, SIOCGIFNETMASK, &req) == -1)
1270 		return (-1);
1271 	if (ifa->inmask.s_addr != sa->sin_addr.s_addr) {
1272 		syslog(LOG_ERR, "%s: netmask mismatch", __func__);
1273 		return (-1);
1274 	}
1275 	return (0);
1276 }
1277 
1278 /*
1279  * Restore a deleted interface address. Don't wait for the routing socket
1280  * to update us.
1281  */
1282 void
1283 mib_undestroy_ifa(struct mibifa *ifa)
1284 {
1285 	struct mibif *ifp;
1286 
1287 	if ((ifp = mib_find_if(ifa->ifindex)) == NULL)
1288 		/* keep it destroyed */
1289 		return;
1290 
1291 	if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast))
1292 		/* keep it destroyed */
1293 		return;
1294 
1295 	ifa->flags &= ~MIBIFA_DESTROYED;
1296 }
1297 
1298 /*
1299  * Destroy an interface address
1300  */
1301 int
1302 mib_destroy_ifa(struct mibifa *ifa)
1303 {
1304 	struct mibif *ifp;
1305 
1306 	if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1307 		/* ups. */
1308 		mib_iflist_bad = 1;
1309 		return (-1);
1310 	}
1311 	if (siocdifaddr(ifp->name, ifa->inaddr)) {
1312 		/* ups. */
1313 		syslog(LOG_ERR, "SIOCDIFADDR: %m");
1314 		mib_iflist_bad = 1;
1315 		return (-1);
1316 	}
1317 	ifa->flags |= MIBIFA_DESTROYED;
1318 	return (0);
1319 }
1320 
1321 /*
1322  * Rollback the modification of an address. Don't bother to wait for
1323  * the routing socket.
1324  */
1325 void
1326 mib_unmodify_ifa(struct mibifa *ifa)
1327 {
1328 	struct mibif *ifp;
1329 
1330 	if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1331 		/* ups. */
1332 		mib_iflist_bad = 1;
1333 		return;
1334 	}
1335 
1336 	if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) {
1337 		/* ups. */
1338 		mib_iflist_bad = 1;
1339 		return;
1340 	}
1341 }
1342 
1343 /*
1344  * Modify an IFA.
1345  */
1346 int
1347 mib_modify_ifa(struct mibifa *ifa)
1348 {
1349 	struct mibif *ifp;
1350 
1351 	if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1352 		/* ups. */
1353 		mib_iflist_bad = 1;
1354 		return (-1);
1355 	}
1356 
1357 	if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) {
1358 		/* ups. */
1359 		mib_iflist_bad = 1;
1360 		return (-1);
1361 	}
1362 
1363 	if (verify_ifa(ifp->name, ifa)) {
1364 		/* ups. */
1365 		mib_iflist_bad = 1;
1366 		return (-1);
1367 	}
1368 
1369 	return (0);
1370 }
1371 
1372 /*
1373  * Destroy a freshly created interface address. Don't bother to wait for
1374  * the routing socket.
1375  */
1376 void
1377 mib_uncreate_ifa(struct mibifa *ifa)
1378 {
1379 	struct mibif *ifp;
1380 
1381 	if ((ifp = mib_find_if(ifa->ifindex)) == NULL) {
1382 		/* ups. */
1383 		mib_iflist_bad = 1;
1384 		return;
1385 	}
1386 	if (siocdifaddr(ifp->name, ifa->inaddr)) {
1387 		/* ups. */
1388 		mib_iflist_bad = 1;
1389 		return;
1390 	}
1391 
1392 	destroy_ifa(ifa);
1393 }
1394 
1395 /*
1396  * Create a new ifa and verify it
1397  */
1398 struct mibifa *
1399 mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask,
1400     struct in_addr bcast)
1401 {
1402 	struct mibif *ifp;
1403 	struct mibifa *ifa;
1404 
1405 	if ((ifp = mib_find_if(ifindex)) == NULL)
1406 		return (NULL);
1407 	if ((ifa = alloc_ifa(ifindex, addr)) == NULL)
1408 		return (NULL);
1409 	ifa->inmask = mask;
1410 	ifa->inbcast = bcast;
1411 
1412 	if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) {
1413 		syslog(LOG_ERR, "%s: %m", __func__);
1414 		destroy_ifa(ifa);
1415 		return (NULL);
1416 	}
1417 	if (verify_ifa(ifp->name, ifa)) {
1418 		destroy_ifa(ifa);
1419 		return (NULL);
1420 	}
1421 	return (ifa);
1422 }
1423 
1424 /*
1425  * Get all cloning interfaces and make them dynamic.
1426  * Hah! Whe should probably do this on a periodic basis (XXX).
1427  */
1428 static void
1429 get_cloners(void)
1430 {
1431 	struct if_clonereq req;
1432 	char *buf, *cp;
1433 	int i;
1434 
1435 	memset(&req, 0, sizeof(req));
1436 	if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) {
1437 		syslog(LOG_ERR, "get cloners: %m");
1438 		return;
1439 	}
1440 	if ((buf = malloc(req.ifcr_total * IFNAMSIZ)) == NULL) {
1441 		syslog(LOG_ERR, "%m");
1442 		return;
1443 	}
1444 	req.ifcr_count = req.ifcr_total;
1445 	req.ifcr_buffer = buf;
1446 	if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) {
1447 		syslog(LOG_ERR, "get cloners: %m");
1448 		free(buf);
1449 		return;
1450 	}
1451 	for (cp = buf, i = 0; i < req.ifcr_total; i++, cp += IFNAMSIZ)
1452 		mib_if_set_dyn(cp);
1453 	free(buf);
1454 }
1455 
1456 /*
1457  * Idle function
1458  */
1459 static void
1460 mibII_idle(void)
1461 {
1462 	struct mibifa *ifa;
1463 
1464 	if (mib_iflist_bad) {
1465 		TAILQ_FOREACH(ifa, &mibifa_list, link)
1466 			ifa->flags &= ~MIBIFA_DESTROYED;
1467 
1468 		/* assume, that all cloning interfaces are dynamic */
1469 		get_cloners();
1470 
1471 		mib_refresh_iflist();
1472 		update_ifa_info();
1473 		mib_arp_update();
1474 		mib_iflist_bad = 0;
1475 	}
1476 	if (update_arp)
1477 		mib_arp_update();
1478 }
1479 
1480 
1481 /*
1482  * Start the module
1483  */
1484 static void
1485 mibII_start(void)
1486 {
1487 	if ((route_fd = fd_select(route, route_input, NULL, module)) == NULL) {
1488 		syslog(LOG_ERR, "fd_select(route): %m");
1489 		return;
1490 	}
1491 	mib_refresh_iflist();
1492 	update_ifa_info();
1493 	mib_arp_update();
1494 	(void)mib_fetch_route();
1495 	mib_iftable_last_change = 0;
1496 	mib_ifstack_last_change = 0;
1497 
1498 	ifmib_reg = or_register(&oid_ifMIB,
1499 	    "The MIB module to describe generic objects for network interface"
1500 	    " sub-layers.", module);
1501 
1502 	ipmib_reg = or_register(&oid_ipMIB,
1503 	   "The MIB module for managing IP and ICMP implementations, but "
1504 	   "excluding their management of IP routes.", module);
1505 
1506 	tcpmib_reg = or_register(&oid_tcpMIB,
1507 	   "The MIB module for managing TCP implementations.", module);
1508 
1509 	udpmib_reg = or_register(&oid_udpMIB,
1510 	   "The MIB module for managing UDP implementations.", module);
1511 
1512 	ipForward_reg = or_register(&oid_ipForward,
1513 	   "The MIB module for the display of CIDR multipath IP Routes.",
1514 	   module);
1515 }
1516 
1517 /*
1518  * Initialize the module
1519  */
1520 static int
1521 mibII_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
1522 {
1523 	size_t len;
1524 
1525 	module = mod;
1526 
1527 	len = sizeof(clockinfo);
1528 	if (sysctlbyname("kern.clockrate", &clockinfo, &len, NULL, 0) == -1) {
1529 		syslog(LOG_ERR, "kern.clockrate: %m");
1530 		return (-1);
1531 	}
1532 	if (len != sizeof(clockinfo)) {
1533 		syslog(LOG_ERR, "kern.clockrate: wrong size");
1534 		return (-1);
1535 	}
1536 
1537 	if ((route = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) {
1538 		syslog(LOG_ERR, "PF_ROUTE: %m");
1539 		return (-1);
1540 	}
1541 
1542 	if ((mib_netsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
1543 		syslog(LOG_ERR, "PF_INET: %m");
1544 		(void)close(route);
1545 		return (-1);
1546 	}
1547 	(void)shutdown(mib_netsock, SHUT_RDWR);
1548 
1549 	/* assume, that all cloning interfaces are dynamic */
1550 	get_cloners();
1551 
1552 	return (0);
1553 }
1554 
1555 static int
1556 mibII_fini(void)
1557 {
1558 	if (route_fd != NULL)
1559 		fd_deselect(route_fd);
1560 	if (route != -1)
1561 		(void)close(route);
1562 	if (mib_netsock != -1)
1563 		(void)close(mib_netsock);
1564 	/* XXX free memory */
1565 
1566 	or_unregister(ipForward_reg);
1567 	or_unregister(udpmib_reg);
1568 	or_unregister(tcpmib_reg);
1569 	or_unregister(ipmib_reg);
1570 	or_unregister(ifmib_reg);
1571 
1572 	return (0);
1573 }
1574 
1575 static void
1576 mibII_loading(const struct lmodule *mod, int loaded)
1577 {
1578 	struct mibif *ifp;
1579 
1580 	if (loaded == 1)
1581 		return;
1582 
1583 	TAILQ_FOREACH(ifp, &mibif_list, link)
1584 		if (ifp->xnotify_mod == mod) {
1585 			ifp->xnotify_mod = NULL;
1586 			ifp->xnotify_data = NULL;
1587 			ifp->xnotify = NULL;
1588 		}
1589 
1590 	mib_unregister_newif(mod);
1591 }
1592 
1593 const struct snmp_module config = {
1594 	"This module implements the interface and ip groups.",
1595 	mibII_init,
1596 	mibII_fini,
1597 	mibII_idle,	/* idle */
1598 	NULL,		/* dump */
1599 	NULL,		/* config */
1600 	mibII_start,
1601 	NULL,
1602 	mibII_ctree,
1603 	mibII_CTREE_SIZE,
1604 	mibII_loading
1605 };
1606 
1607 /*
1608  * Should have a list of these attached to each interface.
1609  */
1610 void *
1611 mibif_notify(struct mibif *ifp, const struct lmodule *mod,
1612     mibif_notify_f func, void *data)
1613 {
1614 	ifp->xnotify = func;
1615 	ifp->xnotify_data = data;
1616 	ifp->xnotify_mod = mod;
1617 
1618 	return (ifp);
1619 }
1620 
1621 void
1622 mibif_unnotify(void *arg)
1623 {
1624 	struct mibif *ifp = arg;
1625 
1626 	ifp->xnotify = NULL;
1627 	ifp->xnotify_data = NULL;
1628 	ifp->xnotify_mod = NULL;
1629 }
1630