19014a6epfg/*-
29014a6epfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
39014a6epfg *
447c129abms * Copyright (c) 2003 Bruce M. Simpson.
547c129abms * All rights reserved
647c129abms *
747c129abms * Redistribution and use in source and binary forms, with or without
847c129abms * modification, are permitted provided that the following conditions
947c129abms * are met:
1047c129abms * 1. Redistributions of source code must retain the above copyright
1147c129abms *    notice, this list of conditions and the following disclaimer.
1247c129abms * 2. Redistributions in binary form must reproduce the above copyright
1347c129abms *    notice, this list of conditions and the following disclaimer in the
1447c129abms *    documentation and/or other materials provided with the distribution.
1547c129abms *
16c454bafemaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17c454bafemaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c454bafemaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c454bafemaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20c454bafemaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c454bafemaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c454bafemaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c454bafemaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c454bafemaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c454bafemaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c454bafemaste * SUCH DAMAGE.
2747c129abms */
2847c129abms
2947c129abms#include <sys/cdefs.h>
3047c129abms__FBSDID("$FreeBSD$");
3147c129abms
3247c129abms#include "namespace.h"
3347c129abms#include <sys/param.h>
3447c129abms#include <sys/sysctl.h>
3547c129abms#include <sys/ioctl.h>
3647c129abms#include <sys/socket.h>
3747c129abms#include <net/if.h>
3847c129abms#include <net/if_dl.h>
3947c129abms#include <net/route.h>
4047c129abms
4147c129abms#include <errno.h>
4247c129abms#include <ifaddrs.h>
4347c129abms#include <stdlib.h>
4447c129abms#include <string.h>
4547c129abms#include "un-namespace.h"
4647c129abms
4747c129abms#define	SALIGN	(sizeof(long) - 1)
4847c129abms#define	SA_RLEN(sa)	((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
4947c129abms			    (SALIGN + 1))
5047c129abms#define	MAX_SYSCTL_TRY	5
5147c129abms#define	RTA_MASKS	(RTA_GATEWAY | RTA_IFP | RTA_IFA)
5247c129abms
5347c129abmsint
5447c129abmsgetifmaddrs(struct ifmaddrs **pif)
5547c129abms{
5647c129abms	int icnt = 1;
5747c129abms	int dcnt = 0;
5847c129abms	int ntry = 0;
5947c129abms	size_t len;
6047c129abms	size_t needed;
6147c129abms	int mib[6];
6247c129abms	int i;
6347c129abms	char *buf;
6447c129abms	char *data;
6547c129abms	char *next;
6647c129abms	char *p;
6747c129abms	struct ifma_msghdr *ifmam;
6847c129abms	struct ifmaddrs *ifa, *ift;
6947c129abms	struct rt_msghdr *rtm;
7047c129abms	struct sockaddr *sa;
7147c129abms
7247c129abms	mib[0] = CTL_NET;
7347c129abms	mib[1] = PF_ROUTE;
7447c129abms	mib[2] = 0;             /* protocol */
7547c129abms	mib[3] = 0;             /* wildcard address family */
7647c129abms	mib[4] = NET_RT_IFMALIST;
7747c129abms	mib[5] = 0;             /* no flags */
7847c129abms	do {
7947c129abms		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
8047c129abms			return (-1);
8147c129abms		if ((buf = malloc(needed)) == NULL)
8247c129abms			return (-1);
8347c129abms		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
8447c129abms			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
8547c129abms				free(buf);
8647c129abms				return (-1);
8747c129abms			}
8847c129abms			free(buf);
8947c129abms			buf = NULL;
9047c129abms		}
9147c129abms	} while (buf == NULL);
9247c129abms
9347c129abms	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
9447c129abms		rtm = (struct rt_msghdr *)(void *)next;
9547c129abms		if (rtm->rtm_version != RTM_VERSION)
9647c129abms			continue;
9747c129abms		switch (rtm->rtm_type) {
9847c129abms		case RTM_NEWMADDR:
9947c129abms			ifmam = (struct ifma_msghdr *)(void *)rtm;
10047c129abms			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
10147c129abms				break;
10247c129abms			icnt++;
10347c129abms			p = (char *)(ifmam + 1);
10447c129abms			for (i = 0; i < RTAX_MAX; i++) {
10547c129abms				if ((RTA_MASKS & ifmam->ifmam_addrs &
10647c129abms				    (1 << i)) == 0)
10747c129abms					continue;
10847c129abms				sa = (struct sockaddr *)(void *)p;
10947c129abms				len = SA_RLEN(sa);
11047c129abms				dcnt += len;
11147c129abms				p += len;
11247c129abms			}
11347c129abms			break;
11447c129abms		}
11547c129abms	}
11647c129abms
11747c129abms	data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
11847c129abms	if (data == NULL) {
11947c129abms		free(buf);
12047c129abms		return (-1);
12147c129abms	}
12247c129abms
12347c129abms	ifa = (struct ifmaddrs *)(void *)data;
12447c129abms	data += sizeof(struct ifmaddrs) * icnt;
12547c129abms
12647c129abms	memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
12747c129abms	ift = ifa;
12847c129abms
12947c129abms	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
13047c129abms		rtm = (struct rt_msghdr *)(void *)next;
13147c129abms		if (rtm->rtm_version != RTM_VERSION)
13247c129abms			continue;
13347c129abms
13447c129abms		switch (rtm->rtm_type) {
13547c129abms		case RTM_NEWMADDR:
13647c129abms			ifmam = (struct ifma_msghdr *)(void *)rtm;
13747c129abms			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
13847c129abms				break;
13947c129abms
14047c129abms			p = (char *)(ifmam + 1);
14147c129abms			for (i = 0; i < RTAX_MAX; i++) {
14247c129abms				if ((RTA_MASKS & ifmam->ifmam_addrs &
14347c129abms				    (1 << i)) == 0)
14447c129abms					continue;
14547c129abms				sa = (struct sockaddr *)(void *)p;
14647c129abms				len = SA_RLEN(sa);
14747c129abms				switch (i) {
14847c129abms				case RTAX_GATEWAY:
14947c129abms					ift->ifma_lladdr =
15047c129abms					    (struct sockaddr *)(void *)data;
15147c129abms					memcpy(data, p, len);
15247c129abms					data += len;
15347c129abms					break;
15447c129abms
15547c129abms				case RTAX_IFP:
15647c129abms					ift->ifma_name =
15747c129abms					    (struct sockaddr *)(void *)data;
15847c129abms					memcpy(data, p, len);
15947c129abms					data += len;
16047c129abms					break;
16147c129abms
16247c129abms				case RTAX_IFA:
16347c129abms					ift->ifma_addr =
16447c129abms					    (struct sockaddr *)(void *)data;
16547c129abms					memcpy(data, p, len);
16647c129abms					data += len;
16747c129abms					break;
16847c129abms
16947c129abms				default:
17047c129abms					data += len;
17147c129abms					break;
17247c129abms				}
17347c129abms				p += len;
17447c129abms			}
17547c129abms			ift->ifma_next = ift + 1;
17647c129abms			ift = ift->ifma_next;
17747c129abms			break;
17847c129abms		}
17947c129abms	}
18047c129abms
18147c129abms	free(buf);
18247c129abms
18347c129abms	if (ift > ifa) {
18447c129abms		ift--;
18547c129abms		ift->ifma_next = NULL;
18647c129abms		*pif = ifa;
18747c129abms	} else {
18847c129abms		*pif = NULL;
18947c129abms		free(ifa);
19047c129abms	}
19147c129abms	return (0);
19247c129abms}
19347c129abms
19447c129abmsvoid
19547c129abmsfreeifmaddrs(struct ifmaddrs *ifmp)
19647c129abms{
19747c129abms
19847c129abms	free(ifmp);
19947c129abms}
200