Implement WOL_SET netlink request to set wake-on-lan settings. This is equivalent to ETHTOOL_SWOL ioctl request.
Unified · Split
| @@ -188,6 +188,7 @@ Userspace to kernel: · 187 unmodified lines | ||
| 188 | 188 | ``ETHTOOL_MSG_DEBUG_GET`` get debugging settings |
| 189 | 189 | ``ETHTOOL_MSG_DEBUG_SET`` set debugging settings |
| 190 | 190 | ``ETHTOOL_MSG_WOL_GET`` get wake-on-lan settings |
| 191 | + ``ETHTOOL_MSG_WOL_SET`` set wake-on-lan settings | |
| 191 | 192 | ===================================== ================================ |
| 192 | 193 | |
| 193 | 194 | Kernel to userspace: |
| @@ -502,6 +503,23 @@ device, value of modes which are enabled. ``ETHTOOL_A_WOL_SOPASS`` is only · 308 unmodified lines | ||
| 502 | 503 | included in reply if ``WAKE_MAGICSECURE`` mode is supported. |
| 503 | 504 | |
| 504 | 505 | |
| 506 | +WOL_SET | |
| 507 | +======= | |
| 508 | + | |
| 509 | +Set or update wake-on-lan settings. | |
| 510 | + | |
| 511 | +Request contents: | |
| 512 | + | |
| 513 | + ==================================== ====== ========================== | |
| 514 | + ``ETHTOOL_A_WOL_HEADER`` nested request header | |
| 515 | + ``ETHTOOL_A_WOL_MODES`` bitset enabled WoL modes | |
| 516 | + ``ETHTOOL_A_WOL_SOPASS`` binary SecureOn(tm) password | |
| 517 | + ==================================== ====== ========================== | |
| 518 | + | |
| 519 | +``ETHTOOL_A_WOL_SOPASS`` is only allowed for devices supporting | |
| 520 | +``WAKE_MAGICSECURE`` mode. | |
| 521 | + | |
| 522 | + | |
| 505 | 523 | Request translation |
| 506 | 524 | =================== |
| 507 | 525 | |
| @@ -519,7 +537,7 @@ have their netlink replacement yet. · 11 unmodified lines | ||
| 519 | 537 | ``ETHTOOL_GDRVINFO`` n/a |
| 520 | 538 | ``ETHTOOL_GREGS`` n/a |
| 521 | 539 | ``ETHTOOL_GWOL`` ``ETHTOOL_MSG_WOL_GET`` |
| 522 | − ``ETHTOOL_SWOL`` n/a | |
| 540 | + ``ETHTOOL_SWOL`` ``ETHTOOL_MSG_WOL_SET`` | |
| 523 | 541 | ``ETHTOOL_GMSGLVL`` ``ETHTOOL_MSG_DEBUG_GET`` |
| 524 | 542 | ``ETHTOOL_SMSGLVL`` ``ETHTOOL_MSG_DEBUG_SET`` |
| 525 | 543 | ``ETHTOOL_NWAY_RST`` n/a |
| @@ -23,6 +23,7 @@ enum { · 22 unmodified lines | ||
| 23 | 23 | ETHTOOL_MSG_DEBUG_GET, |
| 24 | 24 | ETHTOOL_MSG_DEBUG_SET, |
| 25 | 25 | ETHTOOL_MSG_WOL_GET, |
| 26 | + ETHTOOL_MSG_WOL_SET, | |
| 26 | 27 | |
| 27 | 28 | /* add new constants above here */ |
| 28 | 29 | __ETHTOOL_MSG_USER_CNT, |
| @@ -688,6 +688,11 @@ static const struct genl_ops ethtool_genl_ops[] = { · 687 unmodified lines | ||
| 688 | 688 | .dumpit = ethnl_default_dumpit, |
| 689 | 689 | .done = ethnl_default_done, |
| 690 | 690 | }, |
| 691 | + { | |
| 692 | + .cmd = ETHTOOL_MSG_WOL_SET, | |
| 693 | + .flags = GENL_UNS_ADMIN_PERM, | |
| 694 | + .doit = ethnl_set_wol, | |
| 695 | + }, | |
| 691 | 696 | }; |
| 692 | 697 | |
| 693 | 698 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { |
| @@ -340,5 +340,6 @@ extern const struct ethnl_request_ops ethnl_wol_request_ops; · 339 unmodified lines | ||
| 340 | 340 | int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); |
| 341 | 341 | int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); |
| 342 | 342 | int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info); |
| 343 | +int ethnl_set_wol(struct sk_buff *skb, struct genl_info *info); | |
| 343 | 344 | |
| 344 | 345 | #endif /* _NET_ETHTOOL_NETLINK_H */ |
| @@ -97,3 +97,79 @@ const struct ethnl_request_ops ethnl_wol_request_ops = { · 96 unmodified lines | ||
| 97 | 97 | .reply_size = wol_reply_size, |
| 98 | 98 | .fill_reply = wol_fill_reply, |
| 99 | 99 | }; |
| 100 | + | |
| 101 | +/* WOL_SET */ | |
| 102 | + | |
| 103 | +static const struct nla_policy | |
| 104 | +wol_set_policy[ETHTOOL_A_WOL_MAX + 1] = { | |
| 105 | + [ETHTOOL_A_WOL_UNSPEC] = { .type = NLA_REJECT }, | |
| 106 | + [ETHTOOL_A_WOL_HEADER] = { .type = NLA_NESTED }, | |
| 107 | + [ETHTOOL_A_WOL_MODES] = { .type = NLA_NESTED }, | |
| 108 | + [ETHTOOL_A_WOL_SOPASS] = { .type = NLA_BINARY, | |
| 109 | + .len = SOPASS_MAX }, | |
| 110 | +}; | |
| 111 | + | |
| 112 | +int ethnl_set_wol(struct sk_buff *skb, struct genl_info *info) | |
| 113 | +{ | |
| 114 | + struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; | |
| 115 | + struct nlattr *tb[ETHTOOL_A_WOL_MAX + 1]; | |
| 116 | + struct ethnl_req_info req_info = {}; | |
| 117 | + struct net_device *dev; | |
| 118 | + bool mod = false; | |
| 119 | + int ret; | |
| 120 | + | |
| 121 | + ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_WOL_MAX, | |
| 122 | + wol_set_policy, info->extack); | |
| 123 | + if (ret < 0) | |
| 124 | + return ret; | |
| 125 | + ret = ethnl_parse_header(&req_info, tb[ETHTOOL_A_WOL_HEADER], | |
| 126 | + genl_info_net(info), info->extack, true); | |
| 127 | + if (ret < 0) | |
| 128 | + return ret; | |
| 129 | + dev = req_info.dev; | |
| 130 | + if (!dev->ethtool_ops->get_wol || !dev->ethtool_ops->set_wol) | |
| 131 | + return -EOPNOTSUPP; | |
| 132 | + | |
| 133 | + rtnl_lock(); | |
| 134 | + ret = ethnl_ops_begin(dev); | |
| 135 | + if (ret < 0) | |
| 136 | + goto out_rtnl; | |
| 137 | + | |
| 138 | + dev->ethtool_ops->get_wol(dev, &wol); | |
| 139 | + ret = ethnl_update_bitset32(&wol.wolopts, WOL_MODE_COUNT, | |
| 140 | + tb[ETHTOOL_A_WOL_MODES], wol_mode_names, | |
| 141 | + info->extack, &mod); | |
| 142 | + if (ret < 0) | |
| 143 | + goto out_ops; | |
| 144 | + if (wol.wolopts & ~wol.supported) { | |
| 145 | + NL_SET_ERR_MSG_ATTR(info->extack, tb[ETHTOOL_A_WOL_MODES], | |
| 146 | + "cannot enable unsupported WoL mode"); | |
| 147 | + ret = -EINVAL; | |
| 148 | + goto out_ops; | |
| 149 | + } | |
| 150 | + if (tb[ETHTOOL_A_WOL_SOPASS]) { | |
| 151 | + if (!(wol.supported & WAKE_MAGICSECURE)) { | |
| 152 | + NL_SET_ERR_MSG_ATTR(info->extack, | |
| 153 | + tb[ETHTOOL_A_WOL_SOPASS], | |
| 154 | + "magicsecure not supported, cannot set password"); | |
| 155 | + ret = -EINVAL; | |
| 156 | + goto out_ops; | |
| 157 | + } | |
| 158 | + ethnl_update_binary(wol.sopass, sizeof(wol.sopass), | |
| 159 | + tb[ETHTOOL_A_WOL_SOPASS], &mod); | |
| 160 | + } | |
| 161 | + | |
| 162 | + if (!mod) | |
| 163 | + goto out_ops; | |
| 164 | + ret = dev->ethtool_ops->set_wol(dev, &wol); | |
| 165 | + if (ret) | |
| 166 | + goto out_ops; | |
| 167 | + dev->wol_enabled = !!wol.wolopts; | |
| 168 | + | |
| 169 | +out_ops: | |
| 170 | + ethnl_ops_complete(dev); | |
| 171 | +out_rtnl: | |
| 172 | + rtnl_unlock(); | |
| 173 | + dev_put(dev); | |
| 174 | + return ret; | |
| 175 | +} | |