From: Roy Marples Date: Thu, 4 Sep 2008 11:30:11 +0000 (+0000) Subject: When OS reports new and removed interfaces, dhcpcd sees this and either starts or... X-Git-Tag: v5.0.0~302 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=96d0673a2cd58d50f0e4c8e0c60b332a7fff92a8;p=thirdparty%2Fdhcpcd.git When OS reports new and removed interfaces, dhcpcd sees this and either starts or stops watching them. BSD only, Linux to follow. --- diff --git a/dhcpcd.c b/dhcpcd.c index 1afa77a2..306f4d02 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -66,6 +66,8 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; int master = 0; int pidfd = -1; +static char **ifv = NULL; +static int ifc = 0; static int linkfd = -1; static char cffile[PATH_MAX]; static char pidfile[PATH_MAX] = { '\0' }; @@ -195,6 +197,7 @@ stop_interface(struct interface *iface) { struct interface *ifp, *ifl = NULL; + logger(LOG_ERR, "%s: removing interface", iface->name); drop_config(iface, "STOP"); close_sockets(iface); delete_timeout(NULL, iface); @@ -272,8 +275,6 @@ send_message(struct interface *iface, int type, } free(dhcp); if (r == -1) { - logger(LOG_ERR, "%s: removing interface from dhcpcd", - iface->name); stop_interface(iface); } else { if (callback) @@ -592,44 +593,29 @@ open_sockets(struct interface *iface) } static void -handle_link(_unused void *arg) +handle_carrier(struct interface *iface) { - struct interface *iface; - int retval; - - retval = link_changed(linkfd, ifaces); - if (retval == -1) { - logger(LOG_ERR, "link_changed: %s", strerror(errno)); + if (!(iface->state->options->options & DHCPCD_LINK)) return; - } - if (retval == 0) - return; - for (iface = ifaces; iface; iface = iface->next) { - if (iface->state->options->options & DHCPCD_LINK) { - switch (carrier_status(iface->name)) { - case -1: - logger(LOG_ERR, "carrier_status: %s", - strerror(errno)); - break; - case 0: - if (iface->state->carrier != LINK_DOWN) { - iface->state->carrier = LINK_DOWN; - logger(LOG_INFO, "%s: carrier lost", - iface->name); - close_sockets(iface); - delete_timeouts(iface, start_expire, NULL); - } - break; - default: - if (iface->state->carrier != LINK_UP) { - iface->state->carrier = LINK_UP; - logger(LOG_INFO, "%s: carrier acquired", - iface->name); - start_interface(iface); - } - break; - } + switch (carrier_status(iface->name)) { + case -1: + logger(LOG_ERR, "carrier_status: %s", strerror(errno)); + break; + case 0: + if (iface->state->carrier != LINK_DOWN) { + iface->state->carrier = LINK_DOWN; + logger(LOG_INFO, "%s: carrier lost", iface->name); + close_sockets(iface); + delete_timeouts(iface, start_expire, NULL); + } + break; + default: + if (iface->state->carrier != LINK_UP) { + iface->state->carrier = LINK_UP; + logger(LOG_INFO, "%s: carrier acquired", iface->name); + start_interface(iface); } + break; } } @@ -785,6 +771,43 @@ init_state(struct interface *iface, int argc, char **argv) start_interface(iface); } +static void +handle_new_interface(const char *name) +{ + struct interface *ifs, *ifp; + const char * const argv[] = { "dhcpcd", name }; + 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) + break; + if (i >= ifc) + return; + } + + if ((ifs = discover_interfaces(2, UNCONST(argv)))) { + for (ifp = ifs; ifp; ifp = ifp->next) + init_state(ifp, 2, UNCONST(argv)); + if (ifaces) { + ifp = ifaces; + while (ifp->next) + ifp = ifp->next; + ifp->next = ifs; + } else + ifaces = ifs; + } +} + +static void +handle_link(_unused void *arg) +{ + if (manage_link(linkfd, ifaces, handle_carrier, + handle_new_interface, stop_interface) == -1) + logger(LOG_ERR, "manage_link: %s", strerror(errno)); +} + static void handle_signal(_unused void *arg) { @@ -1091,13 +1114,15 @@ main(int argc, char **argv) } free_options(ifo); - argc -= optind; - argv += optind; - ifaces = discover_interfaces(argc, argv); - argc += optind; - argv -= optind; + ifc = argc - optind; + ifv = argv + optind; + ifaces = discover_interfaces(ifc, ifv); for (iface = ifaces; iface; iface = iface->next) init_state(iface, argc, argv); + if (!ifaces && ifc == 1) { + logger(LOG_ERR, "interface `%s' does not exist", ifv[0]); + exit(EXIT_FAILURE); + } start_eloop(); /* NOTREACHED */ } diff --git a/dhcpcd.h b/dhcpcd.h index ccb7ba2f..608a41d0 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -105,6 +105,7 @@ struct interface }; extern int pidfd; + int handle_args(int, char **); void handle_exit_timeout(void *); void send_request(void *); diff --git a/if-bsd.c b/if-bsd.c index bad76832..58aa10ff 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -187,23 +187,29 @@ open_link_socket(void) int fd; fd = socket(PF_ROUTE, SOCK_RAW, 0); - if (fd != -1) + if (fd != -1) { set_cloexec(fd); + set_nonblock(fd); + } return fd; } #define BUFFER_LEN 2048 int -link_changed(int fd, const struct interface *ifaces) +manage_link(int fd, struct interface *ifaces, + void (*if_carrier)(struct interface *), + void (*if_add)(const char *), + void (*if_remove)(struct interface *)) { char buffer[2048], *p; ssize_t bytes; struct rt_msghdr *rtm; + struct if_announcemsghdr *ifa; struct if_msghdr *ifm; - const struct interface *iface; + struct interface *iface; for (;;) { - bytes = recv(fd, buffer, BUFFER_LEN, MSG_DONTWAIT); + bytes = read(fd, buffer, BUFFER_LEN); if (bytes == -1) { if (errno == EAGAIN) return 0; @@ -216,12 +222,31 @@ link_changed(int fd, const struct interface *ifaces) p += ((struct rt_msghdr *)p)->rtm_msglen) { rtm = (struct rt_msghdr *)p; - if (rtm->rtm_type != RTM_IFINFO) - continue; - ifm = (struct if_msghdr *)p; - for (iface = ifaces; iface; iface = iface->next) - if (ifm->ifm_index == if_nametoindex(iface->name)) - return 1; + switch(rtm->rtm_type) { + case RTM_IFANNOUNCE: + ifa = (struct if_announcemsghdr *)p; + switch(ifa->ifan_what) { + case IFAN_ARRIVAL: + 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; + } + 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; + } + break; + } } } } diff --git a/net.h b/net.h index bf8e4ba5..08e29efc 100644 --- a/net.h +++ b/net.h @@ -149,6 +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 link_changed(int, const struct interface *); +int manage_link(int, struct interface *, + void (*)(struct interface *), + void (*)(const char *), + void (*)(struct interface *)); int carrier_status(const char *); #endif