arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / net / devlink / netlink.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5  */
6
7 #include <net/genetlink.h>
8 #include <net/sock.h>
9
10 #include "devl_internal.h"
11
12 static const struct genl_multicast_group devlink_nl_mcgrps[] = {
13         [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
14 };
15
16 int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
17                                  struct devlink *devlink, int attrtype)
18 {
19         struct nlattr *nested_attr;
20         struct net *devl_net;
21
22         nested_attr = nla_nest_start(msg, attrtype);
23         if (!nested_attr)
24                 return -EMSGSIZE;
25         if (devlink_nl_put_handle(msg, devlink))
26                 goto nla_put_failure;
27
28         rcu_read_lock();
29         devl_net = read_pnet_rcu(&devlink->_net);
30         if (!net_eq(net, devl_net)) {
31                 int id = peernet2id_alloc(net, devl_net, GFP_ATOMIC);
32
33                 rcu_read_unlock();
34                 if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
35                         return -EMSGSIZE;
36         } else {
37                 rcu_read_unlock();
38         }
39
40         nla_nest_end(msg, nested_attr);
41         return 0;
42
43 nla_put_failure:
44         nla_nest_cancel(msg, nested_attr);
45         return -EMSGSIZE;
46 }
47
48 int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info)
49 {
50         int err;
51
52         if (*msg) {
53                 err = genlmsg_reply(*msg, info);
54                 if (err)
55                         return err;
56         }
57         *msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
58         if (!*msg)
59                 return -ENOMEM;
60         return 0;
61 }
62
63 struct devlink *
64 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
65 {
66         struct devlink *devlink;
67         unsigned long index;
68         char *busname;
69         char *devname;
70
71         if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
72                 return ERR_PTR(-EINVAL);
73
74         busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
75         devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
76
77         devlinks_xa_for_each_registered_get(net, index, devlink) {
78                 devl_lock(devlink);
79                 if (devl_is_registered(devlink) &&
80                     strcmp(devlink->dev->bus->name, busname) == 0 &&
81                     strcmp(dev_name(devlink->dev), devname) == 0)
82                         return devlink;
83                 devl_unlock(devlink);
84                 devlink_put(devlink);
85         }
86
87         return ERR_PTR(-ENODEV);
88 }
89
90 static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
91                                  u8 flags)
92 {
93         struct devlink_port *devlink_port;
94         struct devlink *devlink;
95         int err;
96
97         devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs);
98         if (IS_ERR(devlink))
99                 return PTR_ERR(devlink);
100
101         info->user_ptr[0] = devlink;
102         if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
103                 devlink_port = devlink_port_get_from_info(devlink, info);
104                 if (IS_ERR(devlink_port)) {
105                         err = PTR_ERR(devlink_port);
106                         goto unlock;
107                 }
108                 info->user_ptr[1] = devlink_port;
109         } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
110                 devlink_port = devlink_port_get_from_info(devlink, info);
111                 if (!IS_ERR(devlink_port))
112                         info->user_ptr[1] = devlink_port;
113         }
114         return 0;
115
116 unlock:
117         devl_unlock(devlink);
118         devlink_put(devlink);
119         return err;
120 }
121
122 int devlink_nl_pre_doit(const struct genl_split_ops *ops,
123                         struct sk_buff *skb, struct genl_info *info)
124 {
125         return __devlink_nl_pre_doit(skb, info, 0);
126 }
127
128 int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
129                              struct sk_buff *skb, struct genl_info *info)
130 {
131         return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT);
132 }
133
134 int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
135                                       struct sk_buff *skb,
136                                       struct genl_info *info)
137 {
138         return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT);
139 }
140
141 void devlink_nl_post_doit(const struct genl_split_ops *ops,
142                           struct sk_buff *skb, struct genl_info *info)
143 {
144         struct devlink *devlink;
145
146         devlink = info->user_ptr[0];
147         devl_unlock(devlink);
148         devlink_put(devlink);
149 }
150
151 static int devlink_nl_inst_single_dumpit(struct sk_buff *msg,
152                                          struct netlink_callback *cb, int flags,
153                                          devlink_nl_dump_one_func_t *dump_one,
154                                          struct nlattr **attrs)
155 {
156         struct devlink *devlink;
157         int err;
158
159         devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs);
160         if (IS_ERR(devlink))
161                 return PTR_ERR(devlink);
162         err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED);
163
164         devl_unlock(devlink);
165         devlink_put(devlink);
166
167         if (err != -EMSGSIZE)
168                 return err;
169         return msg->len;
170 }
171
172 static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg,
173                                        struct netlink_callback *cb, int flags,
174                                        devlink_nl_dump_one_func_t *dump_one)
175 {
176         struct devlink_nl_dump_state *state = devlink_dump_state(cb);
177         struct devlink *devlink;
178         int err = 0;
179
180         while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
181                                                &state->instance))) {
182                 devl_lock(devlink);
183
184                 if (devl_is_registered(devlink))
185                         err = dump_one(msg, devlink, cb, flags);
186                 else
187                         err = 0;
188
189                 devl_unlock(devlink);
190                 devlink_put(devlink);
191
192                 if (err)
193                         break;
194
195                 state->instance++;
196
197                 /* restart sub-object walk for the next instance */
198                 state->idx = 0;
199         }
200
201         if (err != -EMSGSIZE)
202                 return err;
203         return msg->len;
204 }
205
206 int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
207                       devlink_nl_dump_one_func_t *dump_one)
208 {
209         const struct genl_info *info = genl_info_dump(cb);
210         struct nlattr **attrs = info->attrs;
211         int flags = NLM_F_MULTI;
212
213         if (attrs &&
214             (attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME]))
215                 return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one,
216                                                      attrs);
217         else
218                 return devlink_nl_inst_iter_dumpit(msg, cb, flags, dump_one);
219 }
220
221 struct genl_family devlink_nl_family __ro_after_init = {
222         .name           = DEVLINK_GENL_NAME,
223         .version        = DEVLINK_GENL_VERSION,
224         .netnsok        = true,
225         .parallel_ops   = true,
226         .module         = THIS_MODULE,
227         .split_ops      = devlink_nl_ops,
228         .n_split_ops    = ARRAY_SIZE(devlink_nl_ops),
229         .resv_start_op  = DEVLINK_CMD_SELFTESTS_RUN + 1,
230         .mcgrps         = devlink_nl_mcgrps,
231         .n_mcgrps       = ARRAY_SIZE(devlink_nl_mcgrps),
232 };