277 lines
7.9 KiB
C
277 lines
7.9 KiB
C
/* $NetBSD: darwin_route.c,v 1.14 2008/04/28 20:23:41 martin Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2004 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Emmanuel Dreyfus.
|
|
*
|
|
* 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.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``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 THE FOUNDATION OR CONTRIBUTORS
|
|
* 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.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: darwin_route.c,v 1.14 2008/04/28 20:23:41 martin Exp $");
|
|
|
|
#include <sys/errno.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/malloc.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <compat/darwin/darwin_socket.h>
|
|
#include <compat/darwin/darwin_route.h>
|
|
|
|
static int darwin_copyout_sockaddr(struct sockaddr *, char **, size_t *, size_t);
|
|
|
|
#define ALIGN(a) (((a) + 3) & ~0x3UL)
|
|
int
|
|
darwin_ifaddrs(int af, char *dst, size_t *sizep)
|
|
{
|
|
struct darwin_if_msghdr dim;
|
|
struct ifnet *ifp;
|
|
int error;
|
|
int index = 1;
|
|
size_t size = 0;
|
|
size_t maxsize = *sizep;
|
|
uint8_t family;
|
|
|
|
af = darwin_to_native_af[af];
|
|
|
|
IFNET_FOREACH(ifp) {
|
|
struct ifaddr *ifa;
|
|
struct sockaddr *laddr = NULL;
|
|
|
|
/*
|
|
* Find the link layer info as it is needed
|
|
* for computing darwin_if_msghdr's dim_len
|
|
*/
|
|
IFADDR_FOREACH(ifa, ifp) {
|
|
if ((ifa->ifa_addr) &&
|
|
(ifa->ifa_addr->sa_family == AF_LINK)) {
|
|
laddr = (struct sockaddr *)ifa->ifa_addr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (laddr == NULL) {
|
|
#ifdef DEBUG_DARWIN
|
|
printf("darwin_ifaddrs: cannot find link address\n");
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
dim.dim_len = sizeof(dim) + ALIGN(laddr->sa_len);
|
|
dim.dim_vers = DARWIN_RTM_VERSION;
|
|
dim.dim_type = DARWIN_RTM_IFINFO;
|
|
dim.dim_addrs = DARWIN_RTA_IFP;
|
|
dim.dim_flags = ifp->if_flags & 0xffff;
|
|
dim.dim_index = index++;
|
|
|
|
dim.dim_data.did_type = ifp->if_data.ifi_type; /* XXX */
|
|
dim.dim_data.did_typelen = 0 ;/* XXX */
|
|
dim.dim_data.did_physical = 0; /* XXX */
|
|
dim.dim_data.did_addrlen = ifp->if_data.ifi_addrlen;
|
|
dim.dim_data.did_hdrlen = ifp->if_data.ifi_hdrlen;
|
|
dim.dim_data.did_recquota = 0; /* XXX */
|
|
dim.dim_data.did_xmitquota = 0; /* XXX */
|
|
dim.dim_data.did_mtu = ifp->if_data.ifi_mtu;
|
|
dim.dim_data.did_metric = ifp->if_data.ifi_metric;
|
|
dim.dim_data.did_baudrate = ifp->if_data.ifi_baudrate;
|
|
dim.dim_data.did_ipackets = ifp->if_data.ifi_ipackets;
|
|
dim.dim_data.did_ierrors = ifp->if_data.ifi_ierrors;
|
|
dim.dim_data.did_opackets = ifp->if_data.ifi_opackets;
|
|
dim.dim_data.did_oerrors = ifp->if_data.ifi_oerrors;
|
|
dim.dim_data.did_collisions = ifp->if_data.ifi_collisions;
|
|
dim.dim_data.did_ibytes = ifp->if_data.ifi_ibytes;
|
|
dim.dim_data.did_obytes = ifp->if_data.ifi_obytes;
|
|
dim.dim_data.did_imcasts = ifp->if_data.ifi_imcasts;
|
|
dim.dim_data.did_omcasts = ifp->if_data.ifi_omcasts;
|
|
dim.dim_data.did_iqdrops = ifp->if_data.ifi_iqdrops;
|
|
dim.dim_data.did_noproto = ifp->if_data.ifi_noproto;
|
|
dim.dim_data.did_lastchange.tv_sec =
|
|
ifp->if_data.ifi_lastchange.tv_sec;
|
|
dim.dim_data.did_lastchange.tv_usec =
|
|
ifp->if_data.ifi_lastchange.tv_usec;
|
|
dim.dim_data.did_default_proto = 0; /* XXX */
|
|
dim.dim_data.did_hwassist = 0; /* XXX */
|
|
|
|
size += sizeof(dim);
|
|
if (dst && (size <= maxsize)) {
|
|
if ((error = copyout(&dim, dst, sizeof(dim))) != 0)
|
|
return error;
|
|
dst += sizeof(dim);
|
|
}
|
|
|
|
/* Copy the link sockaddr. */
|
|
size += ALIGN(laddr->sa_len);
|
|
if (dst && (size <= maxsize)) {
|
|
if ((error = copyout(laddr, dst, laddr->sa_len)) != 0)
|
|
return error;
|
|
family = native_to_darwin_af[laddr->sa_family];
|
|
error = copyout(&family,
|
|
&((struct sockaddr *)dst)->sa_family, 1);
|
|
if (error != 0)
|
|
return error;
|
|
dst += ALIGN(laddr->sa_len);
|
|
}
|
|
|
|
IFADDR_FOREACH(ifa, ifp) {
|
|
struct darwin_ifa_msghdr diam;
|
|
int iaf;
|
|
|
|
if (ifa->ifa_addr) {
|
|
iaf = ifa->ifa_addr->sa_family;
|
|
if ((af != 0) && (iaf != af))
|
|
continue;
|
|
if (iaf > AF_MAX)
|
|
continue;
|
|
if (iaf == 0)
|
|
continue;
|
|
if (native_to_darwin_af[iaf] == 0)
|
|
continue;
|
|
/* Already handled earlier */
|
|
if (iaf == AF_LINK)
|
|
continue;
|
|
}
|
|
|
|
bzero(&diam, sizeof(diam));
|
|
|
|
diam.diam_len = sizeof(diam);
|
|
diam.diam_vers = DARWIN_RTM_VERSION;
|
|
diam.diam_type = DARWIN_RTM_NEWADDR;
|
|
|
|
/*
|
|
* XXX the following code assumes that
|
|
* Darwin sockaddr have the same size as
|
|
* the original.
|
|
*/
|
|
if (ifa->ifa_addr) {
|
|
diam.diam_addrs |= DARWIN_RTA_IFA;
|
|
diam.diam_len += ALIGN(ifa->ifa_addr->sa_len);
|
|
}
|
|
if (ifa->ifa_netmask) {
|
|
diam.diam_addrs |= DARWIN_RTA_NETMASK;
|
|
diam.diam_len +=
|
|
ALIGN(ifa->ifa_netmask->sa_len);
|
|
}
|
|
if ((ifa->ifa_dstaddr != NULL) &&
|
|
(ifp->if_flags & IFF_POINTOPOINT)) {
|
|
diam.diam_addrs |= DARWIN_RTA_DST;
|
|
diam.diam_len +=
|
|
ALIGN(ifa->ifa_dstaddr->sa_len);
|
|
}
|
|
if ((ifa->ifa_broadaddr != NULL) &&
|
|
(ifp->if_flags & IFF_BROADCAST)) {
|
|
diam.diam_addrs |= DARWIN_RTA_BRD;
|
|
diam.diam_len +=
|
|
ALIGN(ifa->ifa_broadaddr->sa_len);
|
|
}
|
|
|
|
diam.diam_flags = (int)ifa->ifa_flags;
|
|
diam.diam_index = dim.dim_index;
|
|
diam.diam_metric = ifa->ifa_metric;
|
|
|
|
size += sizeof(diam);
|
|
if (dst && (size <= maxsize)) {
|
|
error = copyout(&diam, dst, sizeof(diam));
|
|
if (error != 0)
|
|
return error;
|
|
dst += sizeof(diam);
|
|
}
|
|
|
|
/*
|
|
* Interface netmask
|
|
* We sometime lack the af in native version:
|
|
* copy it from ifa_addr.
|
|
*/
|
|
if (diam.diam_addrs & DARWIN_RTA_NETMASK) {
|
|
struct sockaddr_storage ss;
|
|
|
|
memcpy(&ss, ifa->ifa_netmask,
|
|
ifa->ifa_netmask->sa_len);
|
|
if ((ss.ss_family == 0) &&
|
|
(ifa->ifa_addr != NULL) &&
|
|
(ifa->ifa_addr->sa_family != 0))
|
|
ss.ss_family =
|
|
ifa->ifa_addr->sa_family;
|
|
|
|
if ((error = darwin_copyout_sockaddr(
|
|
(struct sockaddr *)&ss, &dst,
|
|
&size, maxsize)) != 0)
|
|
return error;
|
|
}
|
|
|
|
/* Interface address */
|
|
if (diam.diam_addrs & DARWIN_RTA_IFA)
|
|
if ((error = darwin_copyout_sockaddr(ifa->ifa_addr,
|
|
&dst, &size, maxsize)) != 0)
|
|
return error;
|
|
|
|
/* Interface remote address */
|
|
if (diam.diam_addrs & DARWIN_RTA_DST)
|
|
if ((error = darwin_copyout_sockaddr(ifa->ifa_dstaddr,
|
|
&dst, &size, maxsize)) != 0)
|
|
return error;
|
|
|
|
/* Interface broadcast address */
|
|
if (diam.diam_addrs & DARWIN_RTA_BRD)
|
|
if ((error =
|
|
darwin_copyout_sockaddr(ifa->ifa_broadaddr,
|
|
&dst, &size, maxsize)) != 0)
|
|
return error;
|
|
}
|
|
}
|
|
|
|
*sizep = size;
|
|
|
|
if (dst && (size > maxsize))
|
|
return ENOMEM;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
darwin_copyout_sockaddr(struct sockaddr *sap, char **dstp, size_t *sizep, size_t maxsize)
|
|
{
|
|
size_t len;
|
|
int error;
|
|
uint8_t family;
|
|
|
|
len = sap->sa_len;
|
|
|
|
*sizep += ALIGN(len);
|
|
if (*dstp && (*sizep <= maxsize)) {
|
|
if ((error = copyout(sap, *dstp, len)) != 0)
|
|
return error;
|
|
family = native_to_darwin_af[sap->sa_family];
|
|
error = copyout(&family,
|
|
&((struct sockaddr *)*dstp)->sa_family, 1);
|
|
if (error != 0)
|
|
return error;
|
|
*dstp += ALIGN(len);
|
|
}
|
|
|
|
return 0;
|
|
}
|