18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include "netlink.h" 48c2ecf20Sopenharmony_ci#include "common.h" 58c2ecf20Sopenharmony_ci#include "bitset.h" 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_cistruct debug_req_info { 88c2ecf20Sopenharmony_ci struct ethnl_req_info base; 98c2ecf20Sopenharmony_ci}; 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistruct debug_reply_data { 128c2ecf20Sopenharmony_ci struct ethnl_reply_data base; 138c2ecf20Sopenharmony_ci u32 msg_mask; 148c2ecf20Sopenharmony_ci}; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define DEBUG_REPDATA(__reply_base) \ 178c2ecf20Sopenharmony_ci container_of(__reply_base, struct debug_reply_data, base) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciconst struct nla_policy ethnl_debug_get_policy[] = { 208c2ecf20Sopenharmony_ci [ETHTOOL_A_DEBUG_HEADER] = 218c2ecf20Sopenharmony_ci NLA_POLICY_NESTED(ethnl_header_policy), 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int debug_prepare_data(const struct ethnl_req_info *req_base, 258c2ecf20Sopenharmony_ci struct ethnl_reply_data *reply_base, 268c2ecf20Sopenharmony_ci struct genl_info *info) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct debug_reply_data *data = DEBUG_REPDATA(reply_base); 298c2ecf20Sopenharmony_ci struct net_device *dev = reply_base->dev; 308c2ecf20Sopenharmony_ci int ret; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (!dev->ethtool_ops->get_msglevel) 338c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci ret = ethnl_ops_begin(dev); 368c2ecf20Sopenharmony_ci if (ret < 0) 378c2ecf20Sopenharmony_ci return ret; 388c2ecf20Sopenharmony_ci data->msg_mask = dev->ethtool_ops->get_msglevel(dev); 398c2ecf20Sopenharmony_ci ethnl_ops_complete(dev); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int debug_reply_size(const struct ethnl_req_info *req_base, 458c2ecf20Sopenharmony_ci const struct ethnl_reply_data *reply_base) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci const struct debug_reply_data *data = DEBUG_REPDATA(reply_base); 488c2ecf20Sopenharmony_ci bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return ethnl_bitset32_size(&data->msg_mask, NULL, NETIF_MSG_CLASS_COUNT, 518c2ecf20Sopenharmony_ci netif_msg_class_names, compact); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int debug_fill_reply(struct sk_buff *skb, 558c2ecf20Sopenharmony_ci const struct ethnl_req_info *req_base, 568c2ecf20Sopenharmony_ci const struct ethnl_reply_data *reply_base) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci const struct debug_reply_data *data = DEBUG_REPDATA(reply_base); 598c2ecf20Sopenharmony_ci bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return ethnl_put_bitset32(skb, ETHTOOL_A_DEBUG_MSGMASK, &data->msg_mask, 628c2ecf20Sopenharmony_ci NULL, NETIF_MSG_CLASS_COUNT, 638c2ecf20Sopenharmony_ci netif_msg_class_names, compact); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciconst struct ethnl_request_ops ethnl_debug_request_ops = { 678c2ecf20Sopenharmony_ci .request_cmd = ETHTOOL_MSG_DEBUG_GET, 688c2ecf20Sopenharmony_ci .reply_cmd = ETHTOOL_MSG_DEBUG_GET_REPLY, 698c2ecf20Sopenharmony_ci .hdr_attr = ETHTOOL_A_DEBUG_HEADER, 708c2ecf20Sopenharmony_ci .req_info_size = sizeof(struct debug_req_info), 718c2ecf20Sopenharmony_ci .reply_data_size = sizeof(struct debug_reply_data), 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci .prepare_data = debug_prepare_data, 748c2ecf20Sopenharmony_ci .reply_size = debug_reply_size, 758c2ecf20Sopenharmony_ci .fill_reply = debug_fill_reply, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* DEBUG_SET */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciconst struct nla_policy ethnl_debug_set_policy[] = { 818c2ecf20Sopenharmony_ci [ETHTOOL_A_DEBUG_HEADER] = 828c2ecf20Sopenharmony_ci NLA_POLICY_NESTED(ethnl_header_policy), 838c2ecf20Sopenharmony_ci [ETHTOOL_A_DEBUG_MSGMASK] = { .type = NLA_NESTED }, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciint ethnl_set_debug(struct sk_buff *skb, struct genl_info *info) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct ethnl_req_info req_info = {}; 898c2ecf20Sopenharmony_ci struct nlattr **tb = info->attrs; 908c2ecf20Sopenharmony_ci struct net_device *dev; 918c2ecf20Sopenharmony_ci bool mod = false; 928c2ecf20Sopenharmony_ci u32 msg_mask; 938c2ecf20Sopenharmony_ci int ret; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci ret = ethnl_parse_header_dev_get(&req_info, 968c2ecf20Sopenharmony_ci tb[ETHTOOL_A_DEBUG_HEADER], 978c2ecf20Sopenharmony_ci genl_info_net(info), info->extack, 988c2ecf20Sopenharmony_ci true); 998c2ecf20Sopenharmony_ci if (ret < 0) 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci dev = req_info.dev; 1028c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 1038c2ecf20Sopenharmony_ci if (!dev->ethtool_ops->get_msglevel || !dev->ethtool_ops->set_msglevel) 1048c2ecf20Sopenharmony_ci goto out_dev; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci rtnl_lock(); 1078c2ecf20Sopenharmony_ci ret = ethnl_ops_begin(dev); 1088c2ecf20Sopenharmony_ci if (ret < 0) 1098c2ecf20Sopenharmony_ci goto out_rtnl; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci msg_mask = dev->ethtool_ops->get_msglevel(dev); 1128c2ecf20Sopenharmony_ci ret = ethnl_update_bitset32(&msg_mask, NETIF_MSG_CLASS_COUNT, 1138c2ecf20Sopenharmony_ci tb[ETHTOOL_A_DEBUG_MSGMASK], 1148c2ecf20Sopenharmony_ci netif_msg_class_names, info->extack, &mod); 1158c2ecf20Sopenharmony_ci if (ret < 0 || !mod) 1168c2ecf20Sopenharmony_ci goto out_ops; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci dev->ethtool_ops->set_msglevel(dev, msg_mask); 1198c2ecf20Sopenharmony_ci ethtool_notify(dev, ETHTOOL_MSG_DEBUG_NTF, NULL); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciout_ops: 1228c2ecf20Sopenharmony_ci ethnl_ops_complete(dev); 1238c2ecf20Sopenharmony_ciout_rtnl: 1248c2ecf20Sopenharmony_ci rtnl_unlock(); 1258c2ecf20Sopenharmony_ciout_dev: 1268c2ecf20Sopenharmony_ci dev_put(dev); 1278c2ecf20Sopenharmony_ci return ret; 1288c2ecf20Sopenharmony_ci} 129