From 1cddbe64cfc66b58988c85086d6df3a77c0c61a5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 16 Jul 2012 22:56:05 +0100 Subject: Fix reporting of VLAN tag offload flags on Linux < 2.6.37 These kernel versions implement ETHTOOL_GFLAGS but do not include the flags for VLAN tag offload (and do not implement ETHTOOL_GFEATURES). Since the VLAN tag offload features were already defined and implemented by many drivers, we shouldn't assume they are off. Instead, since these feature flag values were stable, read them from sysfs. Signed-off-by: Ben Hutchings --- ethtool.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/ethtool.c b/ethtool.c index b424756..9991ce2 100644 --- a/ethtool.c +++ b/ethtool.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -1417,6 +1419,31 @@ static struct feature_defs *get_feature_defs(struct cmd_context *ctx) return defs; } +static int get_netdev_attr(struct cmd_context *ctx, const char *name, + char *buf, size_t buf_len) +{ +#ifdef TEST_ETHTOOL + errno = ENOENT; + return -1; +#else + char path[40 + IFNAMSIZ]; + ssize_t len; + int fd; + + len = snprintf(path, sizeof(path), "/sys/class/net/%s/%s", + ctx->devname, name); + assert(len < sizeof(path)); + fd = open(path, O_RDONLY); + if (fd < 0) + return fd; + len = read(fd, buf, buf_len - 1); + if (len >= 0) + buf[len] = 0; + close(fd); + return len; +#endif +} + static int do_gdrv(struct cmd_context *ctx) { int err; @@ -1858,6 +1885,20 @@ get_features(struct cmd_context *ctx, const struct feature_defs *defs) perror("Cannot get device generic features"); else allfail = 0; + } else { + /* We should have got VLAN tag offload flags through + * ETHTOOL_GFLAGS. However, prior to Linux 2.6.37 + * they were not exposed in this way - and since VLAN + * tag offload was defined and implemented by many + * drivers, we shouldn't assume they are off. + * Instead, since these feature flag values were + * stable, read them from sysfs. + */ + char buf[20]; + if (get_netdev_attr(ctx, "features", buf, sizeof(buf)) > 0) + state->off_flags |= + strtoul(buf, NULL, 0) & + (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN); } if (allfail) { -- cgit v1.2.1