summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2009-03-19 17:52:12 +0000
committerRoy Marples <roy@marples.name>2009-03-19 17:52:12 +0000
commit1abffd5ba55b4e4a2a149001a33349ef39139457 (patch)
tree48da83c4a9a64018cfc66e5566531361b7260a9b
parent194b1fcb081f274e5759158267bf930f1bf57708 (diff)
downloaddhcpcd-1abffd5ba55b4e4a2a149001a33349ef39139457.tar.xz
We can now detected primary addresses added or changed in BSD.
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.
-rw-r--r--configure.c21
-rw-r--r--configure.h1
-rw-r--r--dhcp.c9
-rw-r--r--dhcpcd-run-hooks.8.in4
-rw-r--r--dhcpcd.8.in15
-rw-r--r--dhcpcd.c156
-rw-r--r--dhcpcd.conf.5.in19
-rw-r--r--dhcpcd.h4
-rw-r--r--if-bsd.c143
-rw-r--r--if-options.c15
-rw-r--r--if-options.h1
-rw-r--r--net.c25
-rw-r--r--net.h13
13 files changed, 309 insertions, 117 deletions
diff --git a/configure.c b/configure.c
index d41b03ed..bb1bba50 100644
--- a/configure.c
+++ b/configure.c
@@ -497,9 +497,12 @@ add_subnet_route(struct rt *rt, const struct interface *iface)
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;
@@ -534,8 +537,8 @@ get_routes(const struct interface *iface) {
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;
@@ -591,7 +594,12 @@ static int
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),
@@ -616,10 +624,9 @@ configure(struct interface *iface)
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;
}
diff --git a/configure.h b/configure.h
index d103b6e5..58b78026 100644
--- a/configure.h
+++ b/configure.h
@@ -32,6 +32,7 @@
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
diff --git a/dhcp.c b/dhcp.c
index 2689b734..15b21c98 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -195,8 +195,13 @@ int make_option_mask(uint8_t *mask, const char *opts, int add)
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
diff --git a/dhcpcd-run-hooks.8.in b/dhcpcd-run-hooks.8.in
index 6e025ac1..89525697 100644
--- a/dhcpcd-run-hooks.8.in
+++ b/dhcpcd-run-hooks.8.in
@@ -22,7 +22,7 @@
.\" 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
@@ -91,6 +91,8 @@ dhcpcd failed to contact any DHCP servers but did obtain an IPV4LL address.
.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
diff --git a/dhcpcd.8.in b/dhcpcd.8.in
index eae48484..a1edeebb 100644
--- a/dhcpcd.8.in
+++ b/dhcpcd.8.in
@@ -22,7 +22,7 @@
.\" 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
@@ -461,6 +461,19 @@ When discovering interfaces, the interface name must not match
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
diff --git a/dhcpcd.c b/dhcpcd.c
index 752ca555..2448f5e2 100644
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -33,6 +33,7 @@ const char copyright[] = "Copyright (c) 2006-2009 Roy Marples";
#include <sys/uio.h>
#include <arpa/inet.h>
+#include <net/route.h>
#include <ctype.h>
#include <errno.h>
@@ -663,7 +664,11 @@ configure_interface(struct interface *iface, int argc, char **argv)
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;
@@ -821,17 +826,44 @@ dhcp_message_new(struct in_addr *addr, struct in_addr *mask)
*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);
}
@@ -839,11 +871,12 @@ start_static(struct 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();
@@ -909,6 +942,7 @@ start_interface(void *arg)
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;
@@ -930,9 +964,14 @@ start_interface(void *arg)
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 {
@@ -1019,13 +1058,23 @@ init_state(struct interface *iface, int argc, char **argv)
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++)
@@ -1055,24 +1104,91 @@ handle_new_interface(const char *ifname)
}
}
-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");
}
diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in
index e21e568e..988d74e9 100644
--- a/dhcpcd.conf.5.in
+++ b/dhcpcd.conf.5.in
@@ -22,7 +22,7 @@
.\" 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
@@ -143,9 +143,15 @@ It can be a variable to be used in
.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.
@@ -192,6 +198,13 @@ Here is an example which configures a static address, routes and dns.
.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.
diff --git a/dhcpcd.h b/dhcpcd.h
index d8a5fabd..927f019f 100644
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -82,6 +82,7 @@ struct interface {
char name[IF_NAMESIZE];
struct if_state *state;
+ int flags;
sa_family_t family;
unsigned char hwaddr[HWADDR_LEN];
size_t hwlen;
@@ -118,6 +119,9 @@ extern struct interface *ifaces;
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 *);
diff --git a/if-bsd.c b/if-bsd.c
index 8d5529ca..0db8b304 100644
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -60,17 +60,16 @@
#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;
@@ -139,11 +138,11 @@ if_address(const struct interface *iface, const struct in_addr *address,
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);
@@ -184,17 +183,17 @@ if_route(const struct interface *iface, const struct in_addr *dest,
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));
@@ -272,22 +271,38 @@ open_link_socket(void)
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);
@@ -303,13 +318,13 @@ manage_link(int fd,
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;
@@ -317,7 +332,7 @@ manage_link(int fd,
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) ||
@@ -326,26 +341,30 @@ manage_link(int fd,
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;
}
}
}
@@ -391,15 +410,12 @@ discover_link(struct interface **ifs, int argc, char * const *argv,
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)
@@ -413,6 +429,7 @@ discover_interfaces(int argc, char * const *argv)
{
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;
}
diff --git a/if-options.c b/if-options.c
index c49031df..e7c38d24 100644
--- a/if-options.c
+++ b/if-options.c
@@ -78,6 +78,7 @@ const struct option cf_options[] = {
{"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'},
@@ -543,6 +544,16 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
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 ||
@@ -608,8 +619,8 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
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;
diff --git a/if-options.h b/if-options.h
index 98c2f951..39c390f3 100644
--- a/if-options.h
+++ b/if-options.h
@@ -77,6 +77,7 @@ struct if_options {
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;
diff --git a/net.c b/net.c
index b9cb280c..bfe1fd35 100644
--- a/net.c
+++ b/net.c
@@ -174,7 +174,7 @@ hwaddr_aton(unsigned char *buffer, const char *addr)
struct interface *
init_interface(const char *ifname)
{
- int s, arpable;
+ int s;
struct ifreq ifr;
struct interface *iface = NULL;
@@ -187,12 +187,10 @@ init_interface(const char *ifname)
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);
@@ -243,7 +241,6 @@ init_interface(const char *ifname)
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;
@@ -277,7 +274,7 @@ int
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;
@@ -348,6 +345,16 @@ do_interface(const char *ifname,
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;
@@ -436,12 +443,10 @@ carrier_status(const char *ifname)
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);
diff --git a/net.h b/net.h
index cbac54b5..f0ff3ad0 100644
--- a/net.h
+++ b/net.h
@@ -106,7 +106,7 @@ int up_interface(const char *);
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);
@@ -115,9 +115,9 @@ int if_address(const struct interface *,
#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);
@@ -147,9 +147,6 @@ ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
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