freebsd-dev/lib/libc/net/getifaddrs.c
Daniel Eischen d201fe46e3 Remove _THREAD_SAFE and make libc thread-safe by default by
adding (weak definitions to) stubs for some of the pthread
functions.  If the threads library is linked in, the real
pthread functions will pulled in.

Use the following convention for system calls wrapped by the
threads library:
	__sys_foo - actual system call
	_foo - weak definition to __sys_foo
	foo - weak definition to __sys_foo

Change all libc uses of system calls wrapped by the threads
library from foo to _foo.  In order to define the prototypes
for _foo(), we introduce namespace.h and un-namespace.h
(suggested by bde).  All files that need to reference these
system calls, should include namespace.h before any standard
includes, then include un-namespace.h after the standard
includes and before any local includes.  <db.h> is an exception
and shouldn't be included in between namespace.h and
un-namespace.h  namespace.h will define foo to _foo, and
un-namespace.h will undefine foo.

Try to eliminate some of the recursive calls to MT-safe
functions in libc/stdio in preparation for adding a mutex
to FILE.  We have recursive mutexes, but would like to avoid
using them if possible.

Remove uneeded includes of <errno.h> from a few files.

Add $FreeBSD$ to a few files in order to pass commitprep.

Approved by:	-arch
2001-01-24 13:01:12 +00:00

386 lines
9.1 KiB
C

/* $FreeBSD$ */
/*
* Copyright (c) 1995, 1999
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
*/
/*
* NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
* try-and-error for region size.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#ifdef NET_RT_IFLIST
#include <sys/param.h>
#include <net/route.h>
#include <sys/sysctl.h>
#include <net/if_dl.h>
#endif
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#if !defined(AF_LINK)
#define SA_LEN(sa) sizeof(struct sockaddr)
#endif
#if !defined(SA_LEN)
#define SA_LEN(sa) (sa)->sa_len
#endif
#define SALIGN (sizeof(long) - 1)
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
#ifndef ALIGNBYTES
/*
* On systems with a routing socket, ALIGNBYTES should match the value
* that the kernel uses when building the messages.
*/
#define ALIGNBYTES XXX
#endif
#ifndef ALIGN
#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
#endif
#if _BSDI_VERSION >= 199701
#define HAVE_IFM_DATA
#endif
#if _BSDI_VERSION >= 199802
/* ifam_data is very specific to recent versions of bsdi */
#define HAVE_IFAM_DATA
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
#define HAVE_IFM_DATA
#endif
int
getifaddrs(struct ifaddrs **pif)
{
int icnt = 1;
int dcnt = 0;
int ncnt = 0;
#ifdef NET_RT_IFLIST
int mib[6];
size_t needed;
char *buf;
char *next;
struct ifaddrs *cif = 0;
char *p, *p0;
struct rt_msghdr *rtm;
struct if_msghdr *ifm;
struct ifa_msghdr *ifam;
struct sockaddr_dl *dl;
struct sockaddr *sa;
struct ifaddrs *ifa, *ift;
u_short index = 0;
#else /* NET_RT_IFLIST */
char buf[1024];
int m, sock;
struct ifconf ifc;
struct ifreq *ifr;
struct ifreq *lifr;
#endif /* NET_RT_IFLIST */
int i;
size_t len, alen;
char *data;
char *names;
#ifdef NET_RT_IFLIST
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
mib[3] = 0; /* wildcard address family */
mib[4] = NET_RT_IFLIST;
mib[5] = 0; /* no flags */
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return (-1);
if ((buf = malloc(needed)) == NULL)
return (-1);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
free(buf);
return (-1);
}
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case RTM_IFINFO:
ifm = (struct if_msghdr *)rtm;
if (ifm->ifm_addrs & RTA_IFP) {
index = ifm->ifm_index;
++icnt;
dl = (struct sockaddr_dl *)(ifm + 1);
dcnt += SA_RLEN((struct sockaddr *)dl) +
ALIGNBYTES;
#ifdef HAVE_IFM_DATA
dcnt += sizeof(ifm->ifm_data);
#endif /* HAVE_IFM_DATA */
ncnt += dl->sdl_nlen + 1;
} else
index = 0;
break;
case RTM_NEWADDR:
ifam = (struct ifa_msghdr *)rtm;
if (index && ifam->ifam_index != index)
abort(); /* this cannot happen */
#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
break;
p = (char *)(ifam + 1);
++icnt;
#ifdef HAVE_IFAM_DATA
dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
#endif /* HAVE_IFAM_DATA */
/* Scan to look for length of address */
alen = 0;
for (p0 = p, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)p;
len = SA_RLEN(sa);
if (i == RTAX_IFA) {
alen = len;
break;
}
p += len;
}
for (p = p0, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)p;
len = SA_RLEN(sa);
if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
dcnt += alen;
else
dcnt += len;
p += len;
}
break;
}
}
#else /* NET_RT_IFLIST */
ifc.ifc_buf = buf;
ifc.ifc_len = sizeof(buf);
if ((sock = _socket(AF_INET, SOCK_STREAM, 0)) < 0)
return (-1);
i = _ioctl(sock, SIOCGIFCONF, (char *)&ifc);
_close(sock);
if (i < 0)
return (-1);
ifr = ifc.ifc_req;
lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
while (ifr < lifr) {
struct sockaddr *sa;
sa = &ifr->ifr_addr;
++icnt;
dcnt += SA_RLEN(sa);
ncnt += sizeof(ifr->ifr_name) + 1;
ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
}
#endif /* NET_RT_IFLIST */
if (icnt + dcnt + ncnt == 1) {
*pif = NULL;
free(buf);
return (0);
}
data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
if (data == NULL) {
free(buf);
return(-1);
}
ifa = (struct ifaddrs *)data;
data += sizeof(struct ifaddrs) * icnt;
names = data + dcnt;
memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
ift = ifa;
#ifdef NET_RT_IFLIST
index = 0;
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case RTM_IFINFO:
ifm = (struct if_msghdr *)rtm;
if (ifm->ifm_addrs & RTA_IFP) {
index = ifm->ifm_index;
dl = (struct sockaddr_dl *)(ifm + 1);
cif = ift;
ift->ifa_name = names;
ift->ifa_flags = (int)ifm->ifm_flags;
memcpy(names, dl->sdl_data, dl->sdl_nlen);
names[dl->sdl_nlen] = 0;
names += dl->sdl_nlen + 1;
ift->ifa_addr = (struct sockaddr *)data;
memcpy(data, dl, SA_LEN((struct sockaddr *)dl));
data += SA_RLEN((struct sockaddr *)dl);
#ifdef HAVE_IFM_DATA
/* ifm_data needs to be aligned */
ift->ifa_data = data = (void *)ALIGN(data);
memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
data += sizeof(ifm->ifm_data);
#else /* HAVE_IFM_DATA */
ift->ifa_data = NULL;
#endif /* HAVE_IFM_DATA */
ift = (ift->ifa_next = ift + 1);
} else
index = 0;
break;
case RTM_NEWADDR:
ifam = (struct ifa_msghdr *)rtm;
if (index && ifam->ifam_index != index)
abort(); /* this cannot happen */
if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
break;
ift->ifa_name = cif->ifa_name;
ift->ifa_flags = cif->ifa_flags;
ift->ifa_data = NULL;
p = (char *)(ifam + 1);
/* Scan to look for length of address */
alen = 0;
for (p0 = p, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)p;
len = SA_RLEN(sa);
if (i == RTAX_IFA) {
alen = len;
break;
}
p += len;
}
for (p = p0, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)p;
len = SA_RLEN(sa);
switch (i) {
case RTAX_IFA:
ift->ifa_addr = (struct sockaddr *)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_NETMASK:
ift->ifa_netmask =
(struct sockaddr *)data;
if (SA_LEN(sa) == 0) {
memset(data, 0, alen);
data += alen;
break;
}
memcpy(data, p, len);
data += len;
break;
case RTAX_BRD:
ift->ifa_broadaddr =
(struct sockaddr *)data;
memcpy(data, p, len);
data += len;
break;
}
p += len;
}
#ifdef HAVE_IFAM_DATA
/* ifam_data needs to be aligned */
ift->ifa_data = data = (void *)ALIGN(data);
memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
data += sizeof(ifam->ifam_data);
#endif /* HAVE_IFAM_DATA */
ift = (ift->ifa_next = ift + 1);
break;
}
}
free(buf);
#else /* NET_RT_IFLIST */
ifr = ifc.ifc_req;
lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
while (ifr < lifr) {
struct sockaddr *sa;
ift->ifa_name = names;
names[sizeof(ifr->ifr_name)] = 0;
strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
while (*names++)
;
ift->ifa_addr = (struct sockaddr *)data;
sa = &ifr->ifr_addr;
memcpy(data, sa, SA_LEN(sa));
data += SA_RLEN(sa);
ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
ift = (ift->ifa_next = ift + 1);
}
#endif /* NET_RT_IFLIST */
if (--ift >= ifa) {
ift->ifa_next = NULL;
*pif = ifa;
} else {
*pif = NULL;
free(ifa);
}
return (0);
}
void
freeifaddrs(struct ifaddrs *ifp)
{
free(ifp);
}