interface reports a carrier.
.Nd an RFC 2131 compliant DHCP client
.Sh SYNOPSIS
.Nm
-.Op Fl bdgknpqwABDEGKLTV
+.Op Fl bdgknpqABDEGKLTV
.Op Fl c , -script Ar script
.Op Fl e , -env Ar value
.Op Fl f , -config Ar file
.D1 dhcpcd \-v 03,\e"192.168.0.2\e" eth0
Set un-encapulated vendor option to hello world.
.D1 dhcpcd \-v ,"hello world" eth0
-.It Fl w , -waitip
-Wait for an address to be assigned before forking to the background.
.It Fl x , -exit
This will signal an existing
.Nm
if (iface->flags & IFF_NOARP ||
ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
- if (ifo->options & DHCPCD_LINK && carrier_status(iface->name) == -1)
+ if (ifo->options & DHCPCD_LINK && carrier_status(iface) == -1)
ifo->options &= ~DHCPCD_LINK;
if (ifo->metric != -1)
handle_carrier(const char *ifname)
{
struct interface *iface;
+ int carrier;
if (!(options & DHCPCD_LINK))
return;
break;
if (!iface || !(iface->state->options->options & DHCPCD_LINK))
return;
- switch (carrier_status(iface->name)) {
- case -1:
- syslog(LOG_ERR, "carrier_status: %m");
- break;
- case 0:
+ carrier = carrier_status(iface);
+ if (carrier == -1)
+ syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
+ else if (carrier == 0 || !(iface->flags & IFF_RUNNING)) {
if (iface->carrier != LINK_DOWN) {
iface->carrier = LINK_DOWN;
syslog(LOG_INFO, "%s: carrier lost", iface->name);
delete_timeouts(iface, start_expire, NULL);
drop_config(iface, "NOCARRIER");
}
- break;
- default:
+ } else if (carrier == 1 && (iface->flags & IFF_RUNNING)) {
if (iface->carrier != LINK_UP) {
iface->carrier = LINK_UP;
syslog(LOG_INFO, "%s: carrier acquired", iface->name);
run_script(iface);
start_interface(iface);
}
- break;
}
}
run_script(iface);
if (ifs->options->options & DHCPCD_LINK) {
- switch (carrier_status(iface->name)) {
+ switch (carrier_status(iface)) {
case 0:
iface->carrier = LINK_DOWN;
ifs->reason = "NOCARRIER";
if (pid == 0 || kill(pid, sig) != 0) {
if (sig != SIGALRM)
syslog(LOG_ERR, ""PACKAGE" not running");
+ if (pid != 0 && errno != ESRCH) {
+ syslog(LOG_ERR, "kill: %m");
+ exit(EXIT_FAILURE);
+ }
unlink(pidfile);
if (sig != SIGALRM)
exit(EXIT_FAILURE);
ifc = argc - optind;
ifv = argv + optind;
- if (options & DHCPCD_BACKGROUND ||
- (ifc == 0 &&
- options & DHCPCD_LINK &&
- options & DHCPCD_DAEMONISE &&
- !(options & DHCPCD_WAITIP)))
- {
- daemonise();
- } else if (options & DHCPCD_DAEMONISE && ifo->timeout > 0) {
- if (options & DHCPCD_IPV4LL)
- options |= DHCPCD_TIMEOUT_IPV4LL;
- add_timeout_sec(ifo->timeout, handle_exit_timeout, NULL);
- }
- free_options(ifo);
ifaces = discover_interfaces(ifc, ifv);
for (i = 0; i < ifc; i++) {
else
exit(EXIT_FAILURE);
if (!(options & DHCPCD_LINK)) {
- syslog(LOG_ERR, "aborting as we're not backgrounding"
- " with link detection");
+ syslog(LOG_ERR,
+ "aborting as link detection is disabled");
exit(EXIT_FAILURE);
}
}
- for (iface = ifaces; iface; iface = iface->next)
+ if (options & DHCPCD_BACKGROUND)
+ daemonise();
+
+ opt = 0;
+ for (iface = ifaces; iface; iface = iface->next) {
init_state(iface, argc, argv);
+ if (iface->carrier != LINK_DOWN)
+ opt = 1;
+ }
+ if (options & DHCPCD_LINK && opt == 0) {
+ syslog(LOG_WARNING, "no interfaces have a carrier");
+ daemonise();
+ } else if (options & DHCPCD_DAEMONISE && ifo->timeout > 0) {
+ if (options & DHCPCD_IPV4LL)
+ options |= DHCPCD_TIMEOUT_IPV4LL;
+ add_timeout_sec(ifo->timeout, handle_exit_timeout, NULL);
+ }
+ free_options(ifo);
+
sort_interfaces();
for (iface = ifaces; iface; iface = iface->next)
add_timeout_sec(0, start_interface, iface);
.It Ic vendorclassid Ar string
Change the default vendorclassid sent from dhcpcd-version.
If not set then none is sent.
-.It Ic waitip
-Wait for an address to be assigned before forking to the background.
.El
.Sh SEE ALSO
.Xr dhcpcd-run-hooks 8 ,
{"timeout", required_argument, NULL, 't'},
{"userclass", required_argument, NULL, 'u'},
{"vendor", required_argument, NULL, 'v'},
- {"waitip", no_argument, NULL, 'w'},
{"exit", no_argument, NULL, 'x'},
{"allowinterfaces", required_argument, NULL, 'z'},
{"reboot", required_argument, NULL, 'y'},
ifo->vendor[0] += s + 2;
}
break;
- case 'w':
- ifo->options |= DHCPCD_WAITIP;
- break;
case 'y':
ifo->reboot = atoint(arg);
if (ifo->reboot < 0) {
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
-#define IF_OPTS "bc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:wxy:z:ABC:DEF:GI:KLN:O:Q:TVW:X:Z:"
+#define IF_OPTS "bc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLN:O:Q:TVW:X:Z:"
#define DEFAULT_TIMEOUT 30
#define DEFAULT_REBOOT 10
#define DHCPCD_QUIET (1 << 21)
#define DHCPCD_BACKGROUND (1 << 22)
#define DHCPCD_VENDORRAW (1 << 23)
-#define DHCPCD_WAITIP (1 << 24)
-#define DHCPCD_TIMEOUT_IPV4LL (1 << 25)
+#define DHCPCD_TIMEOUT_IPV4LL (1 << 24)
extern const struct option cf_options[];
free(iface);
}
+int
+carrier_status(struct interface *iface)
+{
+ int s, ret;
+ struct ifreq ifr;
+#ifdef SIOCGIFMEDIA
+ struct ifmediareq ifmr;
+#endif
+#ifdef __linux__
+ char *p;
+#endif
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ return -1;
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
+#ifdef __linux__
+ /* We can only test the real interface up */
+ if ((p = strchr(ifr.ifr_name, ':')))
+ *p = '\0';
+#endif
+
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
+ close(s);
+ return -1;
+ }
+ iface->flags = ifr.ifr_flags;
+
+ ret = -1;
+#ifdef SIOCGIFMEDIA
+ memset(&ifmr, 0, sizeof(ifmr));
+ strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
+ if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 &&
+ ifmr.ifm_status & IFM_AVALID)
+ ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
+#endif
+ close(s);
+ if (ret == -1)
+ ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0;
+ return ret;
+}
+
+int
+up_interface(struct interface *iface)
+{
+ int s;
+ struct ifreq ifr;
+ int retval = -1;
+#ifdef __linux__
+ char *p;
+#endif
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ return -1;
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
+#ifdef __linux__
+ /* We can only bring the real interface up */
+ if ((p = strchr(ifr.ifr_name, ':')))
+ *p = '\0';
+#endif
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
+ if ((ifr.ifr_flags & IFF_UP))
+ retval = 0;
+ else {
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
+ retval = 0;
+ }
+ iface->flags = ifr.ifr_flags;
+ }
+ close(s);
+ return retval;
+}
+
struct interface *
discover_interfaces(int argc, char * const *argv)
{
if ((ifp = init_interface(p)) == NULL)
continue;
- /* Bring the interface up */
- if (!(ifp->flags & IFF_UP) && up_interface(p) != 0)
- /* Some drivers return ENODEV here when they are disabled by a switch.
- * We just blunder on as the carrier will be down anyway.
- * When the switch is enabled, it should bring the interface up.
- * Then we'll spot the carrier and start working. */
- syslog(LOG_ERR, "%s: up_interface: %m", p);
+ /* Bring the interface up if not already */
+ if (!(ifp->flags & IFF_UP) &&
+#ifdef SIOCGIFMEDIA
+ carrier_status(ifp) != -1 &&
+#endif
+ up_interface(ifp) != 0)
+ syslog(LOG_ERR, "%s: up_interface: %m", ifp->name);
/* Don't allow loopback unless explicit */
if (ifp->flags & IFF_LOOPBACK) {
freeifaddrs(ifaddrs);
return retval;
}
-
-int
-up_interface(const char *ifname)
-{
- int s;
- struct ifreq ifr;
- int retval = -1;
-#ifdef __linux__
- char *p;
-#endif
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-#ifdef __linux__
- /* We can only bring the real interface up */
- if ((p = strchr(ifr.ifr_name, ':')))
- *p = '\0';
-#endif
- if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
- if ((ifr.ifr_flags & IFF_UP))
- retval = 0;
- else {
- ifr.ifr_flags |= IFF_UP;
- if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
- retval = 0;
- }
- }
- close(s);
- return retval;
-}
-
-int
-carrier_status(const char *ifname)
-{
- int s;
- struct ifreq ifr;
- int retval = -1;
-#ifdef SIOCGIFMEDIA
- struct ifmediareq ifmr;
-#endif
-#ifdef __linux__
- char *p;
-#endif
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- return -1;
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-#ifdef __linux__
- /* We can only test the real interface up */
- if ((p = strchr(ifr.ifr_name, ':')))
- *p = '\0';
-#endif
- if ((retval = ioctl(s, SIOCGIFFLAGS, &ifr)) == 0) {
- if (ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING)
- retval = 1;
- else
- retval = 0;
- }
-
-#ifdef SIOCGIFMEDIA
- 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)
- retval = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
- }
-#endif
- close(s);
- return retval;
-}
-
int
do_mtu(const char *ifname, short int mtu)
int inet_ntocidr(struct in_addr);
int inet_cidrtoaddr(int, struct in_addr *);
-int up_interface(const char *);
+int up_interface(struct interface *);
int do_address(const char *,
struct in_addr *, struct in_addr *, struct in_addr *, int);
int if_address(const struct interface *,
int init_socket(void);
int open_link_socket(void);
int manage_link(int);
-int carrier_status(const char *);
+int carrier_status(struct interface *);
#endif