+ 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;
+}
+
+int
+system_if_dump_info(struct device *dev, struct blob_buf *b)
+{
+ char buf[64];
+ 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);
+
+ close(dir_fd);
+ return 0;
+}
+
+int
+system_if_dump_stats(struct device *dev, struct blob_buf *b)
+{
+ const char *const counters[] = {
+ "collisions", "rx_frame_errors", "tx_compressed",
+ "multicast", "rx_length_errors", "tx_dropped",
+ "rx_bytes", "rx_missed_errors", "tx_errors",
+ "rx_compressed", "rx_over_errors", "tx_fifo_errors",
+ "rx_crc_errors", "rx_packets", "tx_heartbeat_errors",
+ "rx_dropped", "tx_aborted_errors", "tx_packets",
+ "rx_errors", "tx_bytes", "tx_window_errors",
+ "rx_fifo_errors", "tx_carrier_errors",
+ };
+ char buf[64];
+ int stats_dir;
+ 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++)
+ if (read_int_file(stats_dir, counters[i], &val))
+ blobmsg_add_u32(b, counters[i], val);
+
+ close(stats_dir);