X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=system-linux.c;h=0ff2b3b344d742c0beb457a4bbd11c1e6ae53974;hp=159817063f2c1da2700455daf01f7d2034d18206;hb=91fa29a0d17b40963f67f08e740ca0a07365db90;hpb=7af8f13d78660a5983774cde352bf452e6a43876 diff --git a/system-linux.c b/system-linux.c index 1598170..0ff2b3b 100644 --- a/system-linux.c +++ b/system-linux.c @@ -9,11 +9,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -568,31 +570,30 @@ int system_vlan_del(struct device *dev) } static void -system_if_apply_settings(struct device *dev) +system_if_apply_settings(struct device *dev, struct device_settings *s) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name)); - if (dev->flags & DEV_OPT_MTU) { - ifr.ifr_mtu = dev->mtu; + if (s->flags & DEV_OPT_MTU) { + ifr.ifr_mtu = s->mtu; ioctl(sock_ioctl, SIOCSIFMTU, &ifr); } - if (dev->flags & DEV_OPT_TXQUEUELEN) { - ifr.ifr_qlen = dev->txqueuelen; + if (s->flags & DEV_OPT_TXQUEUELEN) { + ifr.ifr_qlen = s->txqueuelen; ioctl(sock_ioctl, SIOCSIFTXQLEN, &ifr); } - if (dev->flags & DEV_OPT_MACADDR) { - memcpy(&ifr.ifr_hwaddr, dev->macaddr, sizeof(dev->macaddr)); + if (s->flags & DEV_OPT_MACADDR) { + memcpy(&ifr.ifr_hwaddr, s->macaddr, sizeof(s->macaddr)); ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr); } - - dev->ifindex = system_if_resolve(dev); } int system_if_up(struct device *dev) { - system_if_apply_settings(dev); + system_if_apply_settings(dev, &dev->settings); + dev->ifindex = system_if_resolve(dev); return system_if_flags(dev->ifname, IFF_UP, 0); } @@ -603,11 +604,151 @@ int system_if_down(struct device *dev) int system_if_check(struct device *dev) { - device_set_present(dev, (system_if_resolve(dev) >= 0)); + device_set_present(dev, (system_if_resolve(dev) > 0)); + return 0; +} + +struct device * +system_if_get_parent(struct device *dev) +{ + char buf[64], *devname; + int ifindex, iflink, len; + FILE *f; + + snprintf(buf, sizeof(buf), "/sys/class/net/%s/iflink", dev->ifname); + f = fopen(buf, "r"); + if (!f) + return NULL; + + len = fread(buf, 1, sizeof(buf) - 1, f); + fclose(f); + + if (len <= 0) + return NULL; + + buf[len] = 0; + iflink = strtoul(buf, NULL, 0); + ifindex = system_if_resolve(dev); + if (!iflink || iflink == ifindex) + return NULL; + + devname = if_indextoname(iflink, buf); + if (!devname) + return NULL; + + return device_get(devname, true); +} + +static bool +read_string_file(int dir_fd, const char *file, char *buf, int len) +{ + bool ret = false; + char *c; + int fd; + + fd = openat(dir_fd, file, O_RDONLY); + if (fd < 0) + return false; + +retry: + len = read(fd, buf, len - 1); + if (len < 0) { + if (errno == EINTR) + goto retry; + } else if (len > 0) { + buf[len] = 0; + + c = strchr(buf, '\n'); + if (c) + *c = 0; + + ret = true; + } + + close(fd); + + return ret; +} + +static bool +read_int_file(int dir_fd, const char *file, int *val) +{ + char buf[64]; + bool ret = false; + + ret = read_string_file(dir_fd, file, buf, sizeof(buf)); + if (ret) + *val = strtoul(buf, NULL, 0); + + return ret; +} + +/* Assume advertised flags == supported flags */ +static const struct { + uint32_t mask; + const char *name; +} ethtool_link_modes[] = { + { ADVERTISED_10baseT_Half, "10H" }, + { ADVERTISED_10baseT_Full, "10F" }, + { ADVERTISED_100baseT_Half, "100H" }, + { ADVERTISED_100baseT_Full, "100F" }, + { ADVERTISED_1000baseT_Half, "1000H" }, + { ADVERTISED_1000baseT_Full, "1000F" }, +}; + +static void system_add_link_modes(struct blob_buf *b, __u32 mask) +{ + int 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); + } +} + +int +system_if_dump_info(struct device *dev, struct blob_buf *b) +{ + struct ethtool_cmd ecmd; + struct ifreq ifr; + char buf[64], *s; + void *c; + int dir_fd, val = 0; + + snprintf(buf, sizeof(buf), "/sys/class/net/%s", dev->ifname); + dir_fd = open(buf, O_DIRECTORY); + + if (read_int_file(dir_fd, "carrier", &val)) + blobmsg_add_u8(b, "link", !!val); + if (read_string_file(dir_fd, "address", buf, sizeof(buf))) + blobmsg_add_string(b, "macaddr", buf); + + memset(&ecmd, 0, sizeof(ecmd)); + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, dev->ifname); + ifr.ifr_data = (caddr_t) &ecmd; + ecmd.cmd = ETHTOOL_GSET; + + if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) == 0) { + c = blobmsg_open_array(b, "link-advertising"); + system_add_link_modes(b, ecmd.advertising); + blobmsg_close_array(b, c); + + c = blobmsg_open_array(b, "link-supported"); + system_add_link_modes(b, ecmd.supported); + blobmsg_close_array(b, c); + + s = blobmsg_alloc_string_buffer(b, "speed", 8); + snprintf(s, 8, "%d%c", ethtool_cmd_speed(&ecmd), + ecmd.duplex == DUPLEX_HALF ? 'H' : 'F'); + blobmsg_add_string_buffer(b); + } + + close(dir_fd); return 0; } -int system_if_dump_stats(struct device *dev, struct blob_buf *b) +int +system_if_dump_stats(struct device *dev, struct blob_buf *b) { const char *const counters[] = { "collisions", "rx_frame_errors", "tx_compressed", @@ -621,30 +762,16 @@ int system_if_dump_stats(struct device *dev, struct blob_buf *b) }; char buf[64]; int stats_dir; - int i, fd, len; + int i, val = 0; snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics", dev->ifname); stats_dir = open(buf, O_DIRECTORY); if (stats_dir < 0) return -1; - for (i = 0; i < ARRAY_SIZE(counters); i++) { - fd = openat(stats_dir, counters[i], O_RDONLY); - if (fd < 0) - continue; - -retry: - len = read(fd, buf, sizeof(buf)); - if (len < 0) { - if (errno == EINTR) - goto retry; - continue; - } - - buf[len] = 0; - blobmsg_add_u32(b, counters[i], strtoul(buf, NULL, 0)); - close(fd); - } + for (i = 0; i < ARRAY_SIZE(counters); i++) + if (read_int_file(stats_dir, counters[i], &val)) + blobmsg_add_u32(b, counters[i], val); close(stats_dir); return 0;