ipcalc: more correct checking for proper number of arguments
[oweals/busybox.git] / networking / ifplugd.c
index 3567dea03a5c89a7317a0f3abe34a79c32a85c3a..41b04c4ed83cf290d0959d840e1eb59a587d5602 100644 (file)
@@ -1,6 +1,6 @@
 /* vi: set sw=4 ts=4: */
 /*
- * ifplugd for busybox
+ * ifplugd for busybox, based on ifplugd 0.28 (written by Lennart Poettering).
  *
  * Copyright (C) 2009 Maksym Kryzhanovskyy <xmaks@email.cz>
  *
 #include <linux/wireless.h>
 
 /*
-TODO: describe compat status here.
+From initial port to busybox, removed most of the redundancy by
+converting implementation of a polymorphic interface to the strict
+functional style. The main role is run a script when link state
+changed, other activities like audio signal or detailed reports
+are on the script itself.
 
 One questionable point of the design is netlink usage:
 
@@ -214,7 +218,7 @@ static int network_ioctl(int request, void* data, const char *errmsg)
 {
        int r = ioctl(ioctl_fd, request, data);
        if (r < 0 && errmsg)
-               bb_perror_msg(errmsg);
+               bb_perror_msg("%s failed", errmsg);
        return r;
 }
 
@@ -239,7 +243,7 @@ static void up_iface(void)
                return;
 
        set_ifreq_to_ifname(&ifrequest);
-       if (network_ioctl(SIOCGIFFLAGS, &ifrequest, "can't get interface flags") < 0) {
+       if (network_ioctl(SIOCGIFFLAGS, &ifrequest, "getting interface flags") < 0) {
                G.iface_exists = 0;
                return;
        }
@@ -248,7 +252,7 @@ static void up_iface(void)
                ifrequest.ifr_flags |= IFF_UP;
                /* Let user know we mess up with interface */
                bb_error_msg("upping interface");
-               if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "can't set interface flags") < 0)
+               if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0)
                        xfunc_die();
        }
 
@@ -307,13 +311,13 @@ static smallint detect_link_mii(void)
 
        set_ifreq_to_ifname(&ifreq);
 
-       if (network_ioctl(SIOCGMIIPHY, &ifreq, "SIOCGMIIPHY failed") < 0) {
+       if (network_ioctl(SIOCGMIIPHY, &ifreq, "SIOCGMIIPHY") < 0) {
                return IFSTATUS_ERR;
        }
 
        mii->reg_num = 1;
 
-       if (network_ioctl(SIOCGMIIREG, &ifreq, "SIOCGMIIREG failed") < 0) {
+       if (network_ioctl(SIOCGMIIREG, &ifreq, "SIOCGMIIREG") < 0) {
                return IFSTATUS_ERR;
        }
 
@@ -327,13 +331,13 @@ static smallint detect_link_priv(void)
 
        set_ifreq_to_ifname(&ifreq);
 
-       if (network_ioctl(SIOCDEVPRIVATE, &ifreq, "SIOCDEVPRIVATE failed") < 0) {
+       if (network_ioctl(SIOCDEVPRIVATE, &ifreq, "SIOCDEVPRIVATE") < 0) {
                return IFSTATUS_ERR;
        }
 
        mii->reg_num = 1;
 
-       if (network_ioctl(SIOCDEVPRIVATE+1, &ifreq, "SIOCDEVPRIVATE+1 failed") < 0) {
+       if (network_ioctl(SIOCDEVPRIVATE+1, &ifreq, "SIOCDEVPRIVATE+1") < 0) {
                return IFSTATUS_ERR;
        }
 
@@ -350,7 +354,7 @@ static smallint detect_link_ethtool(void)
        edata.cmd = ETHTOOL_GLINK;
        ifreq.ifr_data = (void*) &edata;
 
-       if (network_ioctl(SIOCETHTOOL, &ifreq, "ETHTOOL_GLINK failed") < 0) {
+       if (network_ioctl(SIOCETHTOOL, &ifreq, "ETHTOOL_GLINK") < 0) {
                return IFSTATUS_ERR;
        }
 
@@ -363,7 +367,7 @@ static smallint detect_link_iff(void)
 
        set_ifreq_to_ifname(&ifreq);
 
-       if (network_ioctl(SIOCGIFFLAGS, &ifreq, "SIOCGIFFLAGS failed") < 0) {
+       if (network_ioctl(SIOCGIFFLAGS, &ifreq, "SIOCGIFFLAGS") < 0) {
                return IFSTATUS_ERR;
        }
 
@@ -381,20 +385,21 @@ static smallint detect_link_iff(void)
 
 static smallint detect_link_wlan(void)
 {
+       int i;
        struct iwreq iwrequest;
        uint8_t mac[ETH_ALEN];
 
-       memset(&iwrequest, 0, sizeof(struct iwreq));
+       memset(&iwrequest, 0, sizeof(iwrequest));
        strncpy_IFNAMSIZ(iwrequest.ifr_ifrn.ifrn_name, G.iface);
 
-       if (network_ioctl(SIOCGIWAP, &iwrequest, "SIOCGIWAP failed") < 0) {
+       if (network_ioctl(SIOCGIWAP, &iwrequest, "SIOCGIWAP") < 0) {
                return IFSTATUS_ERR;
        }
 
-       memcpy(mac, &(iwrequest.u.ap_addr.sa_data), ETH_ALEN);
+       memcpy(mac, &iwrequest.u.ap_addr.sa_data, ETH_ALEN);
 
        if (mac[0] == 0xFF || mac[0] == 0x44 || mac[0] == 0x00) {
-               for (int i = 1; i < ETH_ALEN; ++i) {
+               for (i = 1; i < ETH_ALEN; ++i) {
                        if (mac[i] != mac[0])
                                return IFSTATUS_UP;
                }
@@ -406,7 +411,17 @@ static smallint detect_link_wlan(void)
 
 static smallint detect_link_auto(void)
 {
-       const char *method;
+       static const struct {
+               const char *name;
+               smallint (*func)(void);
+       } method[] = {
+               { "SIOCETHTOOL"       , &detect_link_ethtool },
+               { "SIOCGMIIPHY"       , &detect_link_mii     },
+               { "SIOCDEVPRIVATE"    , &detect_link_priv    },
+               { "wireless extension", &detect_link_wlan    },
+               { "IFF_RUNNING"       , &detect_link_iff     },
+       };
+       int i;
        smallint iface_status;
        smallint sv_logmode;
 
@@ -417,48 +432,17 @@ static smallint detect_link_auto(void)
        }
 
        sv_logmode = logmode;
-       logmode = LOGMODE_NONE;
-
-       iface_status = detect_link_ethtool();
-       if (iface_status != IFSTATUS_ERR) {
-               G.cached_detect_link_func = detect_link_ethtool;
-               method = "SIOCETHTOOL";
- found_method:
+       for (i = 0; i < ARRAY_SIZE(method); i++) {
+               logmode = LOGMODE_NONE;
+               iface_status = method[i].func();
                logmode = sv_logmode;
-               bb_error_msg("using %s detection mode", method);
-               return iface_status;
-       }
-
-       iface_status = detect_link_mii();
-       if (iface_status != IFSTATUS_ERR) {
-               G.cached_detect_link_func = detect_link_mii;
-               method = "SIOCGMIIPHY";
-               goto found_method;
-       }
-
-       iface_status = detect_link_priv();
-       if (iface_status != IFSTATUS_ERR) {
-               G.cached_detect_link_func = detect_link_priv;
-               method = "SIOCDEVPRIVATE";
-               goto found_method;
-       }
-
-       iface_status = detect_link_wlan();
-       if (iface_status != IFSTATUS_ERR) {
-               G.cached_detect_link_func = detect_link_wlan;
-               method = "wireless extension";
-               goto found_method;
-       }
-
-       iface_status = detect_link_iff();
-       if (iface_status != IFSTATUS_ERR) {
-               G.cached_detect_link_func = detect_link_iff;
-               method = "IFF_RUNNING";
-               goto found_method;
+               if (iface_status != IFSTATUS_ERR) {
+                       G.cached_detect_link_func = method[i].func;
+                       bb_error_msg("using %s detection mode", method[i].name);
+                       break;
+               }
        }
-
-       logmode = sv_logmode;
-       return iface_status; /* IFSTATUS_ERR */
+       return iface_status;
 }
 
 static smallint detect_link(void)
@@ -501,8 +485,10 @@ static smallint detect_link(void)
 
 static NOINLINE int check_existence_through_netlink(void)
 {
+       int iface_len;
        char replybuf[1024];
 
+       iface_len = strlen(G.iface);
        while (1) {
                struct nlmsghdr *mhdr;
                ssize_t bytes;
@@ -520,38 +506,31 @@ static NOINLINE int check_existence_through_netlink(void)
 
                mhdr = (struct nlmsghdr*)replybuf;
                while (bytes > 0) {
-                       if (!NLMSG_OK(mhdr, bytes)
-                        || bytes < sizeof(struct nlmsghdr)
-                        || bytes < mhdr->nlmsg_len
-                       ) {
+                       if (!NLMSG_OK(mhdr, bytes)) {
                                bb_error_msg("netlink packet too small or truncated");
                                return -1;
                        }
 
                        if (mhdr->nlmsg_type == RTM_NEWLINK || mhdr->nlmsg_type == RTM_DELLINK) {
                                struct rtattr *attr;
-                               struct ifinfomsg *imsg;
                                int attr_len;
 
-                               imsg = NLMSG_DATA(mhdr);
-
                                if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
                                        bb_error_msg("netlink packet too small or truncated");
                                        return -1;
                                }
 
-                               attr = (struct rtattr*)((char*)imsg + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
-                               attr_len = NLMSG_PAYLOAD(mhdr, sizeof(struct ifinfomsg));
+                               attr = IFLA_RTA(NLMSG_DATA(mhdr));
+                               attr_len = IFLA_PAYLOAD(mhdr);
 
                                while (RTA_OK(attr, attr_len)) {
                                        if (attr->rta_type == IFLA_IFNAME) {
-                                               char ifname[IFNAMSIZ + 1];
                                                int len = RTA_PAYLOAD(attr);
-
                                                if (len > IFNAMSIZ)
                                                        len = IFNAMSIZ;
-                                               memcpy(ifname, RTA_DATA(attr), len);
-                                               if (strcmp(G.iface, ifname) == 0) {
+                                               if (iface_len <= len
+                                                && strncmp(G.iface, RTA_DATA(attr), len) == 0
+                                               ) {
                                                        G.iface_exists = (mhdr->nlmsg_type == RTM_NEWLINK);
                                                }
                                        }