This is if.c in view mode; [Download] [Up]
/*
* $Header: /disk/d/src/devel/gated/dist/src/RCS/if.c,v 2.1 92/02/24 14:12:37 jch Exp $
*/
/*%Copyright%*/
/************************************************************************
* *
* GateD, Release 2 *
* *
* Copyright (c) 1990,1991,1992 by Cornell University *
* All rights reserved. *
* *
* THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY *
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT *
* LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY *
* AND FITNESS FOR A PARTICULAR PURPOSE. *
* *
* Royalty-free licenses to redistribute GateD Release *
* 2 in whole or in part may be obtained by writing to: *
* *
* GateDaemon Project *
* Information Technologies/Network Resources *
* 143 Caldwell Hall *
* Cornell University *
* Ithaca, NY 14853-2602 *
* *
* GateD is based on Kirton's EGP, UC Berkeley's routing *
* daemon (routed), and DCN's HELLO routing Protocol. *
* Development of Release 2 has been supported by the *
* National Science Foundation. *
* *
* Please forward bug fixes, enhancements and questions to the *
* gated mailing list: gated-people@gated.cornell.edu. *
* *
* Authors: *
* *
* Jeffrey C Honig <jch@gated.cornell.edu> *
* Scott W Brim <swb@gated.cornell.edu> *
* *
*************************************************************************
* *
* Portions of this software may fall under the following *
* copyrights: *
* *
* Copyright (c) 1988 Regents of the University of California. *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms are *
* permitted provided that the above copyright notice and *
* this paragraph are duplicated in all such forms and that *
* any documentation, advertising materials, and other *
* materials related to such distribution and use *
* acknowledge that the software was developed by the *
* University of California, Berkeley. The name of the *
* University may not be used to endorse or promote *
* products derived from this software without specific *
* prior written permission. THIS SOFTWARE IS PROVIDED *
* ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, *
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *
* *
************************************************************************/
/*
* if.c
*
*/
#include "include.h"
#ifdef SYSV
#include <sys/sioctl.h>
#include <sys/stropts.h>
#else /* SYSV */
#include <sys/ioctl.h>
#endif /* SYSV */
#include "snmp.h"
/* Some systems (SunOS 3.x where x > 2) do not define ifr_broadaddr */
#if defined(SIOCGIFBRDADDR) && !defined(ifr_broadaddr)
#define ifr_broadaddr ifr_addr
#endif /* defined(SIOCGIFBRDADDR) && !defined(ifr_broadaddr) */
task *if_task = (task *) 0;
if_entry *ifnet; /* direct internet interface list */
int n_interfaces; /* # internet interfaces */
int int_index_max;
int if_rtactive = FALSE; /* Set to true if any protocol is broadcasting */
bits if_flag_bits[] =
{
{IFS_UP, "Up"},
{IFS_BROADCAST, "Broadcast"},
{IFS_POINTOPOINT, "PointoPoint"},
{IFS_SUBNET, "Subnet"},
{IFS_LOOPBACK, "Loopback"},
{IFS_INTERFACE, "Interface"},
{IFS_REMOTE, "Remote"},
{IFS_NOAGE, "NoAge"},
{IFS_NORIPOUT, "NoRipOut"},
{IFS_NORIPIN, "NoRipIn"},
{IFS_NOHELLOOUT, "NoHelloOut"},
{IFS_NOHELLOIN, "NoHelloIn"},
{IFS_NOICMPIN, "NoIcmpIn"},
{IFS_METRICSET, "MetricSet"},
{IFS_MULTICAST, "Multicast"},
{IFS_SIMPLEX, "Simplex"},
{0}
};
/* Find the subnetmask for the specified address, returns it in */
/* host byte order. Do not match the whole network of a subnetted network. */
u_long
if_subnetmask(addr)
struct in_addr addr;
{
u_long mask = (u_long) 0;
if_entry *ifp;
IF_LIST(ifp) {
if (!(ifp->int_state & IFS_UP)) {
continue;
}
/* Ignore the netmasks of P2P links */
/* XXX - What if we want to specify the netmask of remote net when we configure a P2P link? */
if (ifp->int_state & IFS_POINTOPOINT) {
continue;
}
/* XXX - Won't work with variable length subnet masks */
if ((ifp->int_netmask.in.sin_addr.s_addr & addr.s_addr) == ifp->int_net.in.sin_addr.s_addr) {
if (ifp->int_state & IFS_LOOPBACK) {
mask = ifp->int_netmask.in.sin_addr.s_addr;
} else {
mask = ifp->int_subnetmask.in.sin_addr.s_addr;
}
break;
}
} IF_LISTEND(ifp) ;
return (ntohl(mask));
}
/*
* Find the interface with specified address.
*
* For point-to-point interfaces, the destination address is checked
* for other interfaces, the interface address is checked
* for broadcast interfaces, the broadcast address is also checked
*/
if_entry *
if_withaddr(addr)
sockaddr_un *addr;
{
register if_entry *ifp;
IF_LIST(ifp) {
if (!(ifp->int_state & IFS_UP)) {
continue;
}
if (ifp->int_state & IFS_REMOTE) {
continue;
}
if (ifp->int_addr.a.sa_family != addr->a.sa_family) {
continue;
}
if (ifp->int_state & IFS_POINTOPOINT) {
if (equal_in(ifp->int_dstaddr.in.sin_addr, addr->in.sin_addr)) {
break;
} else {
continue;
}
}
if (equal_in(ifp->int_addr.in.sin_addr, addr->in.sin_addr)) {
break;
}
if (ifp->int_state & IFS_BROADCAST) {
if (equal_in(ifp->int_broadaddr.in.sin_addr, addr->in.sin_addr)) {
break;
}
}
} IF_LISTEND(ifp) ;
return (ifp);
}
/* Find the interface on the network of the specified address. On a */
/* point-to-point interface only the destination address is compared. */
/* On all other interfaces, the network/subnet is compared against the */
/* network/subnet of the interface address. */
if_entry *
if_withdst(dstaddr)
sockaddr_un *dstaddr;
{
register if_entry *ifp;
if (dstaddr->a.sa_family != AF_INET)
return (0);
/* Scan the interface list. For P2P interfaces look for an exact */
/* match of the specified address and the destination of this link. */
/* For other types of interfaces search for interfaces with the same */
/* (whole) netmask. On these interfaces, compare the specified */
/* address with the interface address under the subnetmask. */
switch (dstaddr->a.sa_family) {
case AF_INET:
IF_LIST(ifp) {
if (!(ifp->int_state & IFS_UP)) {
continue;
}
if (ifp->int_state & IFS_POINTOPOINT) {
if (dstaddr->in.sin_addr.s_addr == ifp->int_dstaddr.in.sin_addr.s_addr) {
break;
}
} else if (ifp->int_state & IFS_LOOPBACK) {
if (dstaddr->in.sin_addr.s_addr == ifp->int_addr.in.sin_addr.s_addr) {
break;
}
} else if (!((dstaddr->in.sin_addr.s_addr ^ ifp->int_addr.in.sin_addr.s_addr) &
ifp->int_subnetmask.in.sin_addr.s_addr)) {
break;
}
} IF_LISTEND(ifp) ;
break;
default:
ifp = (if_entry *) 0;
}
return (ifp);
}
/*
* Lookup an interface by name
*/
if_entry *
if_withname(name)
char *name;
{
if_entry *ifp;
IF_LIST(ifp) {
if (!strcasecmp(name, ifp->int_name)) {
break;
}
} IF_LISTEND(ifp) ;
return (ifp);
}
/*
* if_display():
* Log the configuration of the interface
*/
void
if_display(name, ifp)
const char *name;
if_entry *ifp;
{
tracef("%s: interface %s: %s addr %A metric %d index %d preference %d",
name,
ifp->int_name,
(ifp->int_state & IFS_UP) ? "up" : "down",
&ifp->int_addr,
ifp->int_metric,
ifp->int_index,
ifp->int_preference);
trace(TR_INT, 0, NULL);
if (ifp->int_state & IFS_BROADCAST) {
tracef("%s: interface %s: broadaddr %A",
name,
ifp->int_name,
&ifp->int_broadaddr);
}
if (ifp->int_state & IFS_POINTOPOINT) {
tracef("%s: interface %s: dstaddr %A",
name,
ifp->int_name,
&ifp->int_dstaddr);
}
if (ifp->int_state & (IFS_BROADCAST | IFS_POINTOPOINT)) {
trace(TR_INT, 0, NULL);
}
trace(TR_INT, 0, "%s: interface %s: net %A netmask %A",
name,
ifp->int_name,
&ifp->int_net,
&ifp->int_netmask);
trace(TR_INT, 0, "%s: interface %s: subnet %A subnetmask %A",
name,
ifp->int_name,
&ifp->int_subnet,
&ifp->int_subnetmask);
trace(TR_INT, 0, "%s: interface %s: flags <%s>",
name,
ifp->int_name,
trace_bits(if_flag_bits, ifp->int_state));
trace(TR_INT, 0, NULL);
}
#ifdef notdef
/* used for DEBUGing */
static void
if_print()
{
register if_entry *ifp;
IF_LIST(ifp) {
if_display("if_print", ifp);
} IF_LISTEND;
}
#endif /* notdef */
/* if_flags():
* Convert kernel interface flags to gated interface flags
*/
flag_t
if_flags(k_flags)
int k_flags;
{
flag_t flags = 0;
if (k_flags & IFF_UP) {
flags |= IFS_UP;
}
if (k_flags & IFF_BROADCAST) {
flags |= IFS_BROADCAST;
}
if (k_flags & IFF_POINTOPOINT) {
flags |= IFS_POINTOPOINT;
}
#ifdef IFF_LOOPBACK
if (k_flags & IFF_LOOPBACK) {
flags |= IFS_LOOPBACK;
}
#endif /* IFF_LOOPBACK */
#ifdef IFF_MULTICAST
if (k_flags & IFF_MULTICAST) {
flags |= IFS_MULTICAST;
}
#endif /* IFF_MULTICAST */
#ifdef IFF_SIMPLEX
if (k_flags & IFF_SIMPLEX) {
flags |= IFS_SIMPLEX;
}
#endif /* IFF_SIMPLEX */
return (flags);
}
/* Verify that no two non-POINTOPOINT interfaces have the same address and */
/* that no two interfaces have the same destination route */
static void
if_dupcheck()
{
if_entry *ifp, *ifp2;
IF_LIST(ifp) {
if (ifp->int_state & IFS_UP) {
IF_LIST(ifp2) {
if ((ifp2->int_state & IFS_UP) && (ifp != ifp2)) {
if (ifp->int_state & IFS_LOOPBACK) {
/* Loopback interfaces only have a route to the */
/* loopback host so we only need check the */
/* destination. But we also need to check that */
/* someone did not configure the other end of a */
/* POINTOPOINT link to be the loopback host */
if (equal(&ifp->int_addr, IF_ADDR(ifp2))) {
break;
}
} else if (ifp->int_state & IFS_POINTOPOINT) {
/* For a POINTOPOINT interface we have to verify */
/* that this destination address is unique amoung */
/* all other POINTOPOINT destination addresses and */
/* non-POINTOPOINT local addresses */
if (equal(&ifp->int_dstaddr, IF_ADDR(ifp2))) {
break;
}
} else if (!(ifp2->int_state & IFS_POINTOPOINT)) {
/* For all other interfaces we must make sure that */
/* no one else has our local address and no one */
/* else has a route to our subnet/network */
if (equal(&ifp->int_addr, &ifp2->int_addr)) {
break;
} else if (equal(&ifp->int_subnet, &ifp2->int_subnet)) {
break;
}
}
}
} IF_LISTEND(ifp2) ;
if (ifp2) {
tracef("if_dupcheck: address/destination conflicts between %s %A",
ifp->int_name,
&ifp->int_addr);
if (ifp->int_state & IFS_POINTOPOINT) {
tracef(" -> %A",
&ifp->int_dstaddr);
}
tracef(" and %s %A",
ifp2->int_name,
&ifp2->int_addr);
if (ifp2->int_state & IFS_POINTOPOINT) {
tracef(" -> %A",
&ifp->int_dstaddr);
}
trace(TR_ALL, LOG_ERR, NULL);
if_display("if_dupcheck", ifp);
if_display("if_dupcheck", ifp2);
}
}
}
}
/* init_if() determines addresses and names of internet interfaces configured.
* Results returned in global linked list of interface tables.
* The interface names are required for later ioctl calls re interface status.
*
* External variables:
* ifnet - pointer to interface list
* n_interfaces - number of direct internet interfaces (set here)
*/
/*ARGSUSED*/
static void
init_if(tp)
task *tp;
{
int if_index = 0;
#ifndef AF_LINK
char *last_name = 0;
#endif /* AF_LINK */
caddr_t limit;
struct ifconf *ifconf_req;
if_entry *ifp;
struct ifreq *ifrp;
u_long a;
/*
* Determine internet addresses of all internet interfaces
*/
/*
* get interface configuration.
*/
#define IFCONF_BUFSIZE (40 * sizeof(struct ifreq) + 1) /* ioctl assumes > size ifreq */
ifconf_req = (struct ifconf *) malloc(IFCONF_BUFSIZE + sizeof (struct ifconf));
ifconf_req->ifc_buf = (caddr_t) (ifconf_req + 1);
ifconf_req->ifc_len = IFCONF_BUFSIZE;
if (task_ioctl(tp->task_socket, SIOCGIFCONF, (char *) ifconf_req, ifconf_req->ifc_len) < 0) {
trace(TR_ALL, LOG_ERR, "init_if: ioctl SIOCGIFCONF: %m");
quit(errno);
}
#define ifrpsize(x) ((socksize(&(x)->ifr_addr) > sizeof((x)->ifr_addr)) ? \
sizeof(*(x)) + socksize(&(x)->ifr_addr) - sizeof((x)->ifr_addr) : sizeof(*(x)))
limit = (caddr_t) ifconf_req->ifc_req + ifconf_req->ifc_len;
n_interfaces = 0;
for (ifrp = ifconf_req->ifc_req;
(caddr_t) ifrp < limit;
ifrp = (struct ifreq *) ((caddr_t) ifrp + ifrpsize(ifrp))) {
trace(TR_INT, 0, "init_if: interface name %s address %A",
ifrp->ifr_name,
&ifrp->ifr_addr);
trace(TR_INT, 0, NULL);
#ifndef AF_LINK
/* If this is a new interface, bump the index */
if (!last_name || strcmp(ifrp->ifr_name, last_name)) {
if_index++;
last_name = ifrp->ifr_name;
}
#else /* AF_LINK */
if (ifrp->ifr_addr.sa_family == AF_LINK) {
if_index = ((struct sockaddr_dl *) & ifrp->ifr_addr)->sdl_index;
}
#endif /* AF_LINK */
if (ifrp->ifr_addr.sa_family != AF_INET) {
continue;
}
ifp = (if_entry *) malloc(sizeof(if_entry));
if (!ifp) {
trace(TR_ALL, LOG_ERR, "init_if: malloc: %m");
quit(errno);
}
ifp->int_preference = RTPREF_DIRECT; /* Preference not set here */
ifp->int_index = if_index;
if (if_index > int_index_max) {
int_index_max = if_index;
}
/* Copy the interface address */
sockcopy(&ifrp->ifr_addr, &ifp->int_addr);
/* save name for future ioctl calls */
(void) strncpy(ifp->int_name, ifrp->ifr_name, IFNAMSIZ);
/* Get interface flags */
if (task_ioctl(tp->task_socket, SIOCGIFFLAGS, (char *) ifrp, sizeof (*ifrp))) {
trace(TR_ALL, LOG_ERR, "init_if: %s: ioctl SIOCGIFFLAGS: %m",
ifp->int_name);
quit(errno);
}
/*
* Mask off flags that we don't understand as some systems use
* them differently than we do.
*/
ifp->int_state = IFS_INTERFACE | if_flags(ifrp->ifr_flags);
if ((ifp->int_state & IFS_LOOPBACK) || (ifp->int_addr.in.sin_addr.s_addr == htonl(INADDR_LOOPBACK))) {
/* Loopback net is never announced or aged and is not counted towards total interfaces */
ifp->int_state |= IFS_NOAGE | IFS_LOOPBACK;
n_interfaces--;
}
/*
* if interface is marked down, we will include it and try again
* later.
*/
/* get interface metric */
#if defined(SIOCGIFMETRIC) && defined(ifr_metric)
if (task_ioctl(tp->task_socket, SIOCGIFMETRIC, (caddr_t) ifrp, sizeof (*ifrp)) < 0) {
trace(TR_ALL, LOG_ERR, "init_if: %s: ioctl SIOCGIFMETRIC: %m",
ifp->int_name);
quit(errno);
}
ifp->int_metric = (ifrp->ifr_metric >= 0) ? ifrp->ifr_metric : 0;
#else /* defined(SIOCGIFMETRIC) && defined(ifr_metric) */
ifp->int_metric = 0;
#endif /* defined(SIOCGIFMETRIC) && defined(ifr_metric) */
/* Get the destination address for point-to-point interfaces */
if (ifp->int_state & IFS_POINTOPOINT) {
if (task_ioctl(tp->task_socket, SIOCGIFDSTADDR, (caddr_t) ifrp, sizeof (*ifrp)) < 0) {
trace(TR_ALL, LOG_ERR, "init_if: %s: ioctl SIOCGIFDSTADDR: %m",
ifp->int_name);
quit(errno);
}
sockcopy(&ifrp->ifr_dstaddr, &ifp->int_dstaddr);
}
/* Calculate the natural netmask */
sockcopy(IF_ADDR(ifp), &ifp->int_netmask);
sockcopy(&ifp->int_netmask, &ifp->int_net);
a = ntohl(ifp->int_netmask.in.sin_addr.s_addr);
if (IN_CLASSA(a)) {
ifp->int_netmask.in.sin_addr.s_addr = htonl(IN_CLASSA_NET);
} else if (IN_CLASSB(a)) {
ifp->int_netmask.in.sin_addr.s_addr = htonl(IN_CLASSB_NET);
} else {
ifp->int_netmask.in.sin_addr.s_addr = htonl(IN_CLASSC_NET);
}
ifp->int_net.in.sin_addr.s_addr &= ifp->int_netmask.in.sin_addr.s_addr;
/* Calculate or get the subnetmask */
if (ifp->int_state & (IFS_LOOPBACK|IFS_POINTOPOINT)) {
sockcopy(IF_ADDR(ifp), &ifp->int_subnet);
sockcopy(&ifp->int_subnet, &ifp->int_subnetmask);
ifp->int_subnetmask.in.sin_addr.s_addr = htonl(INADDR_BROADCAST);
} else {
#ifdef SIOCGIFNETMASK
if (task_ioctl(tp->task_socket, SIOCGIFNETMASK, (caddr_t) ifrp, sizeof (*ifrp)) < 0) {
trace(TR_ALL, LOG_ERR, "init_if: %s: ioctl SIOGIFNETMASK: %m",
ifp->int_name);
quit(errno);
}
sockcopy(&ifrp->ifr_addr, &ifp->int_subnetmask);
#ifdef BSD4_4
/* Masks don't have an address family specified */
if (ifp->int_subnetmask.a.sa_family == AF_UNSPEC) {
ifp->int_subnetmask.a.sa_family = ifp->int_addr.a.sa_family;
}
#endif /* BSD4_4 */
#else /* SIOCGIFNETMASK */
sockcopy(&ifp->int_netmask, &ifp->int_subnetmask);
sockcopy(&ifp->int_net, &ifp->int_subnet);
#endif /* SIOCGIFNETMASK */
if (!ifp->int_subnetmask.in.sin_addr.s_addr) {
sockcopy(&ifp->int_netmask, &ifp->int_subnetmask);
} else if (!equal(&ifp->int_subnetmask, &ifp->int_netmask)) {
ifp->int_state |= IFS_SUBNET;
}
sockcopy(&ifp->int_addr, &ifp->int_subnet);
ifp->int_subnet.in.sin_addr.s_addr &= ifp->int_subnetmask.in.sin_addr.s_addr;
}
/* Get the broadcast address for broadcast interfaces */
if (ifp->int_state & IFS_BROADCAST) {
#ifdef SIOCGIFBRDADDR
if (task_ioctl(tp->task_socket, SIOCGIFBRDADDR, (caddr_t) ifrp, sizeof (*ifrp)) < 0) {
trace(TR_ALL, LOG_ERR, "init_if: %s: ioctl SIOGIFBRDADDR: %m",
ifp->int_name);
quit(errno);
}
sockcopy(&ifrp->ifr_broadaddr, &ifp->int_broadaddr);
#else /* !SIOCGIFBRDADDR */
/* Assume a 4.2 based system with a zeros broadcast */
sockcopy(&ifp->int_net, &ifp->int_broadaddr);
#endif /* SIOCGIFBRDADDR */
}
/* Add new interface to the end of the interface list */
if (ifnet) {
/* Entries on the list, search for the end */
if_entry *ifp2;
for (ifp2 = ifnet; ifp2->int_next; ifp2 = ifp2->int_next) ;
ifp->int_next = ifp2->int_next;
ifp2->int_next = ifp;
} else {
/* Nothing on the list yet, put this first */
ifp->int_next = ifnet;
ifnet = ifp;
}
if_display("init_if", ifp);
n_interfaces++;
}
if (!n_interfaces) {
trace(TR_ALL, LOG_ERR, "init_if: Exit no interfaces");
quit(ENOENT);
}
free((caddr_t) ifconf_req);
if_dupcheck();
}
/*
* if_check() checks the current status of all interfaces
* If any interface has changed status, then the interface values
* are re-read from the kernel and re-set.
*/
/*ARGSUSED*/
void
if_check(tip, interval)
timer *tip;
time_t interval;
{
register if_entry *ifp;
struct ifreq ifrequest;
u_long a;
task *tp = tip->timer_task;
rt_open(if_task);
IF_LIST(ifp) {
(void) strcpy(ifrequest.ifr_name, ifp->int_name);
/* get interface status flags */
if (task_ioctl(tp->task_socket, SIOCGIFFLAGS, (char *) &ifrequest, sizeof (ifrequest)) < 0) {
trace(TR_ALL, LOG_ERR, "if_check: %s: ioctl SIOCGIFFLAGS: %m",
ifp->int_name);
quit(errno);
} else {
if ((ifrequest.ifr_flags & IFF_UP) != (ifp->int_state & IFS_UP)) {
ifp->int_state = if_flags(ifrequest.ifr_flags) | (ifp->int_state & IFS_KEEPMASK);
if (ifrequest.ifr_flags & IFF_UP) {
/* Get the interface address */
if (task_ioctl(tp->task_socket, SIOCGIFADDR, (char *) &ifrequest, sizeof (ifrequest)) < 0) {
trace(TR_ALL, LOG_ERR, "if_check: %s: ioctl SIOCGIFADDR: %m",
ifp->int_name);
quit(errno);
}
sockcopy(&ifrequest.ifr_addr, &ifp->int_addr);
/* Get the destination address for point-to-point interfaces */
if (ifp->int_state & IFS_POINTOPOINT) {
if (task_ioctl(tp->task_socket, SIOCGIFDSTADDR, (char *) &ifrequest, sizeof (ifrequest)) < 0) {
trace(TR_ALL, LOG_ERR, "if_check: %s: ioctl SIOCGIFDSTADDR: %m",
ifp->int_name);
quit(errno);
}
}
sockcopy(&ifrequest.ifr_dstaddr, &ifp->int_dstaddr);
/* Get the new interface metric */
if (!(ifp->int_state & IFS_METRICSET)) {
/* If config file specified a metric, do not reset it */
#if defined(SIOCGIFMETRIC) && defined(ifr_metric)
(void) strcpy(ifrequest.ifr_name, ifp->int_name);
if (task_ioctl(tp->task_socket, SIOCGIFMETRIC, (char *) &ifrequest, sizeof (ifrequest)) < 0) {
trace(TR_ALL, LOG_ERR, "if_check: %s: ioctl SIOCGIFMETRIC: %m",
ifp->int_name);
quit(errno);
}
ifp->int_metric = (ifrequest.ifr_metric >= 0) ? ifrequest.ifr_metric : 0;
#else /* defined(SIOCGIFMETRIC) && defined(ifr_metric) */
ifp->int_metric = 0;
#endif /* defined(SIOCGIFMETRIC) && defined(ifr_metric) */
}
/* Calculate the natural netmask */
sockcopy(IF_ADDR(ifp), &ifp->int_netmask);
sockcopy(&ifp->int_netmask, &ifp->int_net);
a = ntohl(ifp->int_netmask.in.sin_addr.s_addr);
if (IN_CLASSA(a)) {
ifp->int_netmask.in.sin_addr.s_addr = htonl(IN_CLASSA_NET);
} else if (IN_CLASSB(a)) {
ifp->int_netmask.in.sin_addr.s_addr = htonl(IN_CLASSB_NET);
} else {
ifp->int_netmask.in.sin_addr.s_addr = htonl(IN_CLASSC_NET);
}
ifp->int_net.in.sin_addr.s_addr &= ifp->int_netmask.in.sin_addr.s_addr;
/* Get or calculate the subnetmask */
if (ifp->int_state & (IFS_LOOPBACK|IFS_POINTOPOINT)) {
sockcopy(IF_ADDR(ifp), &ifp->int_subnet);
sockcopy(&ifp->int_subnet, &ifp->int_subnetmask);
ifp->int_subnetmask.in.sin_addr.s_addr = htonl(INADDR_BROADCAST);
} else {
#ifdef SIOCGIFNETMASK
if (task_ioctl(tp->task_socket, SIOCGIFNETMASK, (char *) &ifrequest, sizeof (ifrequest)) < 0) {
trace(TR_ALL, LOG_ERR, "if_check: %s: ioctl SIOCGIFNETMASK: %m",
ifp->int_name);
quit(errno);
}
sockcopy(&ifrequest.ifr_addr, &ifp->int_subnetmask);
#ifdef BSD4_4
/* Masks don't have an address family specified */
if (ifp->int_subnetmask.a.sa_family == AF_UNSPEC) {
ifp->int_subnetmask.a.sa_family = ifp->int_addr.a.sa_family;
}
#endif /* BSD4_4 */
#else /* SIOCGIFNETMASK */
sockcopy(&ifp->int_netmask, &ifp->int_subnetmask);
sockcopy(&ifp->int_net, &ifp->int_subnet);
#endif /* SIOCGIFNETMASK */
if (!ifp->int_subnetmask.in.sin_addr.s_addr) {
sockcopy(&ifp->int_netmask, &ifp->int_subnetmask);
} else if (!equal(&ifp->int_subnetmask, &ifp->int_netmask)) {
ifp->int_state |= IFS_SUBNET;
}
sockcopy(&ifp->int_addr, &ifp->int_subnet);
ifp->int_subnet.in.sin_addr.s_addr &= ifp->int_subnetmask.in.sin_addr.s_addr;
}
/* Get the broadcast address */
if (ifp->int_state & IFS_BROADCAST) {
#ifdef SIOCGIFBRDADDR
(void) strcpy(ifrequest.ifr_name, ifp->int_name);
if (task_ioctl(tp->task_socket, SIOCGIFBRDADDR, (char *) &ifrequest, sizeof (ifrequest)) < 0) {
trace(TR_ALL, LOG_ERR, "if_check: %s: ioctl SIOCGIFBRDADDR: %m",
ifp->int_name);
quit(errno);
}
sockcopy(&ifrequest.ifr_broadaddr, &ifp->int_broadaddr);
#else /* !SIOCGIFBRDADDR */
sockcopy(&ifp->int_net, &ifp->int_broadaddr);
#endif /* SIOCGIFBRDADDR */
}
trace(TR_INT, LOG_NOTICE, "if_check: %s, address %A up",
ifp->int_name,
(ifp->int_state & IFS_POINTOPOINT) ? &ifp->int_dstaddr : &ifp->int_addr);
if_display("if_check", ifp);
if_rtup(ifp);
} else {
trace(TR_INT, LOG_NOTICE, "if_check: %s, address %A down",
ifp->int_name,
(ifp->int_state & IFS_POINTOPOINT) ? &ifp->int_dstaddr : &ifp->int_addr);
if_rtdown(ifp);
}
task_ifchange(ifp);
}
}
} IF_LISTEND(ifp) ;
if (rt_close(if_task, (gw_entry *) 0, 0)) {
task_flash(if_task);
}
if_dupcheck();
}
/*
* Dump the interface list
*/
static void
if_dump(fd)
FILE *fd;
{
if_entry *ifp;
/*
* Print out all of the interface stuff.
*/
(void) fprintf(fd, "Interface Stats:\n\n\t\tInterfaces: %d (does not include loopback interface)\n\n", n_interfaces);
IF_LIST(ifp) {
(void) fprintf(fd, "\t%s\t%A\t\tIndex: %d\tPreference: %d\tMetric: %d\n",
ifp->int_name,
&ifp->int_addr,
ifp->int_index,
ifp->int_preference,
ifp->int_metric);
(void) fprintf(fd, "\t\tUp-down transitions: %u", ifp->int_transitions);
(void) fprintf(fd, "\t\tFlags: <%s>\n", trace_bits(if_flag_bits, ifp->int_state));
if (ifp->int_state & IFS_BROADCAST) {
(void) fprintf(fd, "\t\tBroadcast Address: %A\n",
&ifp->int_broadaddr);
}
if (ifp->int_state & IFS_POINTOPOINT) {
(void) fprintf(fd, "\t\tDestination Address: %A\n",
&ifp->int_dstaddr);
}
(void) fprintf(fd, "\t\tNet Number: %A\t\tNet Mask: %A\n",
&ifp->int_net,
&ifp->int_netmask);
(void) fprintf(fd, "\t\tSubnet Number: %A\t\tSubnet Mask: %A\n",
&ifp->int_subnet,
&ifp->int_subnetmask);
(void) fprintf(fd, "\n");
} IF_LISTEND(ifp) ;
}
/*
* Get ready for a reconfig
*/
void
if_cleanup(tp)
task *tp;
{
if_entry *ifp;
if_rtactive = FALSE;
IF_LIST(ifp) {
ifp->int_state &= ~(IFS_NOICMPIN|IFS_NORIPIN|IFS_NORIPOUT|IFS_NOHELLOIN|IFS_NOHELLOOUT);
if (!(ifp->int_state & IFS_LOOPBACK)) {
ifp->int_state &= ~(IFS_NOAGE);
}
} IF_LISTEND(ifp) ;
}
/*
* Initialize task for interface check
*/
void
if_init()
{
int save_test_flag = test_flag;
test_flag = FALSE;
if_task = task_alloc("IF");
if_task->task_rtproto = RTPROTO_DIRECT;
if_task->task_socket = task_get_socket(AF_INET, SOCK_DGRAM, 0);
if_task->task_dump = if_dump;
if_task->task_cleanup = if_cleanup;
/* XXX - need a task_reinit to reset interface options (NOAGE, NORIP*, NOHELLO*) */
/* XXX - also need an IFS_DELETE flag and a task_cleanup */
if (if_task->task_socket < 0) {
quit(errno);
}
if (!task_create(if_task, 0)) {
quit(EINVAL);
}
(void) timer_create(if_task,
0,
"Check",
0,
(time_t) IF_CHECK_INTERVAL,
if_check);
init_if(if_task);
test_flag = save_test_flag;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.