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