From: Roy Marples Date: Wed, 23 Nov 2011 09:03:24 +0000 (+0000) Subject: Respect each kernel message on carrier change instead of checking carrier X-Git-Tag: v5.5.0~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=126abb55cf19c543fe414e23bb26c71b43513d8f;p=thirdparty%2Fdhcpcd.git Respect each kernel message on carrier change instead of checking carrier after receiving the message as it's possible for the kernel to react faster than dhcpcd. --- diff --git a/dhcpcd.c b/dhcpcd.c index 97ad6c6e..80aa04ad 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -871,8 +871,8 @@ configure_interface(struct interface *iface, int argc, char **argv) configure_interface1(iface); } -static void -handle_carrier(const char *ifname) +void +handle_carrier(int action, int flags, const char *ifname) { struct interface *iface; int carrier; @@ -882,9 +882,19 @@ handle_carrier(const char *ifname) for (iface = ifaces; iface; iface = iface->next) if (strcmp(iface->name, ifname) == 0) break; - if (!iface || !(iface->state->options->options & DHCPCD_LINK)) + if (!iface) { + if (options & DHCPCD_LINK) + handle_interface(1, ifname); + return; + } + if (!(iface->state->options->options & DHCPCD_LINK)) return; - carrier = carrier_status(iface); + if (action == 0) + carrier = carrier_status(iface); + else { + carrier = action == 1 ? 1 : 0; + iface->flags = flags; + } if (carrier == -1) syslog(LOG_ERR, "%s: carrier_status: %m", ifname); else if (carrier == 0 || !(iface->flags & IFF_RUNNING)) { @@ -1127,7 +1137,7 @@ start_interface(void *arg) uint32_t l; int nolease; - handle_carrier(iface->name); + handle_carrier(0, 0, iface->name); if (iface->carrier == LINK_DOWN) { syslog(LOG_INFO, "%s: waiting for carrier", iface->name); return; @@ -1255,9 +1265,6 @@ handle_interface(int action, const char *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. */ @@ -2030,7 +2037,7 @@ main(int argc, char **argv) ts.tv_nsec = 0; nanosleep(&ts, NULL); for (iface = ifaces; iface; iface = iface->next) { - handle_carrier(iface->name); + handle_carrier(0, 0, iface->name); if (iface->carrier != LINK_DOWN) { opt = 1; break; diff --git a/dhcpcd.h b/dhcpcd.h index ec324746..1f6ae059 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2010 Roy Marples + * Copyright (c) 2006-2011 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -122,6 +122,7 @@ extern struct interface *ifaces; struct interface *find_interface(const char *); int handle_args(struct fd_list *, int, char **); +void handle_carrier(int, int, const char *); void handle_interface(int, const char *); void handle_hwaddr(const char *, unsigned char *, size_t); void handle_ifa(int, const char *, diff --git a/if-bsd.c b/if-bsd.c index c63d969d..56585bfc 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -362,8 +362,21 @@ manage_link(int fd) case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)p; memset(ifname, 0, sizeof(ifname)); - if (if_indextoname(ifm->ifm_index, ifname)) - handle_interface(0, ifname); + if (!(if_indextoname(ifm->ifm_index, ifname))) + break; + switch (ifm->ifm_data.ifi_link_state) { + case LINK_STATE_DOWN: + len = 1; + break; + case LINK_STATE_UP: + len = -1; + break; + default: + len = ifm->ifm_flags & IFF_RUNNING + ? 1 : -1; + break; + } + handle_carrier(len, ifm->ifm_flags, ifname); break; case RTM_DELETE: if (!(rtm->rtm_addrs & RTA_DST) || diff --git a/if-linux.c b/if-linux.c index 4a06259d..4b7ac682 100644 --- a/if-linux.c +++ b/if-linux.c @@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright (c) 2006-2010 Roy Marples + * Copyright (c) 2006-2011 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -371,11 +371,14 @@ link_netlink(struct nlmsghdr *nlm) } rta = RTA_NEXT(rta, len); } - if (nlm->nlmsg_type == RTM_NEWLINK) - len = ifi->ifi_change == ~0U ? 1 : 0; - else - len = -1; - handle_interface(len, ifn); + + if (nlm->nlmsg_type == RTM_DELLINK) { + handle_interface(-1, ifn); + return 1; + } + + handle_carrier(ifi->ifi_flags & IFF_RUNNING ? 1 : -1, + ifi->ifi_flags, ifn); return 1; }