Home | History | Annotate | Line # | Download | only in net
getifaddrs.c revision 1.13.2.1
      1  1.13.2.1    bouyer /*	$NetBSD: getifaddrs.c,v 1.13.2.1 2011/02/08 16:18:59 bouyer Exp $	*/
      2       1.1    itojun 
      3       1.1    itojun /*
      4       1.1    itojun  * Copyright (c) 1995, 1999
      5       1.1    itojun  *	Berkeley Software Design, Inc.  All rights reserved.
      6       1.1    itojun  *
      7       1.1    itojun  * Redistribution and use in source and binary forms, with or without
      8       1.1    itojun  * modification, are permitted provided that the following conditions
      9       1.1    itojun  * are met:
     10       1.1    itojun  * 1. Redistributions of source code must retain the above copyright
     11       1.1    itojun  *    notice, this list of conditions and the following disclaimer.
     12       1.1    itojun  *
     13       1.1    itojun  * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
     14       1.1    itojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15       1.1    itojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     16       1.1    itojun  * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
     17       1.1    itojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     18       1.1    itojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     19       1.1    itojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     20       1.1    itojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     21       1.1    itojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     22       1.1    itojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     23       1.1    itojun  * SUCH DAMAGE.
     24       1.1    itojun  *
     25       1.2    itojun  *	BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
     26       1.1    itojun  */
     27       1.4    itojun 
     28       1.4    itojun #include <sys/cdefs.h>
     29       1.4    itojun #if defined(LIBC_SCCS) && !defined(lint)
     30  1.13.2.1    bouyer __RCSID("$NetBSD: getifaddrs.c,v 1.13.2.1 2011/02/08 16:18:59 bouyer Exp $");
     31       1.4    itojun #endif /* LIBC_SCCS and not lint */
     32       1.4    itojun 
     33      1.13     pooka #ifndef RUMP_ACTION
     34       1.3    itojun #include "namespace.h"
     35      1.13     pooka #endif
     36       1.1    itojun #include <sys/types.h>
     37       1.1    itojun #include <sys/ioctl.h>
     38       1.1    itojun #include <sys/socket.h>
     39       1.1    itojun #include <net/if.h>
     40       1.1    itojun #include <sys/param.h>
     41       1.1    itojun #include <net/route.h>
     42       1.1    itojun #include <sys/sysctl.h>
     43       1.1    itojun #include <net/if_dl.h>
     44       1.1    itojun 
     45       1.7     lukem #include <assert.h>
     46       1.1    itojun #include <errno.h>
     47       1.1    itojun #include <ifaddrs.h>
     48       1.1    itojun #include <stdlib.h>
     49       1.1    itojun #include <string.h>
     50       1.3    itojun 
     51      1.13     pooka #if defined(__weak_alias) && !defined(RUMP_ACTION)
     52       1.3    itojun __weak_alias(getifaddrs,_getifaddrs)
     53       1.3    itojun __weak_alias(freeifaddrs,_freeifaddrs)
     54       1.3    itojun #endif
     55       1.1    itojun 
     56      1.13     pooka #ifdef RUMP_ACTION
     57      1.13     pooka #include <rump/rump_syscalls.h>
     58      1.13     pooka #define sysctl(a,b,c,d,e,f) rump_sys___sysctl(a,b,c,d,e,f)
     59      1.13     pooka #endif
     60      1.13     pooka 
     61  1.13.2.1    bouyer #define	SA_RLEN(sa)	RT_ROUNDUP((sa)->sa_len)
     62       1.1    itojun 
     63       1.1    itojun int
     64       1.1    itojun getifaddrs(struct ifaddrs **pif)
     65       1.1    itojun {
     66       1.1    itojun 	int icnt = 1;
     67       1.1    itojun 	int dcnt = 0;
     68       1.1    itojun 	int ncnt = 0;
     69       1.1    itojun 	int mib[6];
     70       1.1    itojun 	size_t needed;
     71       1.1    itojun 	char *buf;
     72       1.1    itojun 	char *next;
     73      1.12    dyoung 	struct ifaddrs cif;
     74       1.1    itojun 	char *p, *p0;
     75       1.1    itojun 	struct rt_msghdr *rtm;
     76       1.1    itojun 	struct if_msghdr *ifm;
     77       1.1    itojun 	struct ifa_msghdr *ifam;
     78       1.1    itojun 	struct sockaddr *sa;
     79       1.1    itojun 	struct ifaddrs *ifa, *ift;
     80       1.5  christos 	u_short idx = 0;
     81       1.1    itojun 	int i;
     82       1.1    itojun 	size_t len, alen;
     83       1.1    itojun 	char *data;
     84       1.1    itojun 	char *names;
     85       1.1    itojun 
     86       1.7     lukem 	_DIAGASSERT(pif != NULL);
     87       1.7     lukem 
     88       1.1    itojun 	mib[0] = CTL_NET;
     89       1.1    itojun 	mib[1] = PF_ROUTE;
     90       1.1    itojun 	mib[2] = 0;             /* protocol */
     91       1.1    itojun 	mib[3] = 0;             /* wildcard address family */
     92       1.1    itojun 	mib[4] = NET_RT_IFLIST;
     93       1.1    itojun 	mib[5] = 0;             /* no flags */
     94      1.11    dyoung 	if (sysctl(mib, __arraycount(mib), NULL, &needed, NULL, 0) < 0)
     95       1.1    itojun 		return (-1);
     96       1.1    itojun 	if ((buf = malloc(needed)) == NULL)
     97       1.1    itojun 		return (-1);
     98      1.11    dyoung 	if (sysctl(mib, __arraycount(mib), buf, &needed, NULL, 0) < 0) {
     99       1.1    itojun 		free(buf);
    100       1.1    itojun 		return (-1);
    101       1.1    itojun 	}
    102       1.1    itojun 
    103       1.1    itojun 	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
    104       1.5  christos 		rtm = (struct rt_msghdr *)(void *)next;
    105       1.1    itojun 		if (rtm->rtm_version != RTM_VERSION)
    106       1.1    itojun 			continue;
    107       1.1    itojun 		switch (rtm->rtm_type) {
    108       1.1    itojun 		case RTM_IFINFO:
    109       1.5  christos 			ifm = (struct if_msghdr *)(void *)rtm;
    110       1.1    itojun 			if (ifm->ifm_addrs & RTA_IFP) {
    111      1.12    dyoung 				const struct sockaddr_dl *dl;
    112      1.12    dyoung 
    113       1.5  christos 				idx = ifm->ifm_index;
    114       1.1    itojun 				++icnt;
    115       1.5  christos 				dl = (struct sockaddr_dl *)(void *)(ifm + 1);
    116      1.12    dyoung 				dcnt += SA_RLEN((const struct sockaddr *)(const void *)dl) +
    117       1.5  christos 				    ALIGNBYTES;
    118       1.1    itojun 				dcnt += sizeof(ifm->ifm_data);
    119       1.1    itojun 				ncnt += dl->sdl_nlen + 1;
    120       1.1    itojun 			} else
    121       1.5  christos 				idx = 0;
    122       1.1    itojun 			break;
    123       1.1    itojun 
    124       1.1    itojun 		case RTM_NEWADDR:
    125       1.5  christos 			ifam = (struct ifa_msghdr *)(void *)rtm;
    126       1.5  christos 			if (idx && ifam->ifam_index != idx)
    127       1.1    itojun 				abort();	/* this cannot happen */
    128       1.1    itojun 
    129       1.1    itojun #define	RTA_MASKS	(RTA_NETMASK | RTA_IFA | RTA_BRD)
    130       1.5  christos 			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
    131       1.1    itojun 				break;
    132       1.5  christos 			p = (char *)(void *)(ifam + 1);
    133       1.1    itojun 			++icnt;
    134       1.1    itojun 			/* Scan to look for length of address */
    135       1.1    itojun 			alen = 0;
    136       1.1    itojun 			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
    137       1.1    itojun 				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
    138       1.1    itojun 				    == 0)
    139       1.1    itojun 					continue;
    140       1.5  christos 				sa = (struct sockaddr *)(void *)p;
    141       1.1    itojun 				len = SA_RLEN(sa);
    142       1.1    itojun 				if (i == RTAX_IFA) {
    143       1.1    itojun 					alen = len;
    144       1.1    itojun 					break;
    145       1.1    itojun 				}
    146       1.1    itojun 				p += len;
    147       1.1    itojun 			}
    148       1.1    itojun 			for (p = p0, i = 0; i < RTAX_MAX; i++) {
    149       1.1    itojun 				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
    150       1.1    itojun 				    == 0)
    151       1.1    itojun 					continue;
    152       1.5  christos 				sa = (struct sockaddr *)(void *)p;
    153       1.1    itojun 				len = SA_RLEN(sa);
    154       1.9    itojun 				if (i == RTAX_NETMASK && sa->sa_len == 0)
    155       1.1    itojun 					dcnt += alen;
    156       1.1    itojun 				else
    157       1.1    itojun 					dcnt += len;
    158       1.1    itojun 				p += len;
    159       1.1    itojun 			}
    160       1.1    itojun 			break;
    161       1.1    itojun 		}
    162       1.1    itojun 	}
    163       1.1    itojun 
    164       1.1    itojun 	if (icnt + dcnt + ncnt == 1) {
    165       1.1    itojun 		*pif = NULL;
    166       1.1    itojun 		free(buf);
    167       1.1    itojun 		return (0);
    168       1.1    itojun 	}
    169       1.1    itojun 	data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
    170       1.1    itojun 	if (data == NULL) {
    171       1.1    itojun 		free(buf);
    172       1.1    itojun 		return(-1);
    173       1.1    itojun 	}
    174       1.1    itojun 
    175       1.5  christos 	ifa = (struct ifaddrs *)(void *)data;
    176       1.1    itojun 	data += sizeof(struct ifaddrs) * icnt;
    177       1.1    itojun 	names = data + dcnt;
    178       1.1    itojun 
    179       1.1    itojun 	memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
    180       1.1    itojun 	ift = ifa;
    181       1.1    itojun 
    182       1.5  christos 	idx = 0;
    183       1.1    itojun 	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
    184       1.5  christos 		rtm = (struct rt_msghdr *)(void *)next;
    185       1.1    itojun 		if (rtm->rtm_version != RTM_VERSION)
    186       1.1    itojun 			continue;
    187       1.1    itojun 		switch (rtm->rtm_type) {
    188       1.1    itojun 		case RTM_IFINFO:
    189       1.5  christos 			ifm = (struct if_msghdr *)(void *)rtm;
    190       1.1    itojun 			if (ifm->ifm_addrs & RTA_IFP) {
    191      1.12    dyoung 				const struct sockaddr_dl *dl;
    192      1.12    dyoung 
    193       1.5  christos 				idx = ifm->ifm_index;
    194       1.5  christos 				dl = (struct sockaddr_dl *)(void *)(ifm + 1);
    195       1.1    itojun 
    196      1.12    dyoung 				memset(&cif, 0, sizeof(cif));
    197      1.12    dyoung 
    198      1.12    dyoung 				cif.ifa_name = names;
    199      1.12    dyoung 				cif.ifa_flags = (int)ifm->ifm_flags;
    200       1.5  christos 				memcpy(names, dl->sdl_data,
    201       1.5  christos 				    (size_t)dl->sdl_nlen);
    202       1.1    itojun 				names[dl->sdl_nlen] = 0;
    203       1.1    itojun 				names += dl->sdl_nlen + 1;
    204       1.1    itojun 
    205      1.12    dyoung 				cif.ifa_addr = (struct sockaddr *)(void *)data;
    206      1.12    dyoung 				memcpy(data, dl, (size_t)dl->sdl_len);
    207      1.12    dyoung 				data += SA_RLEN((const struct sockaddr *)(const void *)dl);
    208       1.1    itojun 
    209       1.1    itojun 				/* ifm_data needs to be aligned */
    210      1.12    dyoung 				cif.ifa_data = data = (void *)ALIGN(data);
    211       1.1    itojun 				memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
    212       1.1    itojun  				data += sizeof(ifm->ifm_data);
    213       1.1    itojun 			} else
    214       1.5  christos 				idx = 0;
    215       1.1    itojun 			break;
    216       1.1    itojun 
    217       1.1    itojun 		case RTM_NEWADDR:
    218       1.5  christos 			ifam = (struct ifa_msghdr *)(void *)rtm;
    219       1.5  christos 			if (idx && ifam->ifam_index != idx)
    220       1.1    itojun 				abort();	/* this cannot happen */
    221       1.1    itojun 
    222       1.5  christos 			if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
    223       1.1    itojun 				break;
    224      1.12    dyoung 			ift->ifa_name = cif.ifa_name;
    225      1.12    dyoung 			ift->ifa_flags = cif.ifa_flags;
    226       1.1    itojun 			ift->ifa_data = NULL;
    227       1.5  christos 			p = (char *)(void *)(ifam + 1);
    228       1.1    itojun 			/* Scan to look for length of address */
    229       1.1    itojun 			alen = 0;
    230       1.1    itojun 			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
    231       1.1    itojun 				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
    232       1.1    itojun 				    == 0)
    233       1.1    itojun 					continue;
    234       1.5  christos 				sa = (struct sockaddr *)(void *)p;
    235       1.1    itojun 				len = SA_RLEN(sa);
    236       1.1    itojun 				if (i == RTAX_IFA) {
    237       1.1    itojun 					alen = len;
    238       1.1    itojun 					break;
    239       1.1    itojun 				}
    240       1.1    itojun 				p += len;
    241       1.1    itojun 			}
    242       1.1    itojun 			for (p = p0, i = 0; i < RTAX_MAX; i++) {
    243       1.1    itojun 				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
    244       1.1    itojun 				    == 0)
    245       1.1    itojun 					continue;
    246       1.5  christos 				sa = (struct sockaddr *)(void *)p;
    247       1.1    itojun 				len = SA_RLEN(sa);
    248       1.1    itojun 				switch (i) {
    249       1.1    itojun 				case RTAX_IFA:
    250       1.5  christos 					ift->ifa_addr =
    251       1.5  christos 					    (struct sockaddr *)(void *)data;
    252       1.1    itojun 					memcpy(data, p, len);
    253       1.1    itojun 					data += len;
    254      1.12    dyoung 					if (ift->ifa_addr->sa_family == AF_LINK)
    255      1.12    dyoung 						ift->ifa_data = cif.ifa_data;
    256       1.1    itojun 					break;
    257       1.1    itojun 
    258       1.1    itojun 				case RTAX_NETMASK:
    259       1.1    itojun 					ift->ifa_netmask =
    260       1.5  christos 					    (struct sockaddr *)(void *)data;
    261       1.9    itojun 					if (sa->sa_len == 0) {
    262       1.1    itojun 						memset(data, 0, alen);
    263       1.1    itojun 						data += alen;
    264       1.1    itojun 						break;
    265       1.1    itojun 					}
    266       1.1    itojun 					memcpy(data, p, len);
    267       1.1    itojun 					data += len;
    268       1.1    itojun 					break;
    269       1.1    itojun 
    270       1.1    itojun 				case RTAX_BRD:
    271       1.1    itojun 					ift->ifa_broadaddr =
    272       1.5  christos 					    (struct sockaddr *)(void *)data;
    273       1.1    itojun 					memcpy(data, p, len);
    274       1.1    itojun 					data += len;
    275       1.1    itojun 					break;
    276       1.1    itojun 				}
    277       1.1    itojun 				p += len;
    278       1.1    itojun 			}
    279       1.1    itojun 
    280       1.1    itojun 
    281       1.1    itojun 			ift = (ift->ifa_next = ift + 1);
    282       1.1    itojun 			break;
    283       1.1    itojun 		}
    284       1.1    itojun 	}
    285       1.1    itojun 
    286       1.1    itojun 	free(buf);
    287       1.1    itojun 	if (--ift >= ifa) {
    288       1.1    itojun 		ift->ifa_next = NULL;
    289       1.1    itojun 		*pif = ifa;
    290       1.1    itojun 	} else {
    291       1.1    itojun 		*pif = NULL;
    292       1.1    itojun 		free(ifa);
    293       1.1    itojun 	}
    294       1.1    itojun 	return (0);
    295       1.2    itojun }
    296       1.2    itojun 
    297       1.2    itojun void
    298       1.2    itojun freeifaddrs(struct ifaddrs *ifp)
    299       1.2    itojun {
    300       1.7     lukem 
    301       1.7     lukem 	_DIAGASSERT(ifp != NULL);
    302       1.7     lukem 
    303       1.2    itojun 	free(ifp);
    304       1.1    itojun }
    305