summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-06-08 11:09:00 +0200
committerLennart Poettering <lennart@poettering.net>2021-06-08 18:24:11 +0200
commitc50404aeccdeddfa7a21e497d176f3c1b42f0952 (patch)
tree4a80807d931b9f01c292e301760756969e825348
parentcore/socket: do not assign another fd to SocketPort which already has a fd on... (diff)
downloadsystemd-c50404aeccdeddfa7a21e497d176f3c1b42f0952.tar.xz
systemd-c50404aeccdeddfa7a21e497d176f3c1b42f0952.zip
udev: make WakeOnLan= take multiple features
WAKE_XXX are flag, not enum.
-rw-r--r--man/systemd.link.xml15
-rw-r--r--src/network/test-network-tables.c1
-rw-r--r--src/shared/ethtool-util.c179
-rw-r--r--src/shared/ethtool-util.h18
-rw-r--r--src/udev/net/link-config.c10
-rw-r--r--src/udev/net/link-config.h2
6 files changed, 122 insertions, 103 deletions
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 4650b8f852..3323b028de 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -492,8 +492,9 @@
<varlistentry>
<term><varname>WakeOnLan=</varname></term>
<listitem>
- <para>The Wake-on-LAN policy to set for the device. The
- supported values are:</para>
+ <para>The Wake-on-LAN policy to set for the device. Takes the special value
+ <literal>off</literal> which disables Wake-on-LAN, or space separated list of the following
+ words:</para>
<variablelist>
<varlistentry>
@@ -540,15 +541,11 @@
</para>
</listitem>
</varlistentry>
- <varlistentry>
- <term><option>off</option></term>
- <listitem>
- <para>Never wake.</para>
- </listitem>
- </varlistentry>
</variablelist>
- <para>Defaults to <option>off</option>.</para>
+ <para>Defaults to unset, and the device's default will be used. This setting can be specified
+ multiple times. If an empty string is assigned, then the all previous assignments are
+ cleared.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index ce34449554..f55e524ae9 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -37,7 +37,6 @@ int main(int argc, char **argv) {
test_table(netdev_kind, NETDEV_KIND);
test_table(nl_union_link_info_data, NL_UNION_LINK_INFO_DATA);
test_table(radv_prefix_delegation, RADV_PREFIX_DELEGATION);
- test_table(wol, WOL);
test_table(lldp_event, SD_LLDP_EVENT);
test_table(ndisc_event, SD_NDISC_EVENT);
test_table(dhcp_lease_server_type, SD_DHCP_LEASE_SERVER_TYPE);
diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c
index 9506af8b8b..f77f6943ca 100644
--- a/src/shared/ethtool-util.c
+++ b/src/shared/ethtool-util.c
@@ -24,19 +24,38 @@ static const char* const duplex_table[_DUP_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
-static const char* const wol_table[_WOL_MAX] = {
- [WOL_PHY] = "phy",
- [WOL_UCAST] = "unicast",
- [WOL_MCAST] = "multicast",
- [WOL_BCAST] = "broadcast",
- [WOL_ARP] = "arp",
- [WOL_MAGIC] = "magic",
- [WOL_MAGICSECURE] = "secureon",
- [WOL_OFF] = "off",
+static const struct {
+ uint32_t opt;
+ const char *name;
+} wol_option_map[] = {
+ { WAKE_PHY, "phy" },
+ { WAKE_UCAST, "unicast", },
+ { WAKE_MCAST, "multicast", },
+ { WAKE_BCAST, "broadcast", },
+ { WAKE_ARP, "arp", },
+ { WAKE_MAGIC, "magic", },
+ { WAKE_MAGICSECURE, "secureon", },
};
-DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
+int wol_options_to_string_alloc(uint32_t opts, char **ret) {
+ _cleanup_free_ char *str = NULL;
+
+ assert(ret);
+
+ for (size_t i = 0; i < ELEMENTSOF(wol_option_map); i++)
+ if (opts & wol_option_map[i].opt &&
+ !strextend_with_separator(&str, ",", wol_option_map[i].name))
+ return -ENOMEM;
+
+ if (!str) {
+ str = strdup("off");
+ if (!str)
+ return -ENOMEM;
+ }
+
+ *ret = TAKE_PTR(str);
+ return 0;
+}
static const char* const port_table[] = {
[NET_DEV_PORT_TP] = "tp",
@@ -310,7 +329,7 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et
dest = _v; \
} while(false)
-int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) {
+int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts) {
struct ethtool_wolinfo ecmd = {
.cmd = ETHTOOL_GWOL,
};
@@ -323,7 +342,7 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) {
assert(ethtool_fd);
assert(ifname);
- if (wol == _WOL_INVALID)
+ if (wolopts == UINT32_MAX)
return 0;
r = ethtool_connect(ethtool_fd);
@@ -336,66 +355,15 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) {
if (r < 0)
return -errno;
- switch (wol) {
- case WOL_PHY:
- if (ecmd.wolopts != WAKE_PHY) {
- ecmd.wolopts = WAKE_PHY;
- need_update = true;
- }
- break;
- case WOL_UCAST:
- if (ecmd.wolopts != WAKE_UCAST) {
- ecmd.wolopts = WAKE_UCAST;
- need_update = true;
- }
- break;
- case WOL_MCAST:
- if (ecmd.wolopts != WAKE_MCAST) {
- ecmd.wolopts = WAKE_MCAST;
- need_update = true;
- }
- break;
- case WOL_BCAST:
- if (ecmd.wolopts != WAKE_BCAST) {
- ecmd.wolopts = WAKE_BCAST;
- need_update = true;
- }
- break;
- case WOL_ARP:
- if (ecmd.wolopts != WAKE_ARP) {
- ecmd.wolopts = WAKE_ARP;
- need_update = true;
- }
- break;
- case WOL_MAGIC:
- if (ecmd.wolopts != WAKE_MAGIC) {
- ecmd.wolopts = WAKE_MAGIC;
- need_update = true;
- }
- break;
- case WOL_MAGICSECURE:
- if (ecmd.wolopts != WAKE_MAGICSECURE) {
- ecmd.wolopts = WAKE_MAGICSECURE;
- need_update = true;
- }
- break;
- case WOL_OFF:
- if (ecmd.wolopts != 0) {
- ecmd.wolopts = 0;
- need_update = true;
- }
- break;
- default:
- break;
- }
+ UPDATE(ecmd.wolopts, wolopts, need_update);
- if (need_update) {
- ecmd.cmd = ETHTOOL_SWOL;
+ if (!need_update)
+ return 0;
- r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
- if (r < 0)
- return -errno;
- }
+ ecmd.cmd = ETHTOOL_SWOL;
+ r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
+ if (r < 0)
+ return -errno;
return 0;
}
@@ -1005,7 +973,6 @@ int config_parse_advertise(
void *userdata) {
uint32_t *advertise = data;
- const char *p;
int r;
assert(filename);
@@ -1020,7 +987,7 @@ int config_parse_advertise(
return 0;
}
- for (p = rvalue;;) {
+ for (const char *p = rvalue;;) {
_cleanup_free_ char *w = NULL;
enum ethtool_link_mode_bit_indices mode;
@@ -1098,3 +1065,69 @@ int config_parse_nic_buffer_size(
return 0;
}
+
+int config_parse_wol(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ uint32_t new_opts = 0, *opts = data;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ *opts = UINT32_MAX; /* Do not update WOL option. */
+ return 0;
+ }
+
+ if (streq(rvalue, "off")) {
+ *opts = 0; /* Disable WOL. */
+ return 0;
+ }
+
+ for (const char *p = rvalue;;) {
+ _cleanup_free_ char *w = NULL;
+ bool found = false;
+
+ r = extract_first_word(&p, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to split wake-on-lan modes '%s', ignoring assignment: %m", rvalue);
+ return 0;
+ }
+ if (r == 0)
+ break;
+
+ for (size_t i = 0; i < ELEMENTSOF(wol_option_map); i++)
+ if (streq(w, wol_option_map[i].name)) {
+ new_opts |= wol_option_map[i].opt;
+ found = true;
+ break;
+ }
+
+ if (!found)
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Unknown wake-on-lan mode '%s', ignoring.", w);
+ }
+
+ if (*opts == UINT32_MAX)
+ *opts = new_opts;
+ else
+ *opts |= new_opts;
+
+ return 0;
+}
diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h
index 3c031cda43..7d28766624 100644
--- a/src/shared/ethtool-util.h
+++ b/src/shared/ethtool-util.h
@@ -18,19 +18,6 @@ typedef enum Duplex {
_DUP_INVALID = -EINVAL,
} Duplex;
-typedef enum WakeOnLan {
- WOL_PHY,
- WOL_UCAST,
- WOL_MCAST,
- WOL_BCAST,
- WOL_ARP,
- WOL_MAGIC,
- WOL_MAGICSECURE,
- WOL_OFF,
- _WOL_MAX,
- _WOL_INVALID = -EINVAL,
-} WakeOnLan;
-
typedef enum NetDevFeature {
NET_DEV_FEAT_RX,
NET_DEV_FEAT_TX,
@@ -99,7 +86,7 @@ int ethtool_get_link_info(int *ethtool_fd, const char *ifname,
int *ret_autonegotiation, uint64_t *ret_speed,
Duplex *ret_duplex, NetDevPort *ret_port);
int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct ether_addr *ret);
-int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol);
+int ethtool_set_wol(int *ethtool_fd, const char *ifname, uint32_t wolopts);
int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring);
int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *features);
int ethtool_set_glinksettings(int *ethtool_fd, const char *ifname,
@@ -111,8 +98,7 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au
const char *duplex_to_string(Duplex d) _const_;
Duplex duplex_from_string(const char *d) _pure_;
-const char *wol_to_string(WakeOnLan wol) _const_;
-WakeOnLan wol_from_string(const char *wol) _pure_;
+int wol_options_to_string_alloc(uint32_t opts, char **ret);
const char *port_to_string(NetDevPort port) _const_;
NetDevPort port_from_string(const char *port) _pure_;
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index a9e263a095..8dfe23691b 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -134,7 +134,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
*link = (LinkConfig) {
.filename = TAKE_PTR(name),
.mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
- .wol = _WOL_INVALID,
+ .wol = UINT32_MAX, /* UINT32_MAX means do not change WOL setting. */
.duplex = _DUP_INVALID,
.port = _NET_DEV_PORT_INVALID,
.autonegotiation = -1,
@@ -329,9 +329,13 @@ static int link_config_apply_ethtool_settings(int *ethtool_fd, const LinkConfig
}
r = ethtool_set_wol(ethtool_fd, name, config->wol);
- if (r < 0)
+ if (r < 0) {
+ _cleanup_free_ char *str = NULL;
+
+ (void) wol_options_to_string_alloc(config->wol, &str);
log_device_warning_errno(device, r, "Could not set WakeOnLan to %s, ignoring: %m",
- wol_to_string(config->wol));
+ strna(str));
+ }
r = ethtool_set_features(ethtool_fd, name, config->features);
if (r < 0)
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 601f62af8f..b505c94f95 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -56,7 +56,7 @@ struct LinkConfig {
Duplex duplex;
int autonegotiation;
uint32_t advertise[N_ADVERTISE];
- WakeOnLan wol;
+ uint32_t wol;
NetDevPort port;
int features[_NET_DEV_FEAT_MAX];
netdev_channels channels;