0001
0002
0003 #include "netlink.h"
0004 #include "common.h"
0005 #include "bitset.h"
0006
0007 struct debug_req_info {
0008 struct ethnl_req_info base;
0009 };
0010
0011 struct debug_reply_data {
0012 struct ethnl_reply_data base;
0013 u32 msg_mask;
0014 };
0015
0016 #define DEBUG_REPDATA(__reply_base) \
0017 container_of(__reply_base, struct debug_reply_data, base)
0018
0019 const struct nla_policy ethnl_debug_get_policy[] = {
0020 [ETHTOOL_A_DEBUG_HEADER] =
0021 NLA_POLICY_NESTED(ethnl_header_policy),
0022 };
0023
0024 static int debug_prepare_data(const struct ethnl_req_info *req_base,
0025 struct ethnl_reply_data *reply_base,
0026 struct genl_info *info)
0027 {
0028 struct debug_reply_data *data = DEBUG_REPDATA(reply_base);
0029 struct net_device *dev = reply_base->dev;
0030 int ret;
0031
0032 if (!dev->ethtool_ops->get_msglevel)
0033 return -EOPNOTSUPP;
0034
0035 ret = ethnl_ops_begin(dev);
0036 if (ret < 0)
0037 return ret;
0038 data->msg_mask = dev->ethtool_ops->get_msglevel(dev);
0039 ethnl_ops_complete(dev);
0040
0041 return 0;
0042 }
0043
0044 static int debug_reply_size(const struct ethnl_req_info *req_base,
0045 const struct ethnl_reply_data *reply_base)
0046 {
0047 const struct debug_reply_data *data = DEBUG_REPDATA(reply_base);
0048 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
0049
0050 return ethnl_bitset32_size(&data->msg_mask, NULL, NETIF_MSG_CLASS_COUNT,
0051 netif_msg_class_names, compact);
0052 }
0053
0054 static int debug_fill_reply(struct sk_buff *skb,
0055 const struct ethnl_req_info *req_base,
0056 const struct ethnl_reply_data *reply_base)
0057 {
0058 const struct debug_reply_data *data = DEBUG_REPDATA(reply_base);
0059 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
0060
0061 return ethnl_put_bitset32(skb, ETHTOOL_A_DEBUG_MSGMASK, &data->msg_mask,
0062 NULL, NETIF_MSG_CLASS_COUNT,
0063 netif_msg_class_names, compact);
0064 }
0065
0066 const struct ethnl_request_ops ethnl_debug_request_ops = {
0067 .request_cmd = ETHTOOL_MSG_DEBUG_GET,
0068 .reply_cmd = ETHTOOL_MSG_DEBUG_GET_REPLY,
0069 .hdr_attr = ETHTOOL_A_DEBUG_HEADER,
0070 .req_info_size = sizeof(struct debug_req_info),
0071 .reply_data_size = sizeof(struct debug_reply_data),
0072
0073 .prepare_data = debug_prepare_data,
0074 .reply_size = debug_reply_size,
0075 .fill_reply = debug_fill_reply,
0076 };
0077
0078
0079
0080 const struct nla_policy ethnl_debug_set_policy[] = {
0081 [ETHTOOL_A_DEBUG_HEADER] =
0082 NLA_POLICY_NESTED(ethnl_header_policy),
0083 [ETHTOOL_A_DEBUG_MSGMASK] = { .type = NLA_NESTED },
0084 };
0085
0086 int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info)
0087 {
0088 struct ethnl_req_info req_info = {};
0089 struct nlattr **tb = info->attrs;
0090 struct net_device *dev;
0091 bool mod = false;
0092 u32 msg_mask;
0093 int ret;
0094
0095 ret = ethnl_parse_header_dev_get(&req_info,
0096 tb[ETHTOOL_A_DEBUG_HEADER],
0097 genl_info_net(info), info->extack,
0098 true);
0099 if (ret < 0)
0100 return ret;
0101 dev = req_info.dev;
0102 ret = -EOPNOTSUPP;
0103 if (!dev->ethtool_ops->get_msglevel || !dev->ethtool_ops->set_msglevel)
0104 goto out_dev;
0105
0106 rtnl_lock();
0107 ret = ethnl_ops_begin(dev);
0108 if (ret < 0)
0109 goto out_rtnl;
0110
0111 msg_mask = dev->ethtool_ops->get_msglevel(dev);
0112 ret = ethnl_update_bitset32(&msg_mask, NETIF_MSG_CLASS_COUNT,
0113 tb[ETHTOOL_A_DEBUG_MSGMASK],
0114 netif_msg_class_names, info->extack, &mod);
0115 if (ret < 0 || !mod)
0116 goto out_ops;
0117
0118 dev->ethtool_ops->set_msglevel(dev, msg_mask);
0119 ethtool_notify(dev, ETHTOOL_MSG_DEBUG_NTF, NULL);
0120
0121 out_ops:
0122 ethnl_ops_complete(dev);
0123 out_rtnl:
0124 rtnl_unlock();
0125 out_dev:
0126 ethnl_parse_header_dev_put(&req_info);
0127 return ret;
0128 }