As such, we can wait for a 3RDPARTY to configure the interface, such as PPP.
We can then take the destination addess and automatically give it a default
route or any other DHCP option such as DNS servers.
This addresses #159.
struct rt *r;
if (iface->net.s_addr == INADDR_BROADCAST ||
- iface->net.s_addr == INADDR_ANY)
+ iface->net.s_addr == INADDR_ANY ||
+ (iface->state->options->options &
+ (DHCPCD_INFORM | DHCPCD_STATIC) &&
+ iface->state->options->req_addr.s_addr == INADDR_ANY))
return rt;
-
+
r = xmalloc(sizeof(*r));
r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
r->net.s_addr = iface->net.s_addr;
return get_option_routes(iface->state->new);
}
-static void
-build_routes()
+void
+build_routes(void)
{
struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
const struct interface *ifp;
delete_address(struct interface *iface)
{
int retval;
+ struct if_options *ifo;
+ ifo = iface->state->options;
+ if (ifo->options & DHCPCD_INFORM ||
+ (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
+ return 0;
syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
iface->name,
inet_ntoa(iface->addr),
sort_interfaces();
if (dhcp == NULL) {
- if (iface->addr.s_addr != 0) {
- build_routes();
+ build_routes();
+ if (iface->addr.s_addr != 0)
delete_address(iface);
- }
run_script(iface);
return 0;
}
int send_interface(int, const struct interface *);
int run_script(const struct interface *);
+void build_routes(void);
int configure(struct interface *);
int route_deleted(const struct rt *);
#endif
if (opt->option == n)
match = 1;
}
- if (match) {
- if (add == 1)
+ if (match) {
+ if (add == 2 && !(opt->type & IPV4)) {
+ free(o);
+ errno = EINVAL;
+ return -1;
+ }
+ if (add == 1 || add == 2)
add_option_mask(mask,
opt->option);
else
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 15, 2009
+.Dd March 19, 2009
.Dt DHCPCD.SH 8 SMM
.Os
.Sh NAME
.It Dv STATIC
dhcpcd has been configured with a static configuration which has not been
obtained from a DHCP server.
+.It Dv 3RDPARTY
+dhcpcd is monitoring the interface for a 3rd party to give it an IP address.
.It Dv TIMEOUT
dhcpcd failed to contact any DHCP servers but was able to use an old lease.
.It Dv EXPIRE
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 10, 2009
+.Dd March 19, 2009
.Dt DHCPCD 8 SMM
.Os
.Sh NAME
which is a space or comma separated list of patterns passed to
.Xr fnmatch 3 .
.El
+.Sh 3RDPARTY LINK MANAGEMENT
+Some interfaces require configuration by 3rd parties, such as PPP or VPN.
+When an interface configuration in
+.Nm
+is marked as STATIC or INFORM without an address then
+.Nm
+will monitor the interface until an address is added or removed from it and
+act accordingly.
+For point to point interfaces (like PPP), a default route to it's
+destination is automatically added to the configuration.
+If the point to point interface if configured for INFORM, then
+.Nm
+unicasts INFORM to the destination.
.Sh NOTES
.Nm
requires a Berkley Packet Filter, or BPF device on BSD based systems and a
#include <sys/uio.h>
#include <arpa/inet.h>
+#include <net/route.h>
#include <ctype.h>
#include <errno.h>
free_options(ifs->options);
ifo = ifs->options = read_config(cffile, iface->name, iface->ssid);
add_options(ifo, argc, argv);
-
+ if (iface->flags & IFF_NOARP)
+ ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
+ if (ifo->options & DHCPCD_LINK && carrier_status(iface->name) == -1)
+ ifo->options &= ~DHCPCD_LINK;
+
if (ifo->metric != -1)
iface->metric = ifo->metric;
*p++ = DHO_SUBNETMASK;
*p++ = sizeof(mask->s_addr);
memcpy(p, &mask->s_addr, sizeof(mask->s_addr));
+ p+= sizeof(mask->s_addr);
}
*p++ = DHO_END;
return dhcp;
}
+static int
+handle_3rdparty(struct interface *iface)
+{
+ struct if_options *ifo;
+ struct in_addr addr, net, dst;
+
+ ifo = iface->state->options;
+ if (ifo->req_addr.s_addr != INADDR_ANY)
+ return 0;
+
+ if (get_address(iface->name, &addr, &net, &dst) == 1)
+ handle_ifa(RTM_NEWADDR, iface->name, &addr, &net, &dst);
+ else {
+ syslog(LOG_INFO,
+ "%s: waiting for 3rd party to configure IP address",
+ iface->name);
+ iface->state->reason = "3RDPARTY";
+ run_script(iface);
+ }
+ return 1;
+}
+
static void
start_static(struct interface *iface)
{
- struct if_options *ifo = iface->state->options;
+ struct if_options *ifo;
- iface->state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
+ if (handle_3rdparty(iface))
+ return;
+ ifo = iface->state->options;
+ iface->state->offer =
+ dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
delete_timeout(NULL, iface);
bind_interface(iface);
}
static void
start_inform(struct interface *iface)
{
- struct if_options *ifo = iface->state->options;
+ if (handle_3rdparty(iface))
+ return;
- ifo->options |= DHCPCD_STATIC;
+ iface->state->options->options |= DHCPCD_STATIC;
start_static(iface);
- ifo->options &= ~DHCPCD_STATIC;
+ iface->state->options->options &= ~DHCPCD_STATIC;
iface->state->state = DHS_INFORM;
iface->state->xid = arc4random();
struct timeval now;
uint32_t l;
+ handle_carrier(iface->name);
if (iface->carrier == LINK_DOWN) {
syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
return;
start_inform(iface);
return;
}
+ if (iface->hwlen == 0 && ifo->clientid[0] == '\0') {
+ syslog(LOG_WARNING, "%s: needs a clientid to configure",
+ iface->name);
+ return;
+ }
if (ifo->req_addr.s_addr) {
- iface->state->offer = dhcp_message_new(&ifo->req_addr,
- &ifo->req_mask);
+ iface->state->offer =
+ dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
if (ifo->options & DHCPCD_REQUEST)
ifo->req_addr.s_addr = 0;
else {
iface->carrier = LINK_UNKNOWN;
}
-static void
-handle_new_interface(const char *ifname)
+void
+handle_interface(int action, const char *ifname)
{
struct interface *ifs, *ifp, *ifn, *ifl = NULL;
const char * const argv[] = { "dhcpcd", ifname };
int i;
+ if (action == -1) {
+ ifp = find_interface(ifname);
+ if (ifp != NULL)
+ stop_interface(ifp);
+ return;
+ } else if (action == 0) {
+ handle_carrier(ifname);
+ return;
+ }
+
/* If running off an interface list, check it's in it. */
if (ifc) {
for (i = 0; i < ifc; i++)
}
}
-static void
-handle_remove_interface(const char *ifname)
+static int
+dhcp_message_add_addr(struct dhcp_message *dhcp, char c, struct in_addr *addr)
{
- struct interface *iface;
+ uint8_t *p;
+ size_t len;
- iface = find_interface(ifname);
- if (iface != NULL)
- stop_interface(iface);
+ p = dhcp->options;
+ while (*p != DHO_END) {
+ p++;
+ p += *p + 1;
+ }
+
+ len = p - (uint8_t *)dhcp;
+ if (len + 6 > sizeof(*dhcp)) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ *p++ = c;
+ *p++ = sizeof(addr->s_addr);
+ memcpy(p, &addr->s_addr, sizeof(addr->s_addr));
+ p += sizeof(addr->s_addr);
+ *p = DHO_END;
+ return 0;
+}
+
+void
+handle_ifa(int type, const char *ifname,
+ struct in_addr *addr, struct in_addr *net, struct in_addr *dst)
+{
+ struct interface *ifp;
+ struct if_options *ifo;
+ int i;
+
+ if (addr->s_addr == INADDR_ANY)
+ return;
+ for (ifp = ifaces; ifp; ifp = ifp->next)
+ if (strcmp(ifp->name, ifname) == 0)
+ break;
+ if (ifp == NULL)
+ return;
+ ifo = ifp->state->options;
+ if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)) == 0 ||
+ ifo->req_addr.s_addr != INADDR_ANY)
+ return;
+
+ switch (type) {
+ case RTM_DELADDR:
+ if (ifp->state->new &&
+ ifp->state->new->yiaddr == addr->s_addr)
+ drop_config(ifp, "EXPIRE");
+ break;
+ case RTM_NEWADDR:
+ if (ifo->options & DHCPCD_INFORM) {
+ ifp->state->state = DHS_INFORM;
+ ifp->state->xid = arc4random();
+ ifp->addr = *addr;
+ ifp->net = *net;
+ ifp->state->lease.server = *dst;
+ open_sockets(ifp);
+ send_inform(ifp);
+ } else {
+ free(ifp->state->old);
+ ifp->state->old = ifp->state->new;
+ ifp->state->new = dhcp_message_new(addr, net);
+ if (dst) {
+ for (i = 1; i < 255; i++)
+ if (has_option_mask(ifo->dstmask, i))
+ dhcp_message_add_addr(
+ ifp->state->new,
+ i, dst);
+ }
+ ifp->state->reason = "STATIC";
+ build_routes();
+ run_script(ifp);
+ }
+ break;
+ }
}
/* ARGSUSED */
static void
handle_link(_unused void *arg)
{
- if (manage_link(linkfd,
- handle_carrier,
- handle_new_interface,
- handle_remove_interface) == -1)
+ if (manage_link(linkfd))
syslog(LOG_ERR, "manage_link: %m");
}
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 10, 2009
+.Dd March 19, 2009
.Dt DHCPCD.CONF 5 SMM
.Os
.Sh NAME
.Xr dhcpcd-run-hooks 8
or the numerical value.
You can specify more options seperated by commas, spaces or more option lines.
-.Ic quiet
+.It Ic destination Ar option
+If
+.Nm
+detects an address added to a point to point interface (PPP, TUN, etc) then
+it will set the listed DHCP options to the destination address of the
+interface.
+.It Ic quiet
Supress any dhcpcd output to the console, except for errors.
-.Ic reboot Ar seconds
+.It Ic reboot Ar seconds
Allow
.Ar reboot
seconds before moving to the discover phase if we have an old lease to use.
.D1 static ip_address=192.168.0.10/24
.D1 static routers=192.168.0.1
.D1 static domain_name_servers=192.168.0.1
+.Pp
+Here is an example for PPP which gives the destination a default route.
+It uses the special destination keyword to insert the destination address
+into the value.
+.D1 interface ppp0
+.D1 static ip_address=
+.D1 destination routers
.It Ic timeout Ar seconds
The default timeout for waiting for a DHCP response is 30 seconds which may
be too long or too short and can be changed here.
char name[IF_NAMESIZE];
struct if_state *state;
+ int flags;
sa_family_t family;
unsigned char hwaddr[HWADDR_LEN];
size_t hwlen;
struct interface *find_interface(const char *);
int handle_args(struct fd_list *, int, char **);
+void handle_interface(int, const char *);
+void handle_ifa(int, const char *,
+ struct in_addr *, struct in_addr *, struct in_addr *);
void handle_exit_timeout(void *);
void start_interface(void *);
void start_discover(void *);
#include "if-options.h"
#include "net.h"
-#define ROUNDUP(a) \
+#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-/* Darwin doesn't define this for some very odd reason */
-#ifndef SA_SIZE
-# define SA_SIZE(sa) \
- ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
- sizeof(long) : \
- 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | \
- (sizeof(long) - 1) ) )
-#endif
+/* FIXME: Why do we need to check for sa_family 255 */
+#define COPYOUT(sin, sa) \
+ sin.s_addr = ((sa) != NULL && ((sa)->sa_family == AF_INET || \
+ (sa)->sa_family == 255)) \
+ ? \
+ (((struct sockaddr_in *)sa)->sin_addr).s_addr : 0
static int a_fd = -1;
static int r_fd = -1;
memset(&ifa, 0, sizeof(ifa));
strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
-#define ADDADDR(_var, _addr) { \
- _s.sa = &_var; \
- _s.sin->sin_family = AF_INET; \
- _s.sin->sin_len = sizeof(*_s.sin); \
- memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \
+#define ADDADDR(_var, _addr) { \
+ _s.sa = &_var; \
+ _s.sin->sin_family = AF_INET; \
+ _s.sin->sin_len = sizeof(*_s.sin); \
+ memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \
}
ADDADDR(ifa.ifra_addr, address);
size_t l;
int retval = 0;
-#define ADDSU(_su) { \
- l = SA_SIZE(&(_su.sa)); \
- memcpy(bp, &(_su), l); \
- bp += l; \
- }
-#define ADDADDR(_addr) { \
- memset (&su, 0, sizeof(su)); \
- su.sin.sin_family = AF_INET; \
- su.sin.sin_len = sizeof(su.sin); \
- memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
- ADDSU(su); \
+#define ADDSU(_su) { \
+ l = ROUNDUP(_su.sa.sa_len); \
+ memcpy(bp, &(_su), l); \
+ bp += l; \
+ }
+#define ADDADDR(_a) { \
+ memset (&su, 0, sizeof(su)); \
+ su.sin.sin_family = AF_INET; \
+ su.sin.sin_len = sizeof(su.sin); \
+ memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \
+ ADDSU(su); \
}
memset(&rtm, 0, sizeof(rtm));
return fd;
}
+static void
+get_addrs(int type, char *cp, struct sockaddr **sa)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (type & (1 << i)) {
+ sa[i] = (struct sockaddr *)cp;
+#ifdef DEBUG
+ printf ("got %d %d %s\n", i, sa[i]->sa_family,
+ inet_ntoa(((struct sockaddr_in *)sa[i])->
+ sin_addr));
+#endif
+ ADVANCE(cp, sa[i]);
+ } else
+ sa[i] = NULL;
+ }
+}
+
#define BUFFER_LEN 2048
int
-manage_link(int fd,
- void (*if_carrier)(const char *),
- void (*if_add)(const char *),
- void (*if_remove)(const char *))
+manage_link(int fd)
{
- char buffer[2048], *p, *e;
+ char buffer[2048], *p, *e, *cp;
char ifname[IF_NAMESIZE];
ssize_t bytes;
struct rt_msghdr *rtm;
- struct if_announcemsghdr *ifa;
+ struct if_announcemsghdr *ifan;
struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
struct rt rt;
- struct sockaddr *sa;
- struct sockaddr_in *sin;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
for (;;) {
bytes = read(fd, buffer, BUFFER_LEN);
rtm = (struct rt_msghdr *)(void *)p;
switch(rtm->rtm_type) {
case RTM_IFANNOUNCE:
- ifa = (struct if_announcemsghdr *)(void *)p;
- switch(ifa->ifan_what) {
+ ifan = (struct if_announcemsghdr *)(void *)p;
+ switch(ifan->ifan_what) {
case IFAN_ARRIVAL:
- if_add(ifa->ifan_name);
+ handle_interface(1, ifan->ifan_name);
break;
case IFAN_DEPARTURE:
- if_remove(ifa->ifan_name);
+ handle_interface(-1, ifan->ifan_name);
break;
}
break;
ifm = (struct if_msghdr *)(void *)p;
memset(ifname, 0, sizeof(ifname));
if (if_indextoname(ifm->ifm_index, ifname))
- if_carrier(ifname);
+ handle_interface(0, ifname);
break;
case RTM_DELETE:
if (!(rtm->rtm_addrs & RTA_DST) ||
break;
if (rtm->rtm_pid == getpid())
break;
- sa = (struct sockaddr *)(rtm + 1);
+ cp = (char *)(void *)(rtm + 1);
+ sa = (struct sockaddr *)(void *)cp;
if (sa->sa_family != AF_INET)
break;
- rt.next = NULL;
+ get_addrs(rtm->rtm_addrs, cp, rti_info);
rt.iface = NULL;
- sin = (struct sockaddr_in *)(void *)sa;
- memcpy(&rt.dest.s_addr, &sin->sin_addr.s_addr,
- sizeof(rt.dest.s_addr));
- sa = (struct sockaddr *)
- (ROUNDUP(sa->sa_len) + (char *)sa);
- sin = (struct sockaddr_in *)(void *)sa;
- memcpy(&rt.gate.s_addr, &sin->sin_addr.s_addr,
- sizeof(rt.gate.s_addr));
- sa = (struct sockaddr *)
- (ROUNDUP(sa->sa_len) + (char *)sa);
- sin = (struct sockaddr_in *)(void *)sa;
- memcpy(&rt.net.s_addr, &sin->sin_addr.s_addr,
- sizeof(rt.net.s_addr));
+ rt.next = NULL;
+ COPYOUT(rt.dest, rti_info[RTAX_DST]);
+ COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+ COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
route_deleted(&rt);
break;
+ case RTM_DELADDR:
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)(void *)p;
+ cp = (char *)(void *)(ifam + 1);
+ get_addrs(ifam->ifam_addrs, cp, rti_info);
+ COPYOUT(rt.dest, rti_info[RTAX_IFA]);
+ COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
+ COPYOUT(rt.gate, rti_info[RTAX_BRD]);
+ if (if_indextoname(ifam->ifam_index, ifname))
+ handle_ifa(rtm->rtm_type, ifname,
+ &rt.dest, &rt.net, &rt.gate);
+ break;
}
}
}
ifp->hwlen = sdl->sdl_alen;
memcpy(ifp->hwaddr, LLADDR(sdl), sdl->sdl_alen);
break;
- default:
- /* Don't needlessly spam console on startup */
- if (!(options & DHCPCD_MASTER &&
- !(options & DHCPCD_DAEMONISED) &&
- options & DHCPCD_QUIET))
- syslog(LOG_ERR, "%s: unsupported interface type",
- ifr->ifr_name);
- free(ifp);
- ifp = NULL;
+ case IFT_LOOP:
+ /* We don't allow loopback unless requested */
+ if (argc == 0 && ifac == 0) {
+ free(ifp);
+ ifp = NULL;
+ }
break;
}
if (ifl)
{
struct interface *ifs = NULL;
- do_interface(NULL, discover_link, &ifs, argc, argv, NULL, NULL, 2);
+ do_interface(NULL, discover_link, &ifs, argc, argv,
+ NULL, NULL, NULL, 2);
return ifs;
}
{"clientid", optional_argument, NULL, 'I'},
{"nolink", no_argument, NULL, 'K'},
{"noipv4ll", no_argument, NULL, 'L'},
+ {"destination", required_argument, NULL, 'N'},
{"nooption", optional_argument, NULL, 'O'},
{"require", required_argument, NULL, 'Q'},
{"static", required_argument, NULL, 'S'},
case 'L':
ifo->options &= ~DHCPCD_IPV4LL;
break;
+ case 'N':
+ if (make_option_mask(ifo->dstmask, arg, 2) != 0) {
+ if (errno == EINVAL)
+ syslog(LOG_ERR, "option `%s' does not take"
+ " an IPv4 address", arg);
+ else
+ syslog(LOG_ERR, "unknown otpion `%s'", arg);
+ return -1;
+ }
+ break;
case 'O':
if (make_option_mask(ifo->requestmask, arg, -1) != 0 ||
make_option_mask(ifo->requiremask, arg, -1) != 0 ||
rt->next = xmalloc(sizeof(*rt));
rt = rt->next;
}
- rt->dest.s_addr = 0;
- rt->net.s_addr = 0;
+ rt->dest.s_addr = INADDR_ANY;
+ rt->net.s_addr = INADDR_ANY;
rt->next = NULL;
if (parse_addr(&rt->gate, NULL, p) == -1)
return -1;
uint8_t requestmask[256 / 8];
uint8_t requiremask[256 / 8];
uint8_t nomask[256 / 8];
+ uint8_t dstmask[256 / 8];
uint32_t leasetime;
time_t timeout;
time_t reboot;
struct interface *
init_interface(const char *ifname)
{
- int s, arpable;
+ int s;
struct ifreq ifr;
struct interface *iface = NULL;
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1)
goto eexit;
- if (ifr.ifr_flags & IFF_LOOPBACK || ifr.ifr_flags & IFF_POINTOPOINT)
- goto eexit;
- arpable = !(ifr.ifr_flags & IFF_NOARP);
iface = xzalloc(sizeof(*iface));
strlcpy(iface->name, ifname, sizeof(iface->name));
+ iface->flags = ifr.ifr_flags;
/* We reserve the 100 range for virtual interfaces, if and when
* we can work them out. */
iface->metric = 200 + if_nametoindex(iface->name);
goto eexit;
snprintf(iface->leasefile, sizeof(iface->leasefile),
LEASEFILE, ifname);
- iface->arpable = arpable;
/* 0 is a valid fd, so init to -1 */
iface->raw_fd = -1;
iface->udp_fd = -1;
do_interface(const char *ifname,
void (*do_link)(struct interface **, int, char * const *, struct ifreq *),
struct interface **ifs, int argc, char * const *argv,
- struct in_addr *addr, struct in_addr *net, int act)
+ struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
{
int s;
struct ifconf ifc;
continue;
netmask = sin->sin_addr.s_addr;
if (act == 1) {
+ if (dst) {
+ sin = (struct sockaddr_in *)
+ (void *)&ifr->ifr_dstaddr;
+ if (ioctl(s, SIOCGIFDSTADDR, ifr)
+ == -1)
+ dst->s_addr = INADDR_ANY;
+ else
+ dst->s_addr =
+ sin->sin_addr.s_addr;
+ }
addr->s_addr = address;
net->s_addr = netmask;
retval = 1;
if (retval == 1) {
memset(&ifmr, 0, sizeof(ifmr));
strlcpy(ifmr.ifm_name, ifr.ifr_name, sizeof(ifmr.ifm_name));
+ retval = -1;
if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 &&
ifmr.ifm_status & IFM_AVALID)
- {
- if (!(ifmr.ifm_status & IFM_ACTIVE))
- retval = 0;
- }
+ retval = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
}
#endif
close(s);
int do_interface(const char *,
void (*)(struct interface **, int, char * const *, struct ifreq *),
struct interface **, int, char * const *,
- struct in_addr *, struct in_addr *, int);
+ struct in_addr *, struct in_addr *, struct in_addr *, int);
int if_address(const struct interface *,
const struct in_addr *, const struct in_addr *,
const struct in_addr *, int);
#define del_address(iface, addr, net) \
if_address(iface, addr, net, NULL, -1)
#define has_address(iface, addr, net) \
- do_interface(iface, NULL, NULL, 0, NULL, addr, net, 0)
-#define get_address(iface, addr, net) \
- do_interface(iface, NULL, NULL, 0, NULL, addr, net, 1)
+ do_interface(iface, NULL, NULL, 0, NULL, addr, net, NULL, 0)
+#define get_address(iface, addr, net, dst) \
+ do_interface(iface, NULL, NULL, 0, NULL, addr, net, dst, 1)
int if_route(const struct interface *, const struct in_addr *,
const struct in_addr *, const struct in_addr *, int, int);
int init_socket(void);
int open_link_socket(void);
-int manage_link(int,
- void (*)(const char *),
- void (*)(const char *),
- void (*)(const char *));
+int manage_link(int);
int carrier_status(const char *);
#endif