146283Sdfr/*	$NetBSD: if.c,v 1.20 2011/12/11 20:44:44 christos Exp $	*/
246283Sdfr/*	$KAME: if.c,v 1.36 2004/11/30 22:32:01 suz Exp $	*/
346283Sdfr
446283Sdfr/*
546283Sdfr * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
646283Sdfr * All rights reserved.
746283Sdfr *
846283Sdfr * Redistribution and use in source and binary forms, with or without
946283Sdfr * modification, are permitted provided that the following conditions
1046283Sdfr * are met:
1146283Sdfr * 1. Redistributions of source code must retain the above copyright
1246283Sdfr *    notice, this list of conditions and the following disclaimer.
1346283Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1446283Sdfr *    notice, this list of conditions and the following disclaimer in the
1546283Sdfr *    documentation and/or other materials provided with the distribution.
1646283Sdfr * 3. Neither the name of the project nor the names of its contributors
1746283Sdfr *    may be used to endorse or promote products derived from this software
1846283Sdfr *    without specific prior written permission.
1946283Sdfr *
2046283Sdfr * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2146283Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2246283Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2346283Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2446283Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2546283Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2646283Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2746283Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2846283Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2946283Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3046283Sdfr * SUCH DAMAGE.
3146283Sdfr */
3246283Sdfr
3346283Sdfr#include <sys/param.h>
3446283Sdfr#include <sys/socket.h>
3546283Sdfr#include <sys/sysctl.h>
3646283Sdfr#include <sys/ioctl.h>
3746283Sdfr#include <net/if.h>
3846283Sdfr#include <net/if_types.h>
3946283Sdfr#include <ifaddrs.h>
4046283Sdfr#include <net/if_ether.h>
4146283Sdfr#include <net/route.h>
4246283Sdfr#include <net/if_dl.h>
4346283Sdfr#include <netinet/in.h>
4446283Sdfr#include <netinet/icmp6.h>
4546283Sdfr#include <unistd.h>
4646283Sdfr#include <errno.h>
4746283Sdfr#include <stdlib.h>
4846283Sdfr#include <string.h>
4946283Sdfr#include <syslog.h>
5046283Sdfr#include "rtadvd.h"
5146283Sdfr#include "if.h"
5246283Sdfr
5346283Sdfr#ifndef RT_ROUNDUP
5446283Sdfr#define RT_ROUNDUP(a)							       \
5546283Sdfr	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
5646283Sdfr#define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
5746283Sdfr#endif
5846283Sdfr
5946283Sdfrstruct if_msghdr **iflist;
6046283Sdfrint iflist_init_ok;
6146283Sdfrsize_t ifblock_size;
6246283Sdfrchar *ifblock;
6346283Sdfr
6446283Sdfrstatic void get_iflist(char **buf, size_t *size);
6546283Sdfrstatic void parse_iflist(struct if_msghdr ***ifmlist_p, char *buf,
6646283Sdfr		       size_t bufsize);
6746283Sdfr
6846283Sdfrstatic void
6946283Sdfrget_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
7046283Sdfr{
7146283Sdfr	int i;
7246283Sdfr
7346283Sdfr	for (i = 0; i < RTAX_MAX; i++) {
7446283Sdfr		if (addrs & (1 << i)) {
7546283Sdfr			rti_info[i] = sa;
7646283Sdfr			RT_ADVANCE(sa, sa);
7746283Sdfr		}
7846283Sdfr		else
7946283Sdfr			rti_info[i] = NULL;
8046283Sdfr	}
8146283Sdfr}
8246283Sdfr
8346283Sdfrstruct sockaddr_dl *
8446283Sdfrif_nametosdl(const char *name)
8546283Sdfr{
8646283Sdfr	struct ifaddrs *ifap, *ifa;
8746283Sdfr	struct sockaddr_dl *sdl;
8846283Sdfr
8946283Sdfr	if (getifaddrs(&ifap) != 0)
9046283Sdfr		return (NULL);
9146283Sdfr
9246283Sdfr	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
9346283Sdfr		if (strcmp(ifa->ifa_name, name) != 0)
9446283Sdfr			continue;
9546283Sdfr		if (ifa->ifa_addr->sa_family != AF_LINK)
9646283Sdfr			continue;
9746283Sdfr
9846283Sdfr		sdl = malloc(ifa->ifa_addr->sa_len);
9946283Sdfr		if (!sdl)
10046283Sdfr			continue;	/*XXX*/
10146283Sdfr
10246283Sdfr		memcpy(sdl, ifa->ifa_addr, ifa->ifa_addr->sa_len);
10346283Sdfr		freeifaddrs(ifap);
10446283Sdfr		return (sdl);
10546283Sdfr	}
10646283Sdfr
10746283Sdfr	freeifaddrs(ifap);
10846283Sdfr	return (NULL);
10946283Sdfr}
11046283Sdfr
11146283Sdfrint
11246283Sdfrif_getmtu(const char *name)
11346283Sdfr{
11446283Sdfr	struct ifaddrs *ifap, *ifa;
11546283Sdfr	struct if_data *ifd;
11646283Sdfr	u_long mtu = 0;
11746283Sdfr
11846283Sdfr	if (getifaddrs(&ifap) < 0)
11946283Sdfr		return(0);
12046283Sdfr	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
12146283Sdfr		if (strcmp(ifa->ifa_name, name) == 0) {
12246283Sdfr			ifd = ifa->ifa_data;
12346283Sdfr			if (ifd)
12446283Sdfr				mtu = ifd->ifi_mtu;
12546283Sdfr			break;
12646283Sdfr		}
12746283Sdfr	}
12846283Sdfr	freeifaddrs(ifap);
12946283Sdfr
13046283Sdfr#ifdef SIOCGIFMTU		/* XXX: this ifdef may not be necessary */
13146283Sdfr	if (mtu == 0) {
13246283Sdfr		struct ifreq ifr;
13346283Sdfr		int s;
13446283Sdfr
13546283Sdfr		if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
13646283Sdfr			return(0);
13746283Sdfr
13846283Sdfr		ifr.ifr_addr.sa_family = AF_INET6;
13946283Sdfr		strncpy(ifr.ifr_name, name,
14046283Sdfr			sizeof(ifr.ifr_name));
14146283Sdfr		if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
14246283Sdfr			close(s);
14346283Sdfr			return(0);
14446283Sdfr		}
14546283Sdfr		close(s);
14646283Sdfr
14746283Sdfr		mtu = ifr.ifr_mtu;
14846283Sdfr	}
14946283Sdfr#endif
15046283Sdfr
15146283Sdfr	return(mtu);
15246283Sdfr}
15346283Sdfr
15446283Sdfr/* give interface index and its old flags, then new flags returned */
15546283Sdfrint
15646283Sdfrif_getflags(int ifindex, int oifflags)
15746283Sdfr{
15846283Sdfr	struct ifreq ifr;
15946283Sdfr	int s;
16046283Sdfr
16146283Sdfr	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
16246283Sdfr		syslog(LOG_ERR, "<%s> socket: %s", __func__,
16346283Sdfr		       strerror(errno));
16446283Sdfr		return (oifflags & ~IFF_UP);
16546283Sdfr	}
16646283Sdfr
16746283Sdfr	if_indextoname(ifindex, ifr.ifr_name);
16846283Sdfr	if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
16946283Sdfr		syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s",
17046283Sdfr		       __func__, ifr.ifr_name);
17146283Sdfr		close(s);
17246283Sdfr		return (oifflags & ~IFF_UP);
17346283Sdfr	}
17446283Sdfr	close(s);
17546283Sdfr	return (ifr.ifr_flags);
17646283Sdfr}
17746283Sdfr
17846283Sdfr#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
17946283Sdfrint
18046283Sdfrlladdropt_length(struct sockaddr_dl *sdl)
18146283Sdfr{
18246283Sdfr	switch (sdl->sdl_type) {
18346283Sdfr	case IFT_ETHER:
18446283Sdfr	case IFT_FDDI:
18546283Sdfr		return(ROUNDUP8(ETHER_ADDR_LEN + 2));
18646283Sdfr	default:
18746283Sdfr		return(0);
18846283Sdfr	}
18946283Sdfr}
19046283Sdfr
19146283Sdfrvoid
19246283Sdfrlladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
19346283Sdfr{
19446283Sdfr	char *addr;
19546283Sdfr
19646283Sdfr	ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
19746283Sdfr
19846283Sdfr	switch (sdl->sdl_type) {
19946283Sdfr	case IFT_ETHER:
20046283Sdfr	case IFT_FDDI:
20146283Sdfr		ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
20246283Sdfr		addr = (char *)(ndopt + 1);
20346283Sdfr		memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
20446283Sdfr		break;
20546283Sdfr	default:
20646283Sdfr		syslog(LOG_ERR, "<%s> unsupported link type(%d)",
20746283Sdfr		    __func__, sdl->sdl_type);
20846283Sdfr		exit(1);
20946283Sdfr	}
21046283Sdfr
21146283Sdfr	return;
21246283Sdfr}
21346283Sdfr
21446283Sdfr#define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
21546283Sdfr#define SIN6(s) ((struct sockaddr_in6 *)(s))
21646283Sdfr#define SDL(s) ((struct sockaddr_dl *)(s))
21746283Sdfrchar *
21846283Sdfrget_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
21946283Sdfr{
22046283Sdfr	struct rt_msghdr *rtm;
22146283Sdfr	struct ifa_msghdr *ifam;
22246283Sdfr	struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];
22346283Sdfr
22446283Sdfr	*lenp = 0;
22546283Sdfr	for (rtm = (struct rt_msghdr *)buf;
22646283Sdfr	     rtm < (struct rt_msghdr *)lim;
22746283Sdfr	     rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
22846283Sdfr		/* just for safety */
22946283Sdfr		if (!rtm->rtm_msglen) {
23046283Sdfr			syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
23146283Sdfr				"(buf=%p lim=%p rtm=%p)", __func__,
23246283Sdfr				buf, lim, rtm);
23346283Sdfr			break;
23446283Sdfr		}
23546283Sdfr		if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
23646283Sdfr			continue;
23746283Sdfr		}
23846283Sdfr
23946283Sdfr		switch (rtm->rtm_type) {
24046283Sdfr		case RTM_GET:
24146283Sdfr		case RTM_ADD:
24246283Sdfr		case RTM_DELETE:
24346283Sdfr			/* address related checks */
24446283Sdfr			sa = (struct sockaddr *)(rtm + 1);
24546283Sdfr			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
24646283Sdfr			if ((dst = rti_info[RTAX_DST]) == NULL ||
24746283Sdfr			    dst->sa_family != AF_INET6)
24846283Sdfr				continue;
24946283Sdfr
25046283Sdfr			if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
25146283Sdfr			    IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
25246283Sdfr				continue;
25346283Sdfr
25446283Sdfr			if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
25546283Sdfr			    gw->sa_family != AF_LINK)
25646283Sdfr				continue;
25746283Sdfr			if (ifindex && SDL(gw)->sdl_index != ifindex)
25846283Sdfr				continue;
25946283Sdfr
26046283Sdfr			if (rti_info[RTAX_NETMASK] == NULL)
26146283Sdfr				continue;
262130803Smarcel
26346283Sdfr			/* found */
26446283Sdfr			*lenp = rtm->rtm_msglen;
26546283Sdfr			return (char *)rtm;
26646283Sdfr			/* NOTREACHED */
26746283Sdfr		case RTM_NEWADDR:
26846283Sdfr		case RTM_DELADDR:
26946283Sdfr			ifam = (struct ifa_msghdr *)rtm;
27046283Sdfr
27146283Sdfr			/* address related checks */
27246283Sdfr			sa = (struct sockaddr *)(ifam + 1);
27346283Sdfr			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
27446283Sdfr			if ((ifa = rti_info[RTAX_IFA]) == NULL ||
27546283Sdfr			    (ifa->sa_family != AF_INET &&
27646283Sdfr			     ifa->sa_family != AF_INET6))
27746283Sdfr				continue;
27846283Sdfr
27946283Sdfr			if (ifa->sa_family == AF_INET6 &&
28046283Sdfr			    (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
28146283Sdfr			     IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
28246283Sdfr				continue;
28346283Sdfr
28446283Sdfr			if (ifindex && ifam->ifam_index != ifindex)
28546283Sdfr				continue;
28646283Sdfr
28746283Sdfr			/* found */
28846283Sdfr			*lenp = ifam->ifam_msglen;
28946283Sdfr			return (char *)rtm;
29046283Sdfr			/* NOTREACHED */
29146283Sdfr		case RTM_IFINFO:
29246283Sdfr			/* found */
29346283Sdfr			*lenp = rtm->rtm_msglen;
29446283Sdfr			return (char *)rtm;
29546283Sdfr			/* NOTREACHED */
29646283Sdfr		}
29746283Sdfr	}
29846283Sdfr
29946283Sdfr	return (char *)rtm;
30046283Sdfr}
30146283Sdfr#undef FILTER_MATCH
30246283Sdfr
30346283Sdfrstruct in6_addr *
30446283Sdfrget_addr(char *buf)
30546283Sdfr{
30646283Sdfr	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
30746283Sdfr	struct sockaddr *sa, *rti_info[RTAX_MAX];
30846283Sdfr
30946283Sdfr	sa = (struct sockaddr *)(rtm + 1);
31046283Sdfr	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
31146283Sdfr
31246283Sdfr	return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
31346283Sdfr}
31446283Sdfr
31546283Sdfrint
31646283Sdfrget_rtm_ifindex(char *buf)
31746283Sdfr{
31846283Sdfr	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
31946283Sdfr	struct sockaddr *sa, *rti_info[RTAX_MAX];
32046283Sdfr
32146283Sdfr	sa = (struct sockaddr *)(rtm + 1);
32246283Sdfr	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
32346283Sdfr
32446283Sdfr	return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
32546283Sdfr}
32646283Sdfr
32746283Sdfrint
32846283Sdfrget_ifm_ifindex(char *buf)
32946283Sdfr{
33046283Sdfr	struct if_msghdr *ifm = (struct if_msghdr *)buf;
33146283Sdfr
33246283Sdfr	return ((int)ifm->ifm_index);
33346283Sdfr}
33446283Sdfr
33546283Sdfrint
33646283Sdfrget_ifam_ifindex(char *buf)
33746283Sdfr{
33846283Sdfr	struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf;
33946283Sdfr
34046283Sdfr	return ((int)ifam->ifam_index);
34146283Sdfr}
34246283Sdfr
34346283Sdfrint
34446283Sdfrget_ifm_flags(char *buf)
34546283Sdfr{
34646283Sdfr	struct if_msghdr *ifm = (struct if_msghdr *)buf;
34746283Sdfr
34846283Sdfr	return (ifm->ifm_flags);
34946283Sdfr}
35046283Sdfr
35146283Sdfrint
35246283Sdfrget_prefixlen(char *buf)
35346283Sdfr{
35446283Sdfr	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
35546283Sdfr	struct sockaddr *sa, *rti_info[RTAX_MAX];
35646283Sdfr	unsigned char *p, *lim;
35746283Sdfr
35846283Sdfr	sa = (struct sockaddr *)(rtm + 1);
35946283Sdfr	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
36046283Sdfr	sa = rti_info[RTAX_NETMASK];
36146283Sdfr
36246283Sdfr	p = (unsigned char *)(&SIN6(sa)->sin6_addr);
36346283Sdfr	lim = (unsigned char *)sa + sa->sa_len;
36446283Sdfr	return prefixlen(p, lim);
36546283Sdfr}
36646283Sdfr
36746283Sdfrint
36846283Sdfrprefixlen(const unsigned char *p, const unsigned char *lim)
36946283Sdfr{
37046283Sdfr	int masklen;
37146283Sdfr
37246283Sdfr	for (masklen = 0; p < lim; p++) {
37346283Sdfr		switch (*p) {
37446283Sdfr		case 0xff:
37546283Sdfr			masklen += 8;
37646283Sdfr			break;
37746283Sdfr		case 0xfe:
37846283Sdfr			masklen += 7;
37946283Sdfr			break;
38046283Sdfr		case 0xfc:
38146283Sdfr			masklen += 6;
38246283Sdfr			break;
38346283Sdfr		case 0xf8:
38446283Sdfr			masklen += 5;
38546283Sdfr			break;
38646283Sdfr		case 0xf0:
38746283Sdfr			masklen += 4;
38846283Sdfr			break;
38946283Sdfr		case 0xe0:
39046283Sdfr			masklen += 3;
39146283Sdfr			break;
39246283Sdfr		case 0xc0:
39346283Sdfr			masklen += 2;
39446283Sdfr			break;
39546283Sdfr		case 0x80:
39646283Sdfr			masklen += 1;
39746283Sdfr			break;
39846283Sdfr		case 0x00:
39946283Sdfr			break;
40046283Sdfr		default:
40146283Sdfr			return(-1);
40246283Sdfr		}
40346283Sdfr	}
40446283Sdfr
40546283Sdfr	return(masklen);
40646283Sdfr}
40746283Sdfr
40846283Sdfrint
40946283Sdfrrtmsg_type(char *buf)
41046283Sdfr{
41146283Sdfr	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
41246283Sdfr
41346283Sdfr	return(rtm->rtm_type);
41446283Sdfr}
41546283Sdfr
41646283Sdfrint
41746283Sdfrrtmsg_len(char *buf)
41846283Sdfr{
41946283Sdfr	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
42046283Sdfr
42146283Sdfr	return(rtm->rtm_msglen);
42246283Sdfr}
42346283Sdfr
42446283Sdfrint
42546283Sdfrifmsg_len(char *buf)
42646283Sdfr{
42746283Sdfr	struct if_msghdr *ifm = (struct if_msghdr *)buf;
42846283Sdfr
42946283Sdfr	return(ifm->ifm_msglen);
43046283Sdfr}
43146283Sdfr
43246283Sdfr/*
43346283Sdfr * alloc buffer and get if_msghdrs block from kernel,
43446283Sdfr * and put them into the buffer
43546283Sdfr */
43646283Sdfrstatic void
43746283Sdfrget_iflist(char **buf, size_t *size)
43846283Sdfr{
43946283Sdfr	int mib[6];
44046283Sdfr
44146283Sdfr	mib[0] = CTL_NET;
44246283Sdfr	mib[1] = PF_ROUTE;
44346283Sdfr	mib[2] = 0;
44446283Sdfr	mib[3] = AF_INET6;
44546283Sdfr	mib[4] = NET_RT_IFLIST;
44646283Sdfr	mib[5] = 0;
44746283Sdfr
44846283Sdfr	if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
44946283Sdfr		syslog(LOG_ERR, "<%s> sysctl: iflist size get failed",
45046283Sdfr		       __func__);
45146283Sdfr		exit(1);
45246283Sdfr	}
45346283Sdfr	if ((*buf = malloc(*size)) == NULL) {
45446283Sdfr		syslog(LOG_ERR, "<%s> malloc failed", __func__);
45546283Sdfr		exit(1);
45646283Sdfr	}
45746283Sdfr	if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
45846283Sdfr		syslog(LOG_ERR, "<%s> sysctl: iflist get failed",
45946283Sdfr		       __func__);
46046283Sdfr		exit(1);
46146283Sdfr	}
46246283Sdfr	return;
46346283Sdfr}
46446283Sdfr
46546283Sdfr/*
46646283Sdfr * alloc buffer and parse if_msghdrs block passed as arg,
46746283Sdfr * and init the buffer as list of pointers ot each of the if_msghdr.
46846283Sdfr */
46946283Sdfrstatic void
47046283Sdfrparse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
47146283Sdfr{
47246283Sdfr	int iflentry_size, malloc_size;
47346283Sdfr	struct if_msghdr *ifm;
47446283Sdfr	struct ifa_msghdr *ifam;
47546283Sdfr	char *lim;
47646283Sdfr
47746283Sdfr	/*
47846283Sdfr	 * Estimate least size of an iflist entry, to be obtained from kernel.
47946283Sdfr	 * Should add sizeof(sockaddr) ??
48046283Sdfr	 */
48146283Sdfr	iflentry_size = sizeof(struct if_msghdr);
48246283Sdfr	/* roughly estimate max list size of pointers to each if_msghdr */
48346283Sdfr	malloc_size = (bufsize/iflentry_size) * sizeof(void *);
48446283Sdfr	if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) {
48546283Sdfr		syslog(LOG_ERR, "<%s> malloc failed", __func__);
48646283Sdfr		exit(1);
48746283Sdfr	}
48846283Sdfr
48946283Sdfr	lim = buf + bufsize;
49046283Sdfr	for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
49146283Sdfr		if (ifm->ifm_msglen == 0) {
49246283Sdfr			syslog(LOG_WARNING, "<%s> ifm_msglen is 0 "
49346283Sdfr			       "(buf=%p lim=%p ifm=%p)", __func__,
49446283Sdfr			       buf, lim, ifm);
49546283Sdfr			return;
49646283Sdfr		}
49798944Sobrien
49846283Sdfr		if (ifm->ifm_type == RTM_IFINFO) {
49946283Sdfr			(*ifmlist_p)[ifm->ifm_index] = ifm;
50046283Sdfr		} else {
50146283Sdfr			syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"
50246283Sdfr			       "expected %d, got %d\n msglen = %d\n"
50346283Sdfr			       "buf:%p, ifm:%p, lim:%p\n",
50446283Sdfr			       RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
50546283Sdfr			       buf, ifm, lim);
50646283Sdfr			exit (1);
50746283Sdfr		}
50846283Sdfr		for (ifam = (struct ifa_msghdr *)
50946283Sdfr			((char *)ifm + ifm->ifm_msglen);
51046283Sdfr		     ifam < (struct ifa_msghdr *)lim;
51146283Sdfr		     ifam = (struct ifa_msghdr *)
51246283Sdfr		     	((char *)ifam + ifam->ifam_msglen)) {
51346283Sdfr			/* just for safety */
51446283Sdfr			if (!ifam->ifam_msglen) {
51546283Sdfr				syslog(LOG_WARNING, "<%s> ifa_msglen is 0 "
51646283Sdfr				       "(buf=%p lim=%p ifam=%p)", __func__,
51746283Sdfr				       buf, lim, ifam);
51846283Sdfr				return;
51946283Sdfr			}
52046283Sdfr			if (ifam->ifam_type != RTM_NEWADDR)
52146283Sdfr				break;
52246283Sdfr		}
52346283Sdfr		ifm = (struct if_msghdr *)ifam;
52446283Sdfr	}
52546283Sdfr}
52646283Sdfr
52746283Sdfrvoid
52846283Sdfrinit_iflist()
52946283Sdfr{
53046283Sdfr	if (ifblock) {
53146283Sdfr		free(ifblock);
53246283Sdfr		ifblock_size = 0;
53346283Sdfr	}
53446283Sdfr	if (iflist)
53546283Sdfr		free(iflist);
53646283Sdfr	/* get iflist block from kernel */
53746283Sdfr	get_iflist(&ifblock, &ifblock_size);
53846283Sdfr
53946283Sdfr	/* make list of pointers to each if_msghdr */
54046283Sdfr	parse_iflist(&iflist, ifblock, ifblock_size);
54146283Sdfr}
54246283Sdfr