[DEV_ATTR_DROP_UNSOLICITED_NA] = { .name = "drop_unsolicited_na", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_ARP_ACCEPT] = { .name = "arp_accept", .type = BLOBMSG_TYPE_BOOL },
[DEV_ATTR_AUTH] = { .name = "auth", .type = BLOBMSG_TYPE_BOOL },
+ [DEV_ATTR_SPEED] = { .name = "speed", .type = BLOBMSG_TYPE_INT32 },
+ [DEV_ATTR_DUPLEX] = { .name = "duplex", .type = BLOBMSG_TYPE_BOOL },
};
const struct uci_blob_param_list device_attr_list = {
n->arp_accept = s->flags & DEV_OPT_ARP_ACCEPT ?
s->arp_accept : os->arp_accept;
n->auth = s->flags & DEV_OPT_AUTH ? s->auth : os->auth;
+ n->speed = s->flags & DEV_OPT_SPEED ? s->speed : os->speed;
+ n->duplex = s->flags & DEV_OPT_DUPLEX ? s->duplex : os->duplex;
n->flags = s->flags | os->flags | os->valid_flags;
}
s->flags |= DEV_OPT_AUTH;
}
+ if ((cur = tb[DEV_ATTR_SPEED])) {
+ s->speed = blobmsg_get_u32(cur);
+ s->flags |= DEV_OPT_SPEED;
+ }
+
+ if ((cur = tb[DEV_ATTR_DUPLEX])) {
+ s->duplex = blobmsg_get_bool(cur);
+ s->flags |= DEV_OPT_DUPLEX;
+ }
+
device_set_disabled(dev, disabled);
}
DEV_ATTR_DROP_UNSOLICITED_NA,
DEV_ATTR_ARP_ACCEPT,
DEV_ATTR_AUTH,
+ DEV_ATTR_SPEED,
+ DEV_ATTR_DUPLEX,
__DEV_ATTR_MAX,
};
DEV_OPT_DROP_GRATUITOUS_ARP = (1ULL << 27),
DEV_OPT_DROP_UNSOLICITED_NA = (1ULL << 28),
DEV_OPT_ARP_ACCEPT = (1ULL << 29),
+ DEV_OPT_SPEED = (1ULL << 30),
+ DEV_OPT_DUPLEX = (1ULL << 31),
};
/* events broadcasted to all users of a device */
bool drop_unsolicited_na;
bool arp_accept;
bool auth;
+ unsigned int speed;
+ bool duplex;
};
/*
return system_link_del(vlandev->ifname);
}
+static void
+system_set_ethtool_settings(struct device *dev, struct device_settings *s)
+{
+ struct ethtool_cmd ecmd = {
+ .cmd = ETHTOOL_GSET,
+ };
+ struct ifreq ifr = {
+ .ifr_data = (caddr_t)&ecmd,
+ };
+ static const struct {
+ int speed;
+ uint8_t bit_half;
+ uint8_t bit_full;
+ } speed_mask[] = {
+ { 10, ETHTOOL_LINK_MODE_10baseT_Half_BIT, ETHTOOL_LINK_MODE_10baseT_Full_BIT },
+ { 100, ETHTOOL_LINK_MODE_100baseT_Half_BIT, ETHTOOL_LINK_MODE_100baseT_Full_BIT },
+ { 1000, ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT },
+ };
+ uint32_t adv;
+ int i;
+
+ strncpy(ifr.ifr_name, dev->ifname, sizeof(ifr.ifr_name) - 1);
+
+ if (ioctl(sock_ioctl, SIOCETHTOOL, &ifr) != 0)
+ return;
+
+ adv = ecmd.supported;
+ for (i = 0; i < ARRAY_SIZE(speed_mask); i++) {
+ if (s->flags & DEV_OPT_DUPLEX) {
+ int bit = s->duplex ? speed_mask[i].bit_half : speed_mask[i].bit_full;
+ adv &= ~(1 << bit);
+ }
+
+ if (!(s->flags & DEV_OPT_SPEED) ||
+ s->speed == speed_mask[i].speed)
+ continue;
+
+ adv &= ~(1 << speed_mask[i].bit_full);
+ adv &= ~(1 << speed_mask[i].bit_half);
+ }
+
+
+ if (ecmd.autoneg && ecmd.advertising == adv)
+ return;
+
+ ecmd.autoneg = 1;
+ ecmd.advertising = adv;
+ ecmd.cmd = ETHTOOL_SSET;
+ ioctl(sock_ioctl, SIOCETHTOOL, &ifr);
+}
+
void
system_if_get_settings(struct device *dev, struct device_settings *s)
{
system_set_drop_unsolicited_na(dev, s->drop_unsolicited_na ? "1" : "0");
if (apply_mask & DEV_OPT_ARP_ACCEPT)
system_set_arp_accept(dev, s->arp_accept ? "1" : "0");
+ system_set_ethtool_settings(dev, s);
}
int system_if_up(struct device *dev)