]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/iplink.c
Use libbsd for strlcpy if available
[mirror_iproute2.git] / ip / iplink.c
index 811513c01c25fa3bd66189d4ca6b463b67f55b3a..067f5409e569ef42c75711d1c78526e1f036452d 100644 (file)
@@ -13,7 +13,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <syslog.h>
 #include <fcntl.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
+#ifdef HAVE_LIBBSD
+#include <bsd/string.h>
+#endif
 #include <sys/ioctl.h>
-#include <linux/sockios.h>
 #include <stdbool.h>
 #include <linux/mpls.h>
 
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
-#include "xdp.h"
 #include "namespace.h"
 
 #define IPLINK_IOCTL_COMPAT    1
 #define LIBDIR "/usr/lib"
 #endif
 
+#ifndef GSO_MAX_SIZE
+#define GSO_MAX_SIZE           65536
+#endif
+#ifndef GSO_MAX_SEGS
+#define GSO_MAX_SEGS           65535
+#endif
+
+
 static void usage(void) __attribute__((noreturn));
 static int iplink_have_newlink(void);
 
@@ -80,7 +88,7 @@ void iplink_usage(void)
                "                         [ broadcast LLADDR ]\n"
                "                         [ mtu MTU ]\n"
                "                         [ netns { PID | NAME } ]\n"
-               "                         [ link-netnsid ID ]\n"
+               "                         [ link-netns NAME | link-netnsid ID ]\n"
                "                         [ alias NAME ]\n"
                "                         [ vf NUM [ mac LLADDR ]\n"
                "                                  [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
@@ -99,7 +107,8 @@ void iplink_usage(void)
                "                         [ master DEVICE ][ vrf NAME ]\n"
                "                         [ nomaster ]\n"
                "                         [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
-               "                         [ protodown { on | off } ]\n"
+               "                         [ protodown { on | off } ]\n"
+               "                         [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
                "\n"
                "       ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
 
@@ -111,10 +120,11 @@ void iplink_usage(void)
                        "\n"
                        "       ip link help [ TYPE ]\n"
                        "\n"
-                       "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"
+                       "TYPE := { vlan | veth | vcan | vxcan | dummy | ifb | macvlan | macvtap |\n"
                        "          bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
-                       "          gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n"
-                       "          bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n");
+                       "          gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan |\n"
+                       "          vti | nlmon | team_slave | bond_slave | bridge_slave |\n"
+                       "          ipvlan | ipvtap | geneve | vrf | macsec | netdevsim | rmnet }\n");
        }
        exit(-1);
 }
@@ -192,8 +202,7 @@ static int get_addr_gen_mode(const char *mode)
 #if IPLINK_IOCTL_COMPAT
 static int have_rtnl_newlink = -1;
 
-static int accept_msg(const struct sockaddr_nl *who,
-                     struct rtnl_ctrl_data *ctrl,
+static int accept_msg(struct rtnl_ctrl_data *ctrl,
                      struct nlmsghdr *n, void *arg)
 {
        struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
@@ -235,9 +244,10 @@ static int iplink_have_newlink(void)
 }
 #endif /* ! IPLINK_IOCTL_COMPAT */
 
-static int nl_get_ll_addr_len(unsigned int dev_index)
+static int nl_get_ll_addr_len(const char *ifname)
 {
        int len;
+       int dev_index = ll_name_to_index(ifname);
        struct iplink_req req = {
                .n = {
                        .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
@@ -249,20 +259,31 @@ static int nl_get_ll_addr_len(unsigned int dev_index)
                        .ifi_index = dev_index,
                }
        };
+       struct nlmsghdr *answer;
        struct rtattr *tb[IFLA_MAX+1];
 
-       if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
+       if (dev_index == 0)
                return -1;
 
-       len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.i));
-       if (len < 0)
+       if (rtnl_talk(&rth, &req.n, &answer) < 0)
                return -1;
 
-       parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(&req.i), len, NLA_F_NESTED);
-       if (!tb[IFLA_ADDRESS])
+       len = answer->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       if (len < 0) {
+               free(answer);
                return -1;
+       }
+
+       parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)),
+                          len, NLA_F_NESTED);
+       if (!tb[IFLA_ADDRESS]) {
+               free(answer);
+               return -1;
+       }
 
-       return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
+       len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
+       free(answer);
+       return len;
 }
 
 static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
@@ -270,11 +291,13 @@ static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
 {
        int argc = *argcp;
        char **argv = *argvp;
+       unsigned int vci;
 
        NEXT_ARG();
-       if (get_unsigned(&ivvip->vlan, *argv, 0))
+       if (get_unsigned(&vci, *argv, 0) || vci > 4095)
                invarg("Invalid \"vlan\" value\n", *argv);
 
+       ivvip->vlan = vci;
        ivvip->vf = vf;
        ivvip->qos = 0;
        ivvip->vlan_proto = htons(ETH_P_8021Q);
@@ -320,7 +343,7 @@ static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
 }
 
 static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
-                          struct iplink_req *req, int dev_index)
+                          struct iplink_req *req, const char *dev)
 {
        char new_rate_api = 0, count = 0, override_legacy_rate = 0;
        struct ifla_vf_rate tivt;
@@ -356,7 +379,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                NEXT_ARG();
                if (matches(*argv, "mac") == 0) {
                        struct ifla_vf_mac ivm = { 0 };
-                       int halen = nl_get_ll_addr_len(dev_index);
+                       int halen = nl_get_ll_addr_len(dev);
 
                        NEXT_ARG();
                        ivm.vf = vf;
@@ -525,12 +548,20 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                int tmin, tmax;
 
                if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
-                       ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
+                       ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev);
                        if (tivt.min_tx_rate == -1)
                                tivt.min_tx_rate = tmin;
                        if (tivt.max_tx_rate == -1)
                                tivt.max_tx_rate = tmax;
                }
+
+               if (tivt.max_tx_rate && tivt.min_tx_rate > tivt.max_tx_rate) {
+                       fprintf(stderr,
+                               "Invalid min_tx_rate %d - must be <= max_tx_rate %d\n",
+                               tivt.min_tx_rate, tivt.max_tx_rate);
+                       return -1;
+               }
+
                addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
                          sizeof(tivt));
        }
@@ -545,10 +576,11 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
        return 0;
 }
 
-int iplink_parse(int argc, char **argv, struct iplink_req *req,
-                char **name, char **type, char **link, char **dev,
-                int *group, int *index)
+int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
 {
+       char *name = NULL;
+       char *dev = NULL;
+       char *link = NULL;
        int ret, len;
        char abuf[32];
        int qlen = -1;
@@ -557,11 +589,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
        int vf = -1;
        int numtxqueues = -1;
        int numrxqueues = -1;
-       int dev_index = 0;
        int link_netnsid = -1;
+       int index = 0;
+       int group = -1;
        int addr_len = 0;
 
-       *group = -1;
        ret = argc;
 
        while (argc > 0) {
@@ -573,15 +605,23 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        req->i.ifi_flags &= ~IFF_UP;
                } else if (strcmp(*argv, "name") == 0) {
                        NEXT_ARG();
-                       *name = *argv;
+                       if (name)
+                               duparg("name", *argv);
+                       if (check_ifname(*argv))
+                               invarg("\"name\" not a valid ifname", *argv);
+                       name = *argv;
+                       if (!dev)
+                               dev = name;
                } else if (strcmp(*argv, "index") == 0) {
                        NEXT_ARG();
-                       *index = atoi(*argv);
-                       if (*index < 0)
+                       if (index)
+                               duparg("index", *argv);
+                       index = atoi(*argv);
+                       if (index <= 0)
                                invarg("Invalid \"index\" value", *argv);
                } else if (matches(*argv, "link") == 0) {
                        NEXT_ARG();
-                       *link = *argv;
+                       link = *argv;
                } else if (matches(*argv, "address") == 0) {
                        NEXT_ARG();
                        addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
@@ -616,13 +656,19 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
                } else if (strcmp(*argv, "xdpgeneric") == 0 ||
                           strcmp(*argv, "xdpdrv") == 0 ||
+                          strcmp(*argv, "xdpoffload") == 0 ||
                           strcmp(*argv, "xdp") == 0) {
                        bool generic = strcmp(*argv, "xdpgeneric") == 0;
                        bool drv = strcmp(*argv, "xdpdrv") == 0;
+                       bool offload = strcmp(*argv, "xdpoffload") == 0;
 
                        NEXT_ARG();
-                       if (xdp_parse(&argc, &argv, req, generic, drv))
+                       if (xdp_parse(&argc, &argv, req, dev,
+                                     generic, drv, offload))
                                exit(-1);
+
+                       if (offload && name == dev)
+                               dev = NULL;
                } else if (strcmp(*argv, "netns") == 0) {
                        NEXT_ARG();
                        if (netns != -1)
@@ -707,13 +753,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
 
                        vflist = addattr_nest(&req->n, sizeof(*req),
                                              IFLA_VFINFO_LIST);
-                       if (dev_index == 0)
+                       if (!dev)
                                missarg("dev");
 
-                       len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
+                       len = iplink_parse_vf(vf, &argc, &argv, req, dev);
                        if (len < 0)
                                return -1;
                        addattr_nest_end(&req->n, vflist);
+
+                       if (name == dev)
+                               dev = NULL;
                } else if (matches(*argv, "master") == 0) {
                        int ifindex;
 
@@ -756,16 +805,18 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        break;
                } else if (matches(*argv, "alias") == 0) {
                        NEXT_ARG();
+                       len = strlen(*argv);
+                       if (len >= IFALIASZ)
+                               invarg("alias too long\n", *argv);
                        addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
-                                 *argv, strlen(*argv));
-                       argc--; argv++;
-                       break;
+                                 *argv, len);
                } else if (strcmp(*argv, "group") == 0) {
                        NEXT_ARG();
-                       if (*group != -1)
+                       if (group != -1)
                                duparg("group", *argv);
-                       if (rtnl_group_a2n(group, *argv))
+                       if (rtnl_group_a2n(&group, *argv))
                                invarg("Invalid \"group\" value\n", *argv);
+                       addattr32(&req->n, sizeof(*req), IFLA_GROUP, group);
                } else if (strcmp(*argv, "mode") == 0) {
                        int mode;
 
@@ -816,10 +867,24 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                 IFLA_INET6_ADDR_GEN_MODE, mode);
                        addattr_nest_end(&req->n, afs6);
                        addattr_nest_end(&req->n, afs);
+               } else if (matches(*argv, "link-netns") == 0) {
+                       NEXT_ARG();
+                       if (link_netnsid != -1)
+                               duparg("link-netns/link-netnsid", *argv);
+                       link_netnsid = get_netnsid_from_name(*argv);
+                       /* No nsid? Try to assign one. */
+                       if (link_netnsid < 0)
+                               set_netnsid_from_name(*argv, -1);
+                       link_netnsid = get_netnsid_from_name(*argv);
+                       if (link_netnsid < 0)
+                               invarg("Invalid \"link-netns\" value\n",
+                                      *argv);
+                       addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
+                                 link_netnsid);
                } else if (matches(*argv, "link-netnsid") == 0) {
                        NEXT_ARG();
                        if (link_netnsid != -1)
-                               duparg("link-netnsid", *argv);
+                               duparg("link-netns/link-netnsid", *argv);
                        if (get_integer(&link_netnsid, *argv, 0))
                                invarg("Invalid \"link-netnsid\" value\n",
                                       *argv);
@@ -837,22 +902,53 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                return on_off("protodown", *argv);
                        addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
                                 proto_down);
+               } else if (strcmp(*argv, "gso_max_size") == 0) {
+                       unsigned int max_size;
+
+                       NEXT_ARG();
+                       if (get_unsigned(&max_size, *argv, 0) ||
+                           max_size > GSO_MAX_SIZE)
+                               invarg("Invalid \"gso_max_size\" value\n",
+                                      *argv);
+                       addattr32(&req->n, sizeof(*req),
+                                 IFLA_GSO_MAX_SIZE, max_size);
+               } else if (strcmp(*argv, "gso_max_segs") == 0) {
+                       unsigned int max_segs;
+
+                       NEXT_ARG();
+                       if (get_unsigned(&max_segs, *argv, 0) ||
+                           max_segs > GSO_MAX_SEGS)
+                               invarg("Invalid \"gso_max_segs\" value\n",
+                                      *argv);
+                       addattr32(&req->n, sizeof(*req),
+                                 IFLA_GSO_MAX_SEGS, max_segs);
                } else {
                        if (matches(*argv, "help") == 0)
                                usage();
 
                        if (strcmp(*argv, "dev") == 0)
                                NEXT_ARG();
-                       if (*dev)
+                       if (dev != name)
                                duparg2("dev", *argv);
-                       *dev = *argv;
-                       dev_index = ll_name_to_index(*dev);
+                       if (check_ifname(*argv))
+                               invarg("\"dev\" not a valid ifname", *argv);
+                       dev = *argv;
                }
                argc--; argv++;
        }
 
-       if (dev_index && addr_len) {
-               int halen = nl_get_ll_addr_len(dev_index);
+       ret -= argc;
+
+       /* Allow "ip link add dev" and "ip link add name" */
+       if (!name)
+               name = dev;
+       else if (!dev)
+               dev = name;
+       else if (!strcmp(name, dev))
+               name = dev;
+
+       if (dev && addr_len) {
+               int halen = nl_get_ll_addr_len(dev);
 
                if (halen >= 0 && halen != addr_len) {
                        fprintf(stderr,
@@ -862,111 +958,89 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                }
        }
 
-       return ret - argc;
-}
-
-static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
-{
-       int len;
-       char *dev = NULL;
-       char *name = NULL;
-       char *link = NULL;
-       char *type = NULL;
-       int index = -1;
-       int group;
-       struct link_util *lu = NULL;
-       struct iplink_req req = {
-               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-               .n.nlmsg_flags = NLM_F_REQUEST | flags,
-               .n.nlmsg_type = cmd,
-               .i.ifi_family = preferred_family,
-       };
-       int ret;
-
-       ret = iplink_parse(argc, argv,
-                          &req, &name, &type, &link, &dev, &group, &index);
-       if (ret < 0)
-               return ret;
-
-       argc -= ret;
-       argv += ret;
+       if (!(req->n.nlmsg_flags & NLM_F_CREATE) && index) {
+               fprintf(stderr,
+                       "index can be used only when creating devices.\n");
+               exit(-1);
+       }
 
        if (group != -1) {
-               if (dev)
-                       addattr_l(&req.n, sizeof(req), IFLA_GROUP,
-                                       &group, sizeof(group));
-               else {
+               if (!dev) {
                        if (argc) {
                                fprintf(stderr,
                                        "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
                                        *argv);
-                               return -1;
+                               exit(-1);
                        }
-                       if (flags & NLM_F_CREATE) {
+                       if (req->n.nlmsg_flags & NLM_F_CREATE) {
                                fprintf(stderr,
                                        "group cannot be used when creating devices.\n");
-                               return -1;
+                               exit(-1);
                        }
 
-                       req.i.ifi_index = 0;
-                       addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
-                       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
-                               return -2;
-                       return 0;
+                       *type = NULL;
+                       return ret;
                }
        }
 
-       if (!(flags & NLM_F_CREATE)) {
+       if (!(req->n.nlmsg_flags & NLM_F_CREATE)) {
                if (!dev) {
                        fprintf(stderr,
                                "Not enough information: \"dev\" argument is required.\n");
                        exit(-1);
                }
-               if (cmd == RTM_NEWLINK && index != -1) {
+
+               req->i.ifi_index = ll_name_to_index(dev);
+               if (!req->i.ifi_index)
+                       return nodev(dev);
+
+               /* Not renaming to the same name */
+               if (name == dev)
+                       name = NULL;
+       } else {
+               if (name != dev) {
                        fprintf(stderr,
-                               "index can be used only when creating devices.\n");
+                               "both \"name\" and \"dev\" cannot be used when creating devices.\n");
                        exit(-1);
                }
 
-               req.i.ifi_index = ll_name_to_index(dev);
-               if (req.i.ifi_index == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", dev);
-                       return -1;
-               }
-       } else {
-               /* Allow "ip link add dev" and "ip link add name" */
-               if (!name)
-                       name = dev;
-
                if (link) {
                        int ifindex;
 
                        ifindex = ll_name_to_index(link);
-                       if (ifindex == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       link);
-                               return -1;
-                       }
-                       addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+                       if (!ifindex)
+                               return nodev(link);
+                       addattr32(&req->n, sizeof(*req), IFLA_LINK, ifindex);
                }
 
-               if (index == -1)
-                       req.i.ifi_index = 0;
-               else
-                       req.i.ifi_index = index;
+               req->i.ifi_index = index;
        }
 
        if (name) {
-               len = strlen(name) + 1;
-               if (len == 1)
-                       invarg("\"\" is not a valid device identifier\n",
-                              "name");
-               if (len > IFNAMSIZ)
-                       invarg("\"name\" too long\n", name);
-               addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
+               addattr_l(&req->n, sizeof(*req),
+                         IFLA_IFNAME, name, strlen(name) + 1);
        }
 
+       return ret;
+}
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
+{
+       char *type = NULL;
+       struct iplink_req req = {
+               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+               .n.nlmsg_flags = NLM_F_REQUEST | flags,
+               .n.nlmsg_type = cmd,
+               .i.ifi_family = preferred_family,
+       };
+       int ret;
+
+       ret = iplink_parse(argc, argv, &req, &type);
+       if (ret < 0)
+               return ret;
+
        if (type) {
+               struct link_util *lu;
                struct rtattr *linkinfo;
                char *ulinep = strchr(type, '_');
                int iflatype;
@@ -980,10 +1054,14 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                        iflatype = IFLA_INFO_SLAVE_DATA;
                else
                        iflatype = IFLA_INFO_DATA;
+
+               argc -= ret;
+               argv += ret;
+
                if (lu && argc) {
-                       struct rtattr *data
-                               = addattr_nest(&req.n,
-                                              sizeof(req), iflatype);
+                       struct rtattr *data;
+
+                       data = addattr_nest(&req.n, sizeof(req), iflatype);
 
                        if (lu->parse_opt &&
                            lu->parse_opt(lu, argc, argv, &req.n))
@@ -1005,45 +1083,36 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                return -1;
        }
 
-       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+       if (rtnl_talk(&rth, &req.n, NULL) < 0)
                return -2;
 
        return 0;
 }
 
-int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
+int iplink_get(char *name, __u32 filt_mask)
 {
-       int len;
        struct iplink_req req = {
                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-               .n.nlmsg_flags = NLM_F_REQUEST | flags,
+               .n.nlmsg_flags = NLM_F_REQUEST,
                .n.nlmsg_type = RTM_GETLINK,
                .i.ifi_family = preferred_family,
        };
-       struct {
-               struct nlmsghdr n;
-               char buf[16384];
-       } answer;
+       struct nlmsghdr *answer;
 
        if (name) {
-               len = strlen(name) + 1;
-               if (len == 1)
-                       invarg("\"\" is not a valid device identifier\n",
-                                  "name");
-               if (len > IFNAMSIZ)
-                       invarg("\"name\" too long\n", name);
-               addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
+               addattr_l(&req.n, sizeof(req),
+                         IFLA_IFNAME, name, strlen(name) + 1);
        }
        addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
 
-       if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
+       if (rtnl_talk(&rth, &req.n, &answer) < 0)
                return -2;
 
-       if (brief)
-               print_linkinfo_brief(NULL, &answer.n, stdout, NULL);
-       else
-               print_linkinfo(NULL, &answer.n, stdout);
+       open_json_object(NULL);
+       print_linkinfo(answer, stdout);
+       close_json_object();
 
+       free(answer);
        return 0;
 }
 
@@ -1074,7 +1143,7 @@ static int do_chflags(const char *dev, __u32 flags, __u32 mask)
        int fd;
        int err;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        fd = get_ctl_fd();
        if (fd < 0)
                return -1;
@@ -1101,8 +1170,8 @@ static int do_changename(const char *dev, const char *newdev)
        int fd;
        int err;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
-       strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_newname, newdev, IFNAMSIZ);
        fd = get_ctl_fd();
        if (fd < 0)
                return -1;
@@ -1125,7 +1194,7 @@ static int set_qlen(const char *dev, int qlen)
        if (s < 0)
                return -1;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
                perror("SIOCSIFXQLEN");
                close(s);
@@ -1145,7 +1214,7 @@ static int set_mtu(const char *dev, int mtu)
        if (s < 0)
                return -1;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
                perror("SIOCSIFMTU");
                close(s);
@@ -1172,7 +1241,7 @@ static int get_address(const char *dev, int *htype)
                return -1;
        }
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
                perror("SIOCGIFINDEX");
                close(s);
@@ -1203,7 +1272,7 @@ static int parse_address(const char *dev, int hatype, int halen,
        int alen;
 
        memset(ifr, 0, sizeof(*ifr));
-       strncpy(ifr->ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr->ifr_name, dev, IFNAMSIZ);
        ifr->ifr_hwaddr.sa_family = hatype;
        alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
        if (alen < 0)
@@ -1255,6 +1324,8 @@ static int do_set(int argc, char **argv)
                        flags &= ~IFF_UP;
                } else if (strcmp(*argv, "name") == 0) {
                        NEXT_ARG();
+                       if (check_ifname(*argv))
+                               invarg("\"name\" not a valid ifname", *argv);
                        newname = *argv;
                } else if (matches(*argv, "address") == 0) {
                        NEXT_ARG();
@@ -1345,6 +1416,8 @@ static int do_set(int argc, char **argv)
 
                        if (dev)
                                duparg2("dev", *argv);
+                       if (check_ifname(*argv))
+                               invarg("\"dev\" not a valid ifname", *argv);
                        dev = *argv;
                }
                argc--; argv++;
@@ -1373,9 +1446,6 @@ static int do_set(int argc, char **argv)
        }
 
        if (newname && strcmp(dev, newname)) {
-               if (strlen(newname) == 0)
-                       invarg("\"\" is not a valid device identifier\n",
-                              "name");
                if (do_changename(dev, newname) < 0)
                        return -1;
                dev = newname;
@@ -1468,9 +1538,7 @@ struct af_stats_ctx {
        int ifindex;
 };
 
-static int print_af_stats(const struct sockaddr_nl *who,
-                         struct nlmsghdr *n,
-                         void *arg)
+static int print_af_stats(struct nlmsghdr *n, void *arg)
 {
        struct if_stats_msg *ifsm = NLMSG_DATA(n);
        struct rtattr *tb[IFLA_STATS_MAX+1];
@@ -1533,9 +1601,7 @@ static int iplink_afstats(int argc, char **argv)
                }
        }
 
-       if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
-                                          RTM_GETSTATS,
-                                          filt_mask) < 0) {
+       if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
                perror("Cannont send dump request");
                return 1;
        }