static const char *proc_path = "/proc";
static const char *sysfs_path = "/sys";
+struct netdev_type {
+ unsigned short id;
+ const char *name;
+};
+
+static const struct netdev_type netdev_types[] = {
+ {ARPHRD_NETROM, "netrom"},
+ {ARPHRD_ETHER, "ethernet"},
+ {ARPHRD_EETHER, "eethernet"},
+ {ARPHRD_AX25, "ax25"},
+ {ARPHRD_PRONET, "pronet"},
+ {ARPHRD_CHAOS, "chaos"},
+ {ARPHRD_IEEE802, "ieee802"},
+ {ARPHRD_ARCNET, "arcnet"},
+ {ARPHRD_APPLETLK, "appletlk"},
+ {ARPHRD_DLCI, "dlci"},
+ {ARPHRD_ATM, "atm"},
+ {ARPHRD_METRICOM, "metricom"},
+ {ARPHRD_IEEE1394, "ieee1394"},
+ {ARPHRD_EUI64, "eui64"},
+ {ARPHRD_INFINIBAND, "infiniband"},
+ {ARPHRD_SLIP, "slip"},
+ {ARPHRD_CSLIP, "cslip"},
+ {ARPHRD_SLIP6, "slip6"},
+ {ARPHRD_CSLIP6, "cslip6"},
+ {ARPHRD_RSRVD, "rsrvd"},
+ {ARPHRD_ADAPT, "adapt"},
+ {ARPHRD_ROSE, "rose"},
+ {ARPHRD_X25, "x25"},
+ {ARPHRD_HWX25, "hwx25"},
+ {ARPHRD_PPP, "ppp"},
+ {ARPHRD_CISCO, "cisco"},
+ {ARPHRD_LAPB, "lapb"},
+ {ARPHRD_DDCMP, "ddcmp"},
+ {ARPHRD_RAWHDLC, "rawhdlc"},
+ {ARPHRD_TUNNEL, "tunnel"},
+ {ARPHRD_TUNNEL6, "tunnel6"},
+ {ARPHRD_FRAD, "frad"},
+ {ARPHRD_SKIP, "skip"},
+ {ARPHRD_LOOPBACK, "loopback"},
+ {ARPHRD_LOCALTLK, "localtlk"},
+ {ARPHRD_FDDI, "fddi"},
+ {ARPHRD_BIF, "bif"},
+ {ARPHRD_SIT, "sit"},
+ {ARPHRD_IPDDP, "ipddp"},
+ {ARPHRD_IPGRE, "ipgre"},
+ {ARPHRD_PIMREG,"pimreg"},
+ {ARPHRD_HIPPI, "hippi"},
+ {ARPHRD_ASH, "ash"},
+ {ARPHRD_ECONET, "econet"},
+ {ARPHRD_IRDA, "irda"},
+ {ARPHRD_FCPP, "fcpp"},
+ {ARPHRD_FCAL, "fcal"},
+ {ARPHRD_FCPL, "fcpl"},
+ {ARPHRD_FCFABRIC, "fcfabric"},
+ {ARPHRD_IEEE80211, "ieee80211"},
+ {ARPHRD_IEEE80211_PRISM, "ie80211-prism"},
+ {ARPHRD_IEEE80211_RADIOTAP, "ieee80211-radiotap"},
+#ifdef ARPHRD_PHONET
+ {ARPHRD_PHONET, "phonet"},
+#endif
+#ifdef ARPHRD_PHONET_PIPE
+ {ARPHRD_PHONET_PIPE, "phonet-pipe"},
+#endif
+ {ARPHRD_IEEE802154, "ieee802154"},
+ {ARPHRD_VOID, "void"},
+ {ARPHRD_NONE, "none"}
+};
+
static void
handler_nl_event(struct uloop_fd *u, unsigned int events)
{
return nl_wait_for_ack(sock_rtnl);
}
-static int system_link_del(const char *ifname)
+static struct nl_msg *__system_ifinfo_msg(int af, int index, const char *ifname, uint16_t type, uint16_t flags)
{
struct nl_msg *msg;
struct ifinfomsg iim = {
- .ifi_family = AF_UNSPEC,
- .ifi_index = 0,
+ .ifi_family = af,
+ .ifi_index = index,
};
- msg = nlmsg_alloc_simple(RTM_DELLINK, NLM_F_REQUEST);
+ msg = nlmsg_alloc_simple(type, flags | NLM_F_REQUEST);
+ if (!msg)
+ return NULL;
+
+ nlmsg_append(msg, &iim, sizeof(iim), 0);
+ if (ifname)
+ nla_put_string(msg, IFLA_IFNAME, ifname);
+ return msg;
+}
+
+static struct nl_msg *system_ifinfo_msg(const char *ifname, uint16_t type, uint16_t flags)
+{
+ return __system_ifinfo_msg(AF_UNSPEC, 0, ifname, type, flags);
+}
+
+static int system_link_del(const char *ifname)
+{
+ struct nl_msg *msg;
+
+ msg = system_ifinfo_msg(ifname, RTM_DELLINK, 0);
if (!msg)
return -1;
- nlmsg_append(msg, &iim, sizeof(iim), 0);
- nla_put_string(msg, IFLA_IFNAME, ifname);
return system_rtnl_call(msg);
}
bool mcast_to_ucast = dev->wireless_ap;
bool hairpin;
- if (bridge->settings.flags & DEV_OPT_MULTICAST_TO_UNICAST &&
- !bridge->settings.multicast_to_unicast)
+ if (dev->settings.flags & DEV_OPT_MULTICAST_TO_UNICAST)
+ mcast_to_ucast = dev->settings.multicast_to_unicast;
+ else if (bridge->settings.flags & DEV_OPT_MULTICAST_TO_UNICAST &&
+ !bridge->settings.multicast_to_unicast)
mcast_to_ucast = false;
hairpin = mcast_to_ucast || dev->wireless_proxyarp;
int system_bridge_vlan(const char *iface, uint16_t vid, bool add, unsigned int vflags)
{
- struct ifinfomsg ifi = { .ifi_family = PF_BRIDGE, };
struct bridge_vlan_info vinfo = { .vid = vid, };
unsigned short flags = 0;
struct nlattr *afspec;
struct nl_msg *nlm;
+ int index;
int ret = 0;
- ifi.ifi_index = if_nametoindex(iface);
- if (!ifi.ifi_index)
+ index = if_nametoindex(iface);
+ if (!index)
return -1;
- nlm = nlmsg_alloc_simple(add ? RTM_SETLINK : RTM_DELLINK, NLM_F_REQUEST);
+ nlm = __system_ifinfo_msg(PF_BRIDGE, index, NULL, add ? RTM_SETLINK : RTM_DELLINK, 0);
if (!nlm)
return -1;
- nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
-
if (vflags & BRVLAN_F_SELF)
flags |= BRIDGE_FLAGS_SELF;
struct blob_attr *cur;
char op = cfg ? '+' : '-';
char buf[64];
- int rem;
+ size_t rem;
snprintf(dev_buf, sizeof(dev_buf), "%s/class/net/bonding_masters", sysfs_path);
snprintf(buf, sizeof(buf), "%c%s", op, ifname);
{
const char *port_name = port->ifname;
const char op_ch = add ? '+' : '-';
- char buf[IFNAMSIZ + 2];
+ char buf[IFNAMSIZ + 1];
snprintf(buf, sizeof(buf), "%c%s", op_ch, port_name);
system_if_down(port);
{
struct ifaddrmsg *ifa = NLMSG_DATA(hdr);
- return ifa->ifa_index == ifindex;
+ return (long)ifa->ifa_index == ifindex;
}
static bool check_route(struct nlmsghdr *hdr, int ifindex)
int system_bridge_addbr(struct device *bridge, struct bridge_config *cfg)
{
- struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, };
struct nlattr *linkinfo, *data;
struct nl_msg *msg;
uint64_t val;
int rv;
- msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+ msg = system_ifinfo_msg(bridge->ifname, RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL);
if (!msg)
return -1;
- nlmsg_append(msg, &iim, sizeof(iim), 0);
-
- nla_put_string(msg, IFLA_IFNAME, bridge->ifname);
-
if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
goto nla_put_failure;
{
struct nl_msg *msg;
struct nlattr *linkinfo, *data;
- struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, };
- int i, rv;
+ size_t i;
+ int rv;
static const struct {
const char *name;
enum macvlan_mode val;
{ "passthru", MACVLAN_MODE_PASSTHRU },
};
- msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
-
+ msg = system_ifinfo_msg(macvlan->ifname, RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL);
if (!msg)
return -1;
- nlmsg_append(msg, &iim, sizeof(iim), 0);
-
if (cfg->flags & MACVLAN_OPT_MACADDR)
nla_put(msg, IFLA_ADDRESS, sizeof(cfg->macaddr), cfg->macaddr);
- nla_put_string(msg, IFLA_IFNAME, macvlan->ifname);
nla_put_u32(msg, IFLA_LINK, dev->ifindex);
if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
int system_link_netns_move(struct device *dev, int netns_fd, const char *target_ifname)
{
struct nl_msg *msg;
- struct ifinfomsg iim = {
- .ifi_family = AF_UNSPEC,
- };
+ int index;
if (!dev)
return -1;
- iim.ifi_index = system_if_resolve(dev);
- msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST);
-
+ index = system_if_resolve(dev);
+ msg = __system_ifinfo_msg(AF_UNSPEC, index, target_ifname, RTM_NEWLINK, 0);
if (!msg)
return -1;
- nlmsg_append(msg, &iim, sizeof(iim), 0);
- if (target_ifname)
- nla_put_string(msg, IFLA_IFNAME, target_ifname);
-
nla_put_u32(msg, IFLA_NET_NS_FD, netns_fd);
return system_rtnl_call(msg);
}
int system_veth_add(struct device *veth, struct veth_config *cfg)
{
struct nl_msg *msg;
- struct ifinfomsg empty_iim = {};
+ struct ifinfomsg empty_iim = {0,};
struct nlattr *linkinfo, *data, *veth_info;
int rv;
.ifr_data = (caddr_t)&ecmd,
};
static const struct {
- int speed;
+ unsigned int speed;
uint8_t bit_half;
uint8_t bit_full;
} speed_mask[] = {
{ 1000, ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT },
};
uint32_t adv;
- int i;
+ size_t i;
strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
static void system_add_link_modes(struct blob_buf *b, __u32 mask)
{
- int i;
+ size_t i;
for (i = 0; i < ARRAY_SIZE(ethtool_link_modes); i++) {
if (mask & ethtool_link_modes[i].mask)
blobmsg_add_string(b, NULL, ethtool_link_modes[i].name);
static const char *
system_netdevtype_name(unsigned short dev_type)
{
- unsigned int i;
+ size_t i;
for (i = 0; i < ARRAY_SIZE(netdev_types); i++) {
if (netdev_types[i].id == dev_type)
}
}
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+static int32_t
+ethtool_feature_count(const char *ifname)
+{
+ struct {
+ struct ethtool_sset_info hdr;
+ uint32_t buf;
+ } req = {
+ .hdr = {
+ .cmd = ETHTOOL_GSSET_INFO,
+ .sset_mask = 1 << ETH_SS_FEATURES
+ }
+ };
+
+ struct ifreq ifr = {
+ .ifr_data = (void *)&req
+ };
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+
+ if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) != 0)
+ return -1;
+
+ if (!req.hdr.sset_mask)
+ return 0;
+
+ return req.buf;
+}
+
+static int32_t
+ethtool_feature_index(const char *ifname, const char *keyname)
+{
+ struct ethtool_gstrings *feature_names;
+ struct ifreq ifr = { 0 };
+ int32_t n_features;
+ uint32_t i;
+
+ n_features = ethtool_feature_count(ifname);
+
+ if (n_features <= 0)
+ return -1;
+
+ feature_names = calloc(1, sizeof(*feature_names) + n_features * ETH_GSTRING_LEN);
+
+ if (!feature_names)
+ return -1;
+
+ feature_names->cmd = ETHTOOL_GSTRINGS;
+ feature_names->string_set = ETH_SS_FEATURES;
+ feature_names->len = n_features;
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_data = (void *)feature_names;
+
+ if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) != 0) {
+ free(feature_names);
+
+ return -1;
+ }
+
+ for (i = 0; i < feature_names->len; i++)
+ if (!strcmp((char *)&feature_names->data[i * ETH_GSTRING_LEN], keyname))
+ break;
+
+ if (i >= feature_names->len)
+ i = -1;
+
+ free(feature_names);
+
+ return i;
+}
+
+static bool
+ethtool_feature_value(const char *ifname, const char *keyname)
+{
+ struct ethtool_get_features_block *feature_block;
+ struct ethtool_gfeatures *feature_values;
+ struct ifreq ifr = { 0 };
+ int32_t feature_idx;
+ bool active;
+
+ feature_idx = ethtool_feature_index(ifname, keyname);
+
+ if (feature_idx < 0)
+ return false;
+
+ feature_values = calloc(1,
+ sizeof(*feature_values) +
+ sizeof(feature_values->features[0]) * DIV_ROUND_UP(feature_idx, 32));
+
+ if (!feature_values)
+ return false;
+
+ feature_values->cmd = ETHTOOL_GFEATURES;
+ feature_values->size = DIV_ROUND_UP(feature_idx, 32);
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_data = (void *)feature_values;
+
+ if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) != 0) {
+ free(feature_values);
+
+ return false;
+ }
+
+ feature_block = &feature_values->features[feature_idx / 32];
+ active = feature_block->active & (1U << feature_idx % 32);
+
+ free(feature_values);
+
+ return active;
+}
+
int
system_if_dump_info(struct device *dev, struct blob_buf *b)
{
blobmsg_add_u8(b, "autoneg", !!ecmd.autoneg);
}
+ blobmsg_add_u8(b, "hw-tc-offload",
+ ethtool_feature_value(dev->ifname, "hw-tc-offload"));
+
system_add_devtype(b, dev->ifname);
return 0;
"rx_fifo_errors", "tx_carrier_errors",
};
int stats_dir;
- int i;
+ size_t i;
uint64_t val = 0;
stats_dir = open(dev_sysfs_path(dev->ifname, "statistics"), O_DIRECTORY);
int system_flush_routes(void)
{
const char *names[] = { "ipv4", "ipv6" };
- int fd, i;
+ size_t i;
+ int fd;
for (i = 0; i < ARRAY_SIZE(names); i++) {
snprintf(dev_buf, sizeof(dev_buf), "%s/sys/net/%s/route/flush", proc_path, names[i]);