hardware address replied with or the ip address.
uint8_t *hw_s, *hw_t;
ssize_t bytes;
struct if_state *state = iface->state;
+ struct if_options *opts = state->options;
+ const char *hwaddr;
+ struct in_addr ina;
state->fail.s_addr = 0;
for(;;) {
memcpy(&reply_s, hw_s + ar.ar_hln, ar.ar_pln);
memcpy(&reply_t, hw_t + ar.ar_hln, ar.ar_pln);
+ /* Check for arping */
+ if (state->arping_index &&
+ state->arping_index <= opts->arping_len &&
+ (reply_s == opts->arping[state->arping_index - 1] ||
+ (reply_s == 0 &&
+ reply_t == opts->arping[state->arping_index - 1])))
+ {
+ ina.s_addr = reply_s;
+ hwaddr = hwaddr_ntoa((unsigned char *)hw_s,
+ (size_t)ar.ar_hln);
+ syslog(LOG_INFO,
+ "%s: found %s on hardware address %s",
+ iface->name, inet_ntoa(ina), hwaddr);
+ if (select_profile(iface, hwaddr) == -1 &&
+ errno == ENOENT)
+ select_profile(iface, inet_ntoa(ina));
+ close_sockets(iface);
+ delete_timeout(NULL, iface);
+ start_interface(iface);
+ return;
+ }
+
/* Check for conflict */
if (state->offer &&
(reply_s == state->offer->yiaddr ||
struct if_state *state = iface->state;
struct in_addr addr;
struct timeval tv;
+ int arping = 0;
- if (state->offer) {
+ if (state->probes == 0 &&
+ state->arping_index < state->options->arping_len) {
+ addr.s_addr = state->options->arping[state->arping_index++];
+ arping = 1;
+ } else if (state->offer) {
if (state->offer->yiaddr)
addr.s_addr = state->offer->yiaddr;
else
add_event(iface->arp_fd, handle_arp_packet, iface);
}
if (state->probes == 0) {
- syslog(LOG_INFO, "%s: checking %s is available"
- " on attached networks",
- iface->name, inet_ntoa(addr));
+ if (arping)
+ syslog(LOG_INFO, "%s: searching for %s",
+ iface->name, inet_ntoa(addr));
+ else
+ syslog(LOG_INFO, "%s: checking for %s",
+ iface->name, inet_ntoa(addr));
}
if (++state->probes < PROBE_NUM) {
tv.tv_sec = PROBE_MIN;
} else {
tv.tv_sec = ANNOUNCE_WAIT;
tv.tv_usec = 0;
- add_timeout_tv(&tv, bind_interface, iface);
+ if (arping) {
+ state->probes = 0;
+ if (state->arping_index < state->options->arping_len)
+ add_timeout_tv(&tv, send_arp_probe, iface);
+ else
+ add_timeout_tv(&tv, start_interface, iface);
+ } else
+ add_timeout_tv(&tv, bind_interface, iface);
}
syslog(LOG_DEBUG,
"%s: sending ARP probe (%d of %d), next in %0.2f seconds",
if (send_arp(iface, ARPOP_REQUEST, 0, addr.s_addr) == -1)
syslog(LOG_ERR, "send_arp: %m");
}
+
+void
+start_arping(struct interface *iface)
+{
+ iface->state->probes = 0;
+ iface->state->arping_index = 0;
+ send_arp_probe(iface);
+}
#define RATE_LIMIT_INTERVAL 60
#define DEFEND_INTERVAL 10
+#include "dhcpcd.h"
+
void send_arp_announce(void *);
void send_arp_probe(void *);
+void start_arping(struct interface *);
#endif
e--;
}
*--p = '\0';
+ if (*iface->state->profile) {
+ e = strlen("profile=") + strlen(iface->state->profile) + 2;
+ env[elen] = xmalloc(e);
+ snprintf(env[elen++], e, "profile=%s", iface->state->profile);
+ }
if (iface->wireless) {
e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
if (iface->state->new != NULL ||
}
static void
-configure_interface(struct interface *iface, int argc, char **argv)
+configure_interface1(struct interface *iface)
{
struct if_state *ifs = iface->state;
- struct if_options *ifo;
+ struct if_options *ifo = ifs->options;
uint8_t *duid;
size_t len = 0, ifl;
- free_options(ifs->options);
- ifo = ifs->options = read_config(cffile, iface->name, iface->ssid);
- add_options(ifo, argc, argv);
if (iface->flags & IFF_POINTOPOINT && !(ifo->options & DHCPCD_INFORM))
ifo->options |= DHCPCD_STATIC;
if (iface->flags & IFF_NOARP ||
}
}
+int
+select_profile(struct interface *iface, const char *profile)
+{
+ struct if_options *ifo;
+
+ ifo = read_config(cffile, iface->name, iface->ssid, profile);
+ if (ifo == NULL) {
+ syslog(LOG_DEBUG, "%s: no profile %s", iface->name, profile);
+ return -1;
+ }
+ if (profile != NULL) {
+ strlcpy(iface->state->profile, profile,
+ sizeof(iface->state->profile));
+ syslog(LOG_INFO, "%s: selected profile %s",
+ iface->name, profile);
+ } else
+ *iface->state->profile = '\0';
+ free_options(iface->state->options);
+ iface->state->options = ifo;
+ configure_interface1(iface);
+ return 0;
+}
+
+static void
+configure_interface(struct interface *iface, int argc, char **argv)
+{
+ select_profile(iface, NULL);
+ add_options(iface->state->options, argc, argv);
+ configure_interface1(iface);
+}
+
+
static void
handle_carrier(const char *ifname)
{
struct interface *iface;
- char ssid[IF_SSIDSIZE];
for (iface = ifaces; iface; iface = iface->next)
if (strcmp(iface->name, ifname) == 0)
if (iface->carrier != LINK_UP) {
iface->carrier = LINK_UP;
syslog(LOG_INFO, "%s: carrier acquired", iface->name);
- if (iface->wireless) {
- /* We need to reconfigre for if ssid changed */
- memset(ssid, 0, sizeof(ssid));
- getifssid(iface->name, ssid);
- if (strcmp(iface->ssid, ssid) != 0) {
- strlcpy(iface->ssid, ssid, sizeof(iface->ssid));
- configure_interface(iface, margc, margv);
- }
- }
+ if (iface->wireless)
+ getifssid(iface->name, iface->ssid);
+ configure_interface(iface, margc, margv);
iface->state->interval = 0;
iface->state->reason = "CARRIER";
run_script(iface);
start_discover(iface);
return;
}
+ if (iface->state->arping_index < ifo->arping_len) {
+ start_arping(iface);
+ return;
+ }
if (ifo->options & DHCPCD_STATIC) {
start_static(iface);
return;
ifp->state->state = DHS_INFORM;
ifp->state->xid = arc4random();
ifp->state->lease.server.s_addr =
- dst ? dst->s_addr : INADDR_ANY;
+ dst ? dst->s_addr : INADDR_ANY;
ifp->addr = *addr;
ifp->net = *net;
open_sockets(ifp);
margv = argv;
margc = argc;
- ifo = read_config(cffile, NULL, NULL);
+ ifo = read_config(cffile, NULL, NULL, NULL);
opt = add_options(ifo, argc, argv);
if (opt != 1) {
if (opt == 0)
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 19, 2009
+.Dd March 31, 2009
.Dt DHCPCD.CONF 5 SMM
.Os
.Sh NAME
.Ar pattern
which is a space or comma separated list of patterns passed to
.Xr fnmatch 3 .
+.It Ic arping Ar address Op address
+.Nm dhcpcd
+will arping each address in order.
+If an address is found, we will select the replying hardware address as the
+profile, otherwise the ip address.
+Example:
+.Pp
+.D1 interface bge0
+.D1 arping 192.168.0.1
+.Pp
+.D1 profile 192.168.0.1
+.D1 static ip_address=192.168.0.10/24
.It Ic background
Background immediately.
This is useful for startup scripts which don't disable link messages for
carrier status.
-.It Ic blacklist Ar address Ns Op Ar /cidr
+.It Ic blacklist Ar address Ns Op /cidr
Ignores all packets from
-.Ar address Ns Op Ar /cidr .
+.Ar address Ns Op /cidr .
.It Ic clientid Ar string
Send the
.Ar clientid .
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 profile Ar name
+Subsequent options are only parsed for this profile
+.Ar name .
.It Ic quiet
Supress any dhcpcd output to the console, except for errors.
.It Ic reboot Ar seconds
#define HWADDR_LEN 20
#define IF_SSIDSIZE 33
+#define PROFILE_LEN 32
enum DHS {
DHS_INIT,
struct if_state {
enum DHS state;
+ char profile[PROFILE_LEN];
struct if_options *options;
struct dhcp_message *sent;
struct dhcp_message *offer;
int conflicts;
time_t defend;
struct in_addr fail;
+ size_t arping_index;
};
struct interface {
void send_decline(struct interface *);
void close_sockets(struct interface *);
void drop_config(struct interface *, const char *);
+int select_profile(struct interface *, const char *);
#endif
#include "net.h"
const struct option cf_options[] = {
+ {"arping", required_argument, NULL, 'a'},
{"background", no_argument, NULL, 'b'},
{"script", required_argument, NULL, 'c'},
{"debug", no_argument, NULL, 'd'},
struct rt *rt;
switch(opt) {
+ case 'a':
+ if (parse_addr(&addr, NULL, arg) != 0)
+ return -1;
+ ifo->arping = xrealloc(ifo->arping,
+ sizeof(in_addr_t) * (ifo->arping_len + 1));
+ ifo->arping[ifo->arping_len++] = addr.s_addr;
+ break;
case 'e': /* FALLTHROUGH */
case 'n': /* FALLTHROUGH */
case 'x': /* FALLTHROUGH */
}
struct if_options *
-read_config(const char *file, const char *ifname, const char *ssid)
+read_config(const char *file,
+ const char *ifname, const char *ssid, const char *profile)
{
struct if_options *ifo;
FILE *f;
char *line, *option, *p;
- int skip = 0;
+ int skip = 0, have_profile = 0;
/* Seed our default options */
ifo = xzalloc(sizeof(*ifo));
skip = 1;
continue;
}
+ /* Start of a profile block, skip if not ours */
+ if (strcmp(option, "profile") == 0) {
+ if (profile && line && strcmp(line, profile) == 0) {
+ skip = 0;
+ have_profile = 1;
+ } else
+ skip = 1;
+ continue;
+ }
if (skip)
continue;
- if (parse_config_line(ifo, option, line) != 1) {
+ if (parse_config_line(ifo, option, line) != 1)
break;
- }
}
fclose(f);
+ if (profile && !have_profile) {
+ free_options(ifo);
+ errno = ENOENT;
+ ifo = NULL;
+ }
+
/* Terminate the encapsulated options */
- if (ifo->vendor[0]) {
+ if (ifo && ifo->vendor[0]) {
ifo->vendor[0]++;
ifo->vendor[ifo->vendor[0]] = DHO_END;
}
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
-#define IF_OPTS "bc:def:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLN:O:Q:TVX:Z:"
+#define IF_OPTS "a:bc:def:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLN:O:Q:TVX:Z:"
#define DEFAULT_TIMEOUT 30
#define DEFAULT_REBOOT 10
size_t blacklist_len;
in_addr_t *blacklist;
+ size_t arping_len;
+ in_addr_t *arping;
};
-struct if_options *read_config(const char *, const char *, const char *);
+struct if_options *read_config(const char *,
+ const char *, const char *, const char *);
int add_options(struct if_options *, int, char **);
void free_options(struct if_options *);