diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-06-08 11:09:00 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-06-08 18:24:11 +0200 |
commit | c50404aeccdeddfa7a21e497d176f3c1b42f0952 (patch) | |
tree | 4a80807d931b9f01c292e301760756969e825348 | |
parent | core/socket: do not assign another fd to SocketPort which already has a fd on... (diff) | |
download | systemd-c50404aeccdeddfa7a21e497d176f3c1b42f0952.tar.xz systemd-c50404aeccdeddfa7a21e497d176f3c1b42f0952.zip |
udev: make WakeOnLan= take multiple features
WAKE_XXX are flag, not enum.
-rw-r--r-- | man/systemd.link.xml | 15 | ||||
-rw-r--r-- | src/network/test-network-tables.c | 1 | ||||
-rw-r--r-- | src/shared/ethtool-util.c | 179 | ||||
-rw-r--r-- | src/shared/ethtool-util.h | 18 | ||||
-rw-r--r-- | src/udev/net/link-config.c | 10 | ||||
-rw-r--r-- | src/udev/net/link-config.h | 2 |
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; |