]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Enable detection of addition and removal of interfaces on Linux.
authorRoy Marples <roy@marples.name>
Thu, 4 Sep 2008 14:08:14 +0000 (14:08 +0000)
committerRoy Marples <roy@marples.name>
Thu, 4 Sep 2008 14:08:14 +0000 (14:08 +0000)
dhcpcd.c
if-bsd.c
if-linux.c
net.h

index 306f4d02321eb920fa188a0623e6dc62ecb54483..fdfb1163b5ea31e195d36c815508a5ca4ca1d2c2 100644 (file)
--- 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;
 }
index 58aa10ffc1ca05ad5dc62c9d0427641f3126f4c3..53bf2d6699b8cc3265a975521166f68254a0900b 100644 (file)
--- 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;
                        }
                }
index 695f033efc993aec97ba9db9b89697947f5a9412..bece58cc073e6c6d00071e02d7332fcc16bea383 100644 (file)
 
 #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 08e29efc51f36653a42d58dcc0e5b7edaf20bac7..0629302a4b482b5ab30ef85f3d0c76dde1ba0ec7 100644 (file)
--- 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