From: Roy Marples Date: Thu, 4 Sep 2008 14:08:14 +0000 (+0000) Subject: Enable detection of addition and removal of interfaces on Linux. X-Git-Tag: v5.0.0~300 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=064dd58ee2542ff28fdc0e6615c434529c6c92a0;p=thirdparty%2Fdhcpcd.git Enable detection of addition and removal of interfaces on Linux. --- diff --git a/dhcpcd.c b/dhcpcd.c index 306f4d02..fdfb1163 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -197,7 +197,7 @@ stop_interface(struct interface *iface) { struct interface *ifp, *ifl = NULL; - logger(LOG_ERR, "%s: removing interface", iface->name); + logger(LOG_INFO, "%s: removing interface", iface->name); drop_config(iface, "STOP"); close_sockets(iface); delete_timeout(NULL, iface); @@ -593,9 +593,14 @@ open_sockets(struct interface *iface) } static void -handle_carrier(struct interface *iface) +handle_carrier(const char *ifname) { - if (!(iface->state->options->options & DHCPCD_LINK)) + struct interface *iface; + + for (iface = ifaces; iface; iface = iface->next) + if (strcmp(iface->name, ifname) == 0) + break; + if (!iface || !(iface->state->options->options & DHCPCD_LINK)) return; switch (carrier_status(iface->name)) { case -1: @@ -772,39 +777,59 @@ init_state(struct interface *iface, int argc, char **argv) } static void -handle_new_interface(const char *name) +handle_new_interface(const char *ifname) { - struct interface *ifs, *ifp; - const char * const argv[] = { "dhcpcd", name }; + struct interface *ifs, *ifp, *ifn, *ifl = NULL; + const char * const argv[] = { "dhcpcd", ifname }; int i; /* If running off an interface list, check it's in it. */ if (ifc) { for (i = 0; i < ifc; i++) - if (strcmp(ifv[i], name) == 0) + if (strcmp(ifv[i], ifname) == 0) break; if (i >= ifc) return; } if ((ifs = discover_interfaces(2, UNCONST(argv)))) { - for (ifp = ifs; ifp; ifp = ifp->next) + for (ifp = ifs; ifp; ifp = ifp->next) { + /* Check if we already have the interface */ + for (ifn = ifaces; ifn; ifn = ifn->next) { + if (strcmp(ifn->name, ifp->name) == 0) + break; + ifl = ifn; + } + if (ifn) + continue; init_state(ifp, 2, UNCONST(argv)); - if (ifaces) { - ifp = ifaces; - while (ifp->next) - ifp = ifp->next; - ifp->next = ifs; - } else - ifaces = ifs; + if (ifl) + ifl->next = ifp; + else + ifaces = ifp; + } } } +static void +handle_remove_interface(const char *ifname) +{ + struct interface *iface; + + for (iface = ifaces; iface; iface = iface->next) + if (strcmp(iface->name, ifname) == 0) + break; + if (iface && iface->state->options->options & DHCPCD_LINK) + stop_interface(iface); +} + static void handle_link(_unused void *arg) { - if (manage_link(linkfd, ifaces, handle_carrier, - handle_new_interface, stop_interface) == -1) + if (manage_link(linkfd, + handle_carrier, + handle_new_interface, + handle_remove_interface) == -1) logger(LOG_ERR, "manage_link: %s", strerror(errno)); } @@ -855,7 +880,7 @@ handle_signal(_unused void *arg) int handle_args(int argc, char **argv) { - struct interface *ifs, *ifp, *ifl = NULL; + struct interface *ifs, *ifp, *ifl = NULL, *ifn; int do_exit = 0, do_release = 0, do_reboot = 0, opt, oi = 0; optind = 0; @@ -892,6 +917,7 @@ handle_args(int argc, char **argv) if (do_release) send_release(ifp); if (do_exit || do_release) { + logger(LOG_INFO, "%s: removing interface", ifp->name); drop_config(ifp, do_release ? "RELEASE" : "STOP"); close_sockets(ifp); delete_timeout(NULL, ifp); @@ -911,15 +937,20 @@ handle_args(int argc, char **argv) if ((ifs = discover_interfaces(argc, argv))) { argc += optind; argv -= optind; - for (ifp = ifs; ifp; ifp = ifp->next) - init_state(ifp, argc, argv); - if (ifaces) { - ifp = ifaces; - while (ifp->next) - ifp = ifp->next; - ifp->next = ifs; - } else - ifaces = ifs; + for (ifp = ifs; ifp; ifp = ifp->next) { + for (ifn = ifaces; ifn; ifn = ifn->next) { + if (strcmp(ifn->name, ifp->name) == 0) + break; + ifl = ifn; + } + if (!ifn) { + init_state(ifp, argc, argv); + if (ifl) + ifl->next = ifp; + else + ifaces = ifp; + } + } } return 0; } diff --git a/if-bsd.c b/if-bsd.c index 58aa10ff..53bf2d66 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -196,12 +196,13 @@ open_link_socket(void) #define BUFFER_LEN 2048 int -manage_link(int fd, struct interface *ifaces, - void (*if_carrier)(struct interface *), +manage_link(int fd, + void (*if_carrier)(const char *), void (*if_add)(const char *), - void (*if_remove)(struct interface *)) + void (*if_remove)(const char *)) { char buffer[2048], *p; + char ifname[IFNAMSIZ + 1]; ssize_t bytes; struct rt_msghdr *rtm; struct if_announcemsghdr *ifa; @@ -230,21 +231,14 @@ manage_link(int fd, struct interface *ifaces, if_add(ifa->ifan_name); break; case IFAN_DEPARTURE: - for (iface = ifaces; iface; iface = iface->next) - if (strcmp(ifa->ifan_name, iface->name) == 0) { - if_remove(iface); - break; - } + if_remove(ifa->ifan_name); break; - } break; case RTM_IFINFO: ifm = (struct if_msghdr *)p; - for (iface = ifaces; iface; iface = iface->next) - if (ifm->ifm_index == if_nametoindex(iface->name)) { - if_carrier(iface); - break; - } + memset(ifname, 0, sizeof(ifname)); + if (if_indextoname(ifm->ifm_index, ifname)) + if_carrier(ifname); break; } } diff --git a/if-linux.c b/if-linux.c index 695f033e..bece58cc 100644 --- a/if-linux.c +++ b/if-linux.c @@ -59,6 +59,10 @@ #define BUFFERLEN 256 +static void (*nl_carrier)(const char *) = NULL; +static void (*nl_add)(const char *) = NULL; +static void (*nl_remove)(const char *) = NULL; + int open_link_socket(void) { @@ -78,8 +82,7 @@ open_link_socket(void) static int get_netlink(int fd, int flags, - int (*callback)(struct nlmsghdr *, const struct interface *), - const struct interface *iface) + int (*callback)(struct nlmsghdr *)) { char *buffer = NULL; ssize_t bytes; @@ -102,7 +105,7 @@ get_netlink(int fd, int flags, NLMSG_OK(nlm, (size_t)bytes); nlm = NLMSG_NEXT(nlm, bytes)) { - r = callback(nlm, iface); + r = callback(nlm); if (r != 0) goto eexit; } @@ -114,7 +117,7 @@ eexit: } static int -err_netlink(struct nlmsghdr *nlm, _unused const struct interface *iface) +err_netlink(struct nlmsghdr *nlm) { struct nlmsgerr *err; int l; @@ -134,13 +137,12 @@ err_netlink(struct nlmsghdr *nlm, _unused const struct interface *iface) } static int -link_netlink(struct nlmsghdr *nlm, const struct interface *ifaces) +link_netlink(struct nlmsghdr *nlm) { int len; struct rtattr *rta; struct ifinfomsg *ifi; char ifn[IF_NAMESIZE + 1]; - const struct interface *iface; if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK) return 0; @@ -151,7 +153,7 @@ link_netlink(struct nlmsghdr *nlm, const struct interface *ifaces) } ifi = NLMSG_DATA(nlm); if (ifi->ifi_flags & IFF_LOOPBACK) - return 0; + return 1; rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi))); len = NLMSG_PAYLOAD(nlm, sizeof(*ifi)); *ifn = '\0'; @@ -160,8 +162,8 @@ link_netlink(struct nlmsghdr *nlm, const struct interface *ifaces) case IFLA_WIRELESS: /* Ignore wireless messages */ if (nlm->nlmsg_type == RTM_NEWLINK && - ifi->ifi_change == 0) - return 0; + ifi->ifi_change == 0) + return 1; break; case IFLA_IFNAME: strlcpy(ifn, RTA_DATA(rta), sizeof(ifn)); @@ -169,19 +171,31 @@ link_netlink(struct nlmsghdr *nlm, const struct interface *ifaces) } rta = RTA_NEXT(rta, len); } - - for (iface = ifaces; iface; iface = iface->next) - if (strcmp(iface->name, ifn) == 0) - return 1; - return 0; + if (nlm->nlmsg_type == RTM_NEWLINK) { + if (ifi->ifi_change == ~0U) { + if (nl_add) + nl_add(ifn); + } else { + if (nl_carrier) + nl_carrier(ifn); + } + } else { + if (nl_remove) + nl_remove(ifn); + } + return 1; } -manage_link(int fd, struct interface *ifaces, - void (*if_carrier)(struct interface *), +int +manage_link(int fd, + void (*if_carrier)(const char *), void (*if_add)(const char *), - void (*if_remove)(struct interface *)) + void (*if_remove)(const char *)) { - return get_netlink(fd, MSG_DONTWAIT, &link_netlink, ifaces); + nl_carrier = if_carrier; + nl_add = if_add; + nl_remove = if_remove; + return get_netlink(fd, MSG_DONTWAIT, &link_netlink); } static int @@ -214,7 +228,7 @@ send_netlink(struct nlmsghdr *hdr) hdr->nlmsg_seq = ++seq; if (sendmsg(fd, &msg, 0) != -1) - r = get_netlink(fd, 0, &err_netlink, NULL); + r = get_netlink(fd, 0, &err_netlink); else r = -1; close(fd); diff --git a/net.h b/net.h index 08e29efc..0629302a 100644 --- a/net.h +++ b/net.h @@ -149,9 +149,9 @@ ssize_t send_raw_packet(const struct interface *, int, ssize_t get_raw_packet(struct interface *, int, void *, ssize_t); int open_link_socket(void); -int manage_link(int, struct interface *, - void (*)(struct interface *), +int manage_link(int, void (*)(const char *), - void (*)(struct interface *)); + void (*)(const char *), + void (*)(const char *)); int carrier_status(const char *); #endif