blob: de6b35ba19d4da822ccc4e537a08dd233102230d [file] [log] [blame]
From 43875b17a5d2a1cbeaeee2ebc9e1eff4919b000c Mon Sep 17 00:00:00 2001
From: Paul Stewart <pstew@chromium.org>
Date: Wed, 13 May 2015 11:09:20 -0700
Subject: [PATCH] dhcpcd: Allow lease file to be set on command line
Currently, dhcpcd names its lease files using the interface name
as the unique part of the name. There are a couple reasons why
this may not work well: firstly if "eth0" can have different MAC
addresses (multiple USB-Ethernet dongles for example) leases for
one interface aren't valid for the other. Secondly, when using
a wireless interface, it would be convenient to hold multiple
leases in parallel for each SSID one is connected to.
This change adds a suffix to each interface argument (dhcpcd can
accept multiple interface arguments) that specifies the identifier
to use to save lease files with. By default, the behavior is
identical.
The second CL (https://gerrit.chromium.org/gerrit/22170) for fixing
pid file formating bug originally introduced by this CL is not needed
anymore since this bug doesn't exist/apply in the updated implementation.
BUG=chromium-os:25717
TEST=Re-run dhcpcd with and without an identifier suffix.
Reviewed-on: https://gerrit.chromium.org/gerrit/21991
Reviewed-on: https://gerrit.chromium.org/gerrit/22170
---
dhcp-common.c | 8 ++++++++
dhcp.h | 2 +-
dhcpcd.8.in | 6 ++++++
dhcpcd.c | 22 +++++++++++++++-----
dhcpcd.h | 2 ++
if.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++------------
if.h | 2 ++
7 files changed, 88 insertions(+), 19 deletions(-)
diff --git a/dhcp-common.c b/dhcp-common.c
index 2936b55..39d9787 100644
--- a/dhcp-common.c
+++ b/dhcp-common.c
@@ -741,6 +741,14 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family,
return 0;
}
+ if (strlen(ifp->lease_identifier) > 0) {
+ /* Only supports lease identifier for IPv4 for now. */
+ if (family == AF_INET) {
+ return snprintf(leasefile, len, LEASEFILE,
+ ifp->lease_identifier, "", "");
+ }
+ }
+
switch (family) {
case AF_INET:
case AF_INET6:
diff --git a/dhcp.h b/dhcp.h
index acef896..ed94395 100644
--- a/dhcp.h
+++ b/dhcp.h
@@ -228,7 +228,7 @@ struct dhcp_state {
struct in_addr dst;
uint8_t added;
- char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDSIZE * 4)];
+ char leasefile[PATH_MAX];
time_t start_uptime;
unsigned char *clientid;
diff --git a/dhcpcd.8.in b/dhcpcd.8.in
index a67626a..e815620 100644
--- a/dhcpcd.8.in
+++ b/dhcpcd.8.in
@@ -191,6 +191,12 @@ changes the routes to use the interface with the same route and the lowest
metric.
See options below for controlling which interfaces we allow and deny through
the use of patterns.
+.Pp
+If an interface name is suffixed by an equal-sign, the text following the
+equal sign will be used instead of the interface name as the unique identifier
+for the DHCP lease file. Doing so allows the caller to specify different
+lease files for the same interface (e.g, when switching the same wireless
+interface between different 802.11 networks).
.Ss Hooking into events
.Nm
runs
diff --git a/dhcpcd.c b/dhcpcd.c
index 9528dc8..763e06f 100644
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -1362,6 +1362,7 @@ main(int argc, char **argv)
int sig;
const char *siga;
#endif
+ char ifn[IF_NAMESIZE];
/* Test for --help and --version */
if (argc > 1) {
@@ -1523,13 +1524,15 @@ main(int argc, char **argv)
* instance for that interface. */
if (optind == argc - 1 && !(ctx.options & DHCPCD_MASTER)) {
const char *per;
-
- if (strlen(argv[optind]) > IF_NAMESIZE) {
+ int intf_len = strlen(argv[optind]);
+ split_interface_lease(argv[optind], &intf_len, NULL);
+ if (intf_len > IF_NAMESIZE) {
logger(&ctx, LOG_ERR,
"%s: interface name too long",
argv[optind]);
goto exit_failure;
}
+ strlcpy(ifn, argv[optind], intf_len + 1);
/* Allow a dhcpcd interface per address family */
switch(family) {
case AF_INET:
@@ -1542,7 +1545,7 @@ main(int argc, char **argv)
per = "";
}
snprintf(ctx.pidfile, sizeof(ctx.pidfile),
- PIDFILE, "-", argv[optind], per);
+ PIDFILE, "-", ifn, per);
} else {
snprintf(ctx.pidfile, sizeof(ctx.pidfile),
PIDFILE, "", "", "");
@@ -1780,10 +1783,19 @@ main(int argc, char **argv)
goto exit_failure;
}
for (i = 0; i < ctx.ifc; i++) {
- if (if_find(ctx.ifaces, ctx.ifv[i]) == NULL)
+ int intf_len = strlen(ctx.ifv[i]);
+ split_interface_lease(ctx.ifv[i], &intf_len, NULL);
+ if (intf_len > IF_NAMESIZE) {
logger(&ctx, LOG_ERR,
- "%s: interface not found or invalid",
+ "%s: interface name too long",
ctx.ifv[i]);
+ continue;
+ }
+ strlcpy(ifn, ctx.ifv[i], intf_len + 1);
+ if (if_find(ctx.ifaces, ifn) == NULL)
+ logger(&ctx, LOG_ERR,
+ "%s: interface not found or invalid",
+ ifn);
}
if (TAILQ_FIRST(ctx.ifaces) == NULL) {
if (ctx.ifc == 0)
diff --git a/dhcpcd.h b/dhcpcd.h
index 8b34997..ae2b0ce 100644
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -40,6 +40,7 @@
#define IF_SSIDSIZE 33
#define PROFILE_LEN 64
#define SECRET_LEN 64
+#define LEASE_IDENTIFIER_LEN (PATH_MAX - sizeof(LEASEFILE))
#define LINK_UP 1
#define LINK_UNKNOWN 0
@@ -73,6 +74,7 @@ struct interface {
int wireless;
uint8_t ssid[IF_SSIDSIZE];
unsigned int ssid_len;
+ char lease_identifier[LEASE_IDENTIFIER_LEN];
char profile[PROFILE_LEN];
struct if_options *options;
diff --git a/if.c b/if.c
index 2f1a7e5..683021f 100644
--- a/if.c
+++ b/if.c
@@ -74,6 +74,34 @@
#undef IFLR_ACTIVE
#endif
+int
+split_interface_lease(const char *ifname, int *interface_name_len,
+ const char **lease_identifier)
+{
+ int ret = 0;
+ int len;
+ const char *lease_ptr = ifname;
+ const char *p = strchr(ifname, '=');
+
+ if (interface_name_len)
+ len = *interface_name_len;
+ else
+ len = strlen(ifname);
+
+ if (p) {
+ lease_ptr = p + 1;
+ if (len > p - ifname)
+ len = p - ifname;
+ ret = 1;
+ }
+
+ if (interface_name_len)
+ *interface_name_len = len;
+ if (lease_identifier)
+ *lease_identifier = lease_ptr;
+ return ret;
+}
+
void
if_free(struct interface *ifp)
{
@@ -229,9 +257,13 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
int i;
struct if_head *ifs;
struct interface *ifp;
-#ifdef __linux__
+ const char *lease_identifier;
char ifn[IF_NAMESIZE];
+
+#ifdef __linux__
+ char alias[IF_NAMESIZE];
#endif
+
#ifdef AF_LINK
const struct sockaddr_dl *sdl;
#ifdef SIOCGIFPRIORITY
@@ -287,28 +319,31 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
if (ifp)
continue;
+ lease_identifier = NULL;
if (argc > 0) {
for (i = 0; i < argc; i++) {
+ int intf_len = strlen(argv[i]);
+ split_interface_lease(argv[i], &intf_len,
+ &lease_identifier);
+ if (intf_len > IF_NAMESIZE)
+ continue;
+ strlcpy(ifn, argv[i], intf_len + 1);
#ifdef __linux__
+ strlcpy(alias, argv[i], intf_len + 1);
/* Check the real interface name */
- strlcpy(ifn, argv[i], sizeof(ifn));
p = strchr(ifn, ':');
if (p)
*p = '\0';
+#endif
if (strcmp(ifn, ifa->ifa_name) == 0)
break;
-#else
- if (strcmp(argv[i], ifa->ifa_name) == 0)
- break;
-#endif
}
if (i == argc)
continue;
- p = argv[i];
} else {
- p = ifa->ifa_name;
-#ifdef __linux__
strlcpy(ifn, ifa->ifa_name, sizeof(ifn));
+#ifdef __linux
+ strlcpy(alias, ifa->ifa_name, sizeof(alias));
#endif
/* -1 means we're discovering against a specific
* interface, but we still need the below rules
@@ -316,6 +351,8 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
continue;
}
+ p = ifn;
+
for (i = 0; i < ctx->ifdc; i++)
if (!fnmatch(ctx->ifdv[i], p, 0))
break;
@@ -351,11 +388,13 @@ if_discover(struct dhcpcd_ctx *ctx, int argc, char * const *argv)
}
ifp->ctx = ctx;
#ifdef __linux__
- strlcpy(ifp->name, ifn, sizeof(ifp->name));
- strlcpy(ifp->alias, p, sizeof(ifp->alias));
-#else
- strlcpy(ifp->name, p, sizeof(ifp->name));
+ strlcpy(ifp->alias, alias, sizeof(ifp->alias));
#endif
+ strlcpy(ifp->name, p, sizeof(ifp->name));
+ if (lease_identifier) {
+ strlcpy(ifp->lease_identifier, lease_identifier,
+ sizeof(ifp->lease_identifier));
+ }
ifp->flags = ifa->ifa_flags;
ifp->carrier = if_carrier(ifp);
diff --git a/if.h b/if.h
index cda4c01..a4c67a6 100644
--- a/if.h
+++ b/if.h
@@ -105,6 +105,8 @@ int if_domtu(const char *, short int);
#define if_getmtu(iface) if_domtu(iface, 0)
#define if_setmtu(iface, mtu) if_domtu(iface, mtu)
int if_carrier(struct interface *);
+int split_interface_lease(const char *ifname, int *ifname_len,
+ const char **lease_identifier);
/* The below functions are provided by if-KERNEL.c */
int if_conf(struct interface *);
--
2.2.0.rc0.207.ga3a616c