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 | ``ETHTOOL_MSG_DEBUG_GET`` get debugging settings | 188 | ``ETHTOOL_MSG_DEBUG_GET`` get debugging settings |
| 189 | ``ETHTOOL_MSG_DEBUG_SET`` set debugging settings | 189 | ``ETHTOOL_MSG_DEBUG_SET`` set debugging settings |
| 190 | ``ETHTOOL_MSG_WOL_GET`` get wake-on-lan settings | 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 | Kernel to userspace: | 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 | included in reply if ``WAKE_MAGICSECURE`` mode is supported. | 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 | Request translation | 523 | Request translation |
| 506 | =================== | 524 | =================== |
| 507 | 525 | ||
| @@ -519,7 +537,7 @@ have their netlink replacement yet. · 11 unmodified lines | |||
| 519 | ``ETHTOOL_GDRVINFO`` n/a | 537 | ``ETHTOOL_GDRVINFO`` n/a |
| 520 | ``ETHTOOL_GREGS`` n/a | 538 | ``ETHTOOL_GREGS`` n/a |
| 521 | ``ETHTOOL_GWOL`` ``ETHTOOL_MSG_WOL_GET`` | 539 | ``ETHTOOL_GWOL`` ``ETHTOOL_MSG_WOL_GET`` |
| 522 | ``ETHTOOL_SWOL`` n/a | 540 | ``ETHTOOL_SWOL`` ``ETHTOOL_MSG_WOL_SET`` |
| 523 | ``ETHTOOL_GMSGLVL`` ``ETHTOOL_MSG_DEBUG_GET`` | 541 | ``ETHTOOL_GMSGLVL`` ``ETHTOOL_MSG_DEBUG_GET`` |
| 524 | ``ETHTOOL_SMSGLVL`` ``ETHTOOL_MSG_DEBUG_SET`` | 542 | ``ETHTOOL_SMSGLVL`` ``ETHTOOL_MSG_DEBUG_SET`` |
| 525 | ``ETHTOOL_NWAY_RST`` n/a | 543 | ``ETHTOOL_NWAY_RST`` n/a |
| @@ -23,6 +23,7 @@ enum { · 22 unmodified lines | |||
| 23 | ETHTOOL_MSG_DEBUG_GET, | 23 | ETHTOOL_MSG_DEBUG_GET, |
| 24 | ETHTOOL_MSG_DEBUG_SET, | 24 | ETHTOOL_MSG_DEBUG_SET, |
| 25 | ETHTOOL_MSG_WOL_GET, | 25 | ETHTOOL_MSG_WOL_GET, |
| 26 | ETHTOOL_MSG_WOL_SET, | ||
| 26 | 27 | ||
| 27 | /* add new constants above here */ | 28 | /* add new constants above here */ |
| 28 | __ETHTOOL_MSG_USER_CNT, | 29 | __ETHTOOL_MSG_USER_CNT, |
| @@ -688,6 +688,11 @@ static const struct genl_ops ethtool_genl_ops[] = { · 687 unmodified lines | |||
| 688 | .dumpit = ethnl_default_dumpit, | 688 | .dumpit = ethnl_default_dumpit, |
| 689 | .done = ethnl_default_done, | 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 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { | 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 | int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); | 340 | int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); |
| 341 | int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); | 341 | int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); |
| 342 | int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info); | 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 | #endif /* _NET_ETHTOOL_NETLINK_H */ | 345 | #endif /* _NET_ETHTOOL_NETLINK_H */ |
| @@ -97,3 +97,79 @@ const struct ethnl_request_ops ethnl_wol_request_ops = { · 96 unmodified lines | |||
| 97 | .reply_size = wol_reply_size, | 97 | .reply_size = wol_reply_size, |
| 98 | .fill_reply = wol_fill_reply, | 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 | } | ||