1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker * Copyright (c) 2003-2012 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker */
5*4dc78e53SAndroid Build Coastguard Worker
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker * @ingroup genl
8*4dc78e53SAndroid Build Coastguard Worker * @defgroup genl_ctrl Controller (Resolver)
9*4dc78e53SAndroid Build Coastguard Worker *
10*4dc78e53SAndroid Build Coastguard Worker * Resolves Generic Netlink family names to numeric identifiers.
11*4dc78e53SAndroid Build Coastguard Worker *
12*4dc78e53SAndroid Build Coastguard Worker * The controller is a component in the kernel that resolves Generic Netlink
13*4dc78e53SAndroid Build Coastguard Worker * family names to their numeric identifiers. This module provides functions
14*4dc78e53SAndroid Build Coastguard Worker * to query the controller to access the resolving functionality.
15*4dc78e53SAndroid Build Coastguard Worker * @{
16*4dc78e53SAndroid Build Coastguard Worker */
17*4dc78e53SAndroid Build Coastguard Worker
18*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
19*4dc78e53SAndroid Build Coastguard Worker
20*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
21*4dc78e53SAndroid Build Coastguard Worker #include <netlink/genl/genl.h>
22*4dc78e53SAndroid Build Coastguard Worker #include <netlink/genl/family.h>
23*4dc78e53SAndroid Build Coastguard Worker #include <netlink/genl/mngt.h>
24*4dc78e53SAndroid Build Coastguard Worker #include <netlink/genl/ctrl.h>
25*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
26*4dc78e53SAndroid Build Coastguard Worker
27*4dc78e53SAndroid Build Coastguard Worker #include "nl-genl.h"
28*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/nl-core.h"
29*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/object-api.h"
30*4dc78e53SAndroid Build Coastguard Worker
31*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
32*4dc78e53SAndroid Build Coastguard Worker #define CTRL_VERSION 0x0001
33*4dc78e53SAndroid Build Coastguard Worker
34*4dc78e53SAndroid Build Coastguard Worker static struct nl_cache_ops genl_ctrl_ops;
35*4dc78e53SAndroid Build Coastguard Worker
ctrl_request_update(struct nl_cache * c,struct nl_sock * h)36*4dc78e53SAndroid Build Coastguard Worker static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
37*4dc78e53SAndroid Build Coastguard Worker {
38*4dc78e53SAndroid Build Coastguard Worker return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
39*4dc78e53SAndroid Build Coastguard Worker CTRL_VERSION, NLM_F_DUMP);
40*4dc78e53SAndroid Build Coastguard Worker }
41*4dc78e53SAndroid Build Coastguard Worker
42*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
43*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
44*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING,
45*4dc78e53SAndroid Build Coastguard Worker .maxlen = GENL_NAMSIZ },
46*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_VERSION] = { .type = NLA_U32 },
47*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 },
48*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 },
49*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_OPS] = { .type = NLA_NESTED },
50*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
51*4dc78e53SAndroid Build Coastguard Worker };
52*4dc78e53SAndroid Build Coastguard Worker
53*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
54*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_OP_ID] = { .type = NLA_U32 },
55*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 },
56*4dc78e53SAndroid Build Coastguard Worker };
57*4dc78e53SAndroid Build Coastguard Worker
58*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
59*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
60*4dc78e53SAndroid Build Coastguard Worker [CTRL_ATTR_MCAST_GRP_ID] = { .type = NLA_U32 },
61*4dc78e53SAndroid Build Coastguard Worker };
62*4dc78e53SAndroid Build Coastguard Worker
parse_mcast_grps(struct genl_family * family,struct nlattr * grp_attr)63*4dc78e53SAndroid Build Coastguard Worker static int parse_mcast_grps(struct genl_family *family, struct nlattr *grp_attr)
64*4dc78e53SAndroid Build Coastguard Worker {
65*4dc78e53SAndroid Build Coastguard Worker struct nlattr *nla;
66*4dc78e53SAndroid Build Coastguard Worker int remaining, err;
67*4dc78e53SAndroid Build Coastguard Worker
68*4dc78e53SAndroid Build Coastguard Worker if (!grp_attr)
69*4dc78e53SAndroid Build Coastguard Worker BUG();
70*4dc78e53SAndroid Build Coastguard Worker
71*4dc78e53SAndroid Build Coastguard Worker nla_for_each_nested(nla, grp_attr, remaining) {
72*4dc78e53SAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
73*4dc78e53SAndroid Build Coastguard Worker int id;
74*4dc78e53SAndroid Build Coastguard Worker const char * name;
75*4dc78e53SAndroid Build Coastguard Worker
76*4dc78e53SAndroid Build Coastguard Worker err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
77*4dc78e53SAndroid Build Coastguard Worker family_grp_policy);
78*4dc78e53SAndroid Build Coastguard Worker if (err < 0)
79*4dc78e53SAndroid Build Coastguard Worker goto errout;
80*4dc78e53SAndroid Build Coastguard Worker
81*4dc78e53SAndroid Build Coastguard Worker if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
82*4dc78e53SAndroid Build Coastguard Worker err = -NLE_MISSING_ATTR;
83*4dc78e53SAndroid Build Coastguard Worker goto errout;
84*4dc78e53SAndroid Build Coastguard Worker }
85*4dc78e53SAndroid Build Coastguard Worker id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
86*4dc78e53SAndroid Build Coastguard Worker
87*4dc78e53SAndroid Build Coastguard Worker if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
88*4dc78e53SAndroid Build Coastguard Worker err = -NLE_MISSING_ATTR;
89*4dc78e53SAndroid Build Coastguard Worker goto errout;
90*4dc78e53SAndroid Build Coastguard Worker }
91*4dc78e53SAndroid Build Coastguard Worker name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
92*4dc78e53SAndroid Build Coastguard Worker
93*4dc78e53SAndroid Build Coastguard Worker err = genl_family_add_grp(family, id, name);
94*4dc78e53SAndroid Build Coastguard Worker if (err < 0)
95*4dc78e53SAndroid Build Coastguard Worker goto errout;
96*4dc78e53SAndroid Build Coastguard Worker }
97*4dc78e53SAndroid Build Coastguard Worker
98*4dc78e53SAndroid Build Coastguard Worker err = 0;
99*4dc78e53SAndroid Build Coastguard Worker
100*4dc78e53SAndroid Build Coastguard Worker errout:
101*4dc78e53SAndroid Build Coastguard Worker return err;
102*4dc78e53SAndroid Build Coastguard Worker }
103*4dc78e53SAndroid Build Coastguard Worker
ctrl_msg_parser(struct nl_cache_ops * ops,struct genl_cmd * cmd,struct genl_info * info,void * arg)104*4dc78e53SAndroid Build Coastguard Worker static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
105*4dc78e53SAndroid Build Coastguard Worker struct genl_info *info, void *arg)
106*4dc78e53SAndroid Build Coastguard Worker {
107*4dc78e53SAndroid Build Coastguard Worker struct genl_family *family;
108*4dc78e53SAndroid Build Coastguard Worker struct nl_parser_param *pp = arg;
109*4dc78e53SAndroid Build Coastguard Worker int err;
110*4dc78e53SAndroid Build Coastguard Worker
111*4dc78e53SAndroid Build Coastguard Worker family = genl_family_alloc();
112*4dc78e53SAndroid Build Coastguard Worker if (family == NULL) {
113*4dc78e53SAndroid Build Coastguard Worker err = -NLE_NOMEM;
114*4dc78e53SAndroid Build Coastguard Worker goto errout;
115*4dc78e53SAndroid Build Coastguard Worker }
116*4dc78e53SAndroid Build Coastguard Worker
117*4dc78e53SAndroid Build Coastguard Worker if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
118*4dc78e53SAndroid Build Coastguard Worker err = -NLE_MISSING_ATTR;
119*4dc78e53SAndroid Build Coastguard Worker goto errout;
120*4dc78e53SAndroid Build Coastguard Worker }
121*4dc78e53SAndroid Build Coastguard Worker
122*4dc78e53SAndroid Build Coastguard Worker if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
123*4dc78e53SAndroid Build Coastguard Worker err = -NLE_MISSING_ATTR;
124*4dc78e53SAndroid Build Coastguard Worker goto errout;
125*4dc78e53SAndroid Build Coastguard Worker }
126*4dc78e53SAndroid Build Coastguard Worker
127*4dc78e53SAndroid Build Coastguard Worker family->ce_msgtype = info->nlh->nlmsg_type;
128*4dc78e53SAndroid Build Coastguard Worker genl_family_set_id(family,
129*4dc78e53SAndroid Build Coastguard Worker nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
130*4dc78e53SAndroid Build Coastguard Worker genl_family_set_name(family,
131*4dc78e53SAndroid Build Coastguard Worker nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
132*4dc78e53SAndroid Build Coastguard Worker
133*4dc78e53SAndroid Build Coastguard Worker if (info->attrs[CTRL_ATTR_VERSION]) {
134*4dc78e53SAndroid Build Coastguard Worker uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
135*4dc78e53SAndroid Build Coastguard Worker genl_family_set_version(family, version);
136*4dc78e53SAndroid Build Coastguard Worker }
137*4dc78e53SAndroid Build Coastguard Worker
138*4dc78e53SAndroid Build Coastguard Worker if (info->attrs[CTRL_ATTR_HDRSIZE]) {
139*4dc78e53SAndroid Build Coastguard Worker uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
140*4dc78e53SAndroid Build Coastguard Worker genl_family_set_hdrsize(family, hdrsize);
141*4dc78e53SAndroid Build Coastguard Worker }
142*4dc78e53SAndroid Build Coastguard Worker
143*4dc78e53SAndroid Build Coastguard Worker if (info->attrs[CTRL_ATTR_MAXATTR]) {
144*4dc78e53SAndroid Build Coastguard Worker uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
145*4dc78e53SAndroid Build Coastguard Worker genl_family_set_maxattr(family, maxattr);
146*4dc78e53SAndroid Build Coastguard Worker }
147*4dc78e53SAndroid Build Coastguard Worker
148*4dc78e53SAndroid Build Coastguard Worker if (info->attrs[CTRL_ATTR_OPS]) {
149*4dc78e53SAndroid Build Coastguard Worker struct nlattr *nla, *nla_ops;
150*4dc78e53SAndroid Build Coastguard Worker int remaining;
151*4dc78e53SAndroid Build Coastguard Worker
152*4dc78e53SAndroid Build Coastguard Worker nla_ops = info->attrs[CTRL_ATTR_OPS];
153*4dc78e53SAndroid Build Coastguard Worker nla_for_each_nested(nla, nla_ops, remaining) {
154*4dc78e53SAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
155*4dc78e53SAndroid Build Coastguard Worker int flags = 0, id;
156*4dc78e53SAndroid Build Coastguard Worker
157*4dc78e53SAndroid Build Coastguard Worker err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
158*4dc78e53SAndroid Build Coastguard Worker family_op_policy);
159*4dc78e53SAndroid Build Coastguard Worker if (err < 0)
160*4dc78e53SAndroid Build Coastguard Worker goto errout;
161*4dc78e53SAndroid Build Coastguard Worker
162*4dc78e53SAndroid Build Coastguard Worker if (tb[CTRL_ATTR_OP_ID] == NULL) {
163*4dc78e53SAndroid Build Coastguard Worker err = -NLE_MISSING_ATTR;
164*4dc78e53SAndroid Build Coastguard Worker goto errout;
165*4dc78e53SAndroid Build Coastguard Worker }
166*4dc78e53SAndroid Build Coastguard Worker
167*4dc78e53SAndroid Build Coastguard Worker id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
168*4dc78e53SAndroid Build Coastguard Worker
169*4dc78e53SAndroid Build Coastguard Worker if (tb[CTRL_ATTR_OP_FLAGS])
170*4dc78e53SAndroid Build Coastguard Worker flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
171*4dc78e53SAndroid Build Coastguard Worker
172*4dc78e53SAndroid Build Coastguard Worker err = genl_family_add_op(family, id, flags);
173*4dc78e53SAndroid Build Coastguard Worker if (err < 0)
174*4dc78e53SAndroid Build Coastguard Worker goto errout;
175*4dc78e53SAndroid Build Coastguard Worker
176*4dc78e53SAndroid Build Coastguard Worker }
177*4dc78e53SAndroid Build Coastguard Worker }
178*4dc78e53SAndroid Build Coastguard Worker
179*4dc78e53SAndroid Build Coastguard Worker if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
180*4dc78e53SAndroid Build Coastguard Worker err = parse_mcast_grps(family, info->attrs[CTRL_ATTR_MCAST_GROUPS]);
181*4dc78e53SAndroid Build Coastguard Worker if (err < 0)
182*4dc78e53SAndroid Build Coastguard Worker goto errout;
183*4dc78e53SAndroid Build Coastguard Worker }
184*4dc78e53SAndroid Build Coastguard Worker
185*4dc78e53SAndroid Build Coastguard Worker err = pp->pp_cb((struct nl_object *) family, pp);
186*4dc78e53SAndroid Build Coastguard Worker errout:
187*4dc78e53SAndroid Build Coastguard Worker genl_family_put(family);
188*4dc78e53SAndroid Build Coastguard Worker return err;
189*4dc78e53SAndroid Build Coastguard Worker }
190*4dc78e53SAndroid Build Coastguard Worker
191*4dc78e53SAndroid Build Coastguard Worker /**
192*4dc78e53SAndroid Build Coastguard Worker * process responses from from the query sent by genl_ctrl_probe_by_name
193*4dc78e53SAndroid Build Coastguard Worker * @arg nl_msg Returned message.
194*4dc78e53SAndroid Build Coastguard Worker * @arg name genl_family structure to fill out.
195*4dc78e53SAndroid Build Coastguard Worker *
196*4dc78e53SAndroid Build Coastguard Worker * Process returned messages, filling out the missing informatino in the
197*4dc78e53SAndroid Build Coastguard Worker * genl_family structure
198*4dc78e53SAndroid Build Coastguard Worker *
199*4dc78e53SAndroid Build Coastguard Worker * @return Indicator to keep processing frames or not
200*4dc78e53SAndroid Build Coastguard Worker *
201*4dc78e53SAndroid Build Coastguard Worker */
probe_response(struct nl_msg * msg,void * arg)202*4dc78e53SAndroid Build Coastguard Worker static int probe_response(struct nl_msg *msg, void *arg)
203*4dc78e53SAndroid Build Coastguard Worker {
204*4dc78e53SAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_MAX+1];
205*4dc78e53SAndroid Build Coastguard Worker struct nlmsghdr *nlh = nlmsg_hdr(msg);
206*4dc78e53SAndroid Build Coastguard Worker struct genl_family *ret = (struct genl_family *)arg;
207*4dc78e53SAndroid Build Coastguard Worker
208*4dc78e53SAndroid Build Coastguard Worker if (genlmsg_parse(nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy))
209*4dc78e53SAndroid Build Coastguard Worker return NL_SKIP;
210*4dc78e53SAndroid Build Coastguard Worker
211*4dc78e53SAndroid Build Coastguard Worker if (tb[CTRL_ATTR_FAMILY_ID])
212*4dc78e53SAndroid Build Coastguard Worker genl_family_set_id(ret, nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]));
213*4dc78e53SAndroid Build Coastguard Worker
214*4dc78e53SAndroid Build Coastguard Worker if (tb[CTRL_ATTR_MCAST_GROUPS])
215*4dc78e53SAndroid Build Coastguard Worker if (parse_mcast_grps(ret, tb[CTRL_ATTR_MCAST_GROUPS]) < 0)
216*4dc78e53SAndroid Build Coastguard Worker return NL_SKIP;
217*4dc78e53SAndroid Build Coastguard Worker
218*4dc78e53SAndroid Build Coastguard Worker return NL_STOP;
219*4dc78e53SAndroid Build Coastguard Worker }
220*4dc78e53SAndroid Build Coastguard Worker
221*4dc78e53SAndroid Build Coastguard Worker /**
222*4dc78e53SAndroid Build Coastguard Worker * Look up generic netlink family by family name querying the kernel directly
223*4dc78e53SAndroid Build Coastguard Worker * @arg sk Socket.
224*4dc78e53SAndroid Build Coastguard Worker * @arg name Family name.
225*4dc78e53SAndroid Build Coastguard Worker *
226*4dc78e53SAndroid Build Coastguard Worker * Directly query's the kernel for a given family name. The caller will own a
227*4dc78e53SAndroid Build Coastguard Worker * reference on the returned object which needsd to be given back after usage
228*4dc78e53SAndroid Build Coastguard Worker * using genl_family_put.
229*4dc78e53SAndroid Build Coastguard Worker *
230*4dc78e53SAndroid Build Coastguard Worker * Note: This API call differs from genl_ctrl_search_by_name in that it querys
231*4dc78e53SAndroid Build Coastguard Worker * the kernel directly, alowing for module autoload to take place to resolve the
232*4dc78e53SAndroid Build Coastguard Worker * family request. Using an nl_cache prevents that operation
233*4dc78e53SAndroid Build Coastguard Worker *
234*4dc78e53SAndroid Build Coastguard Worker * @return Generic netlink family object or NULL if no match was found.
235*4dc78e53SAndroid Build Coastguard Worker */
genl_ctrl_probe_by_name(struct nl_sock * sk,const char * name)236*4dc78e53SAndroid Build Coastguard Worker static struct genl_family *genl_ctrl_probe_by_name(struct nl_sock *sk,
237*4dc78e53SAndroid Build Coastguard Worker const char *name)
238*4dc78e53SAndroid Build Coastguard Worker {
239*4dc78e53SAndroid Build Coastguard Worker struct nl_msg *msg;
240*4dc78e53SAndroid Build Coastguard Worker struct genl_family *ret;
241*4dc78e53SAndroid Build Coastguard Worker struct nl_cb *cb, *orig;
242*4dc78e53SAndroid Build Coastguard Worker int rc;
243*4dc78e53SAndroid Build Coastguard Worker
244*4dc78e53SAndroid Build Coastguard Worker ret = genl_family_alloc();
245*4dc78e53SAndroid Build Coastguard Worker if (!ret)
246*4dc78e53SAndroid Build Coastguard Worker goto out;
247*4dc78e53SAndroid Build Coastguard Worker
248*4dc78e53SAndroid Build Coastguard Worker genl_family_set_name(ret, name);
249*4dc78e53SAndroid Build Coastguard Worker
250*4dc78e53SAndroid Build Coastguard Worker msg = nlmsg_alloc();
251*4dc78e53SAndroid Build Coastguard Worker if (!msg)
252*4dc78e53SAndroid Build Coastguard Worker goto out_fam_free;
253*4dc78e53SAndroid Build Coastguard Worker
254*4dc78e53SAndroid Build Coastguard Worker if (!(orig = nl_socket_get_cb(sk)))
255*4dc78e53SAndroid Build Coastguard Worker goto out_msg_free;
256*4dc78e53SAndroid Build Coastguard Worker
257*4dc78e53SAndroid Build Coastguard Worker cb = nl_cb_clone(orig);
258*4dc78e53SAndroid Build Coastguard Worker nl_cb_put(orig);
259*4dc78e53SAndroid Build Coastguard Worker if (!cb)
260*4dc78e53SAndroid Build Coastguard Worker goto out_msg_free;
261*4dc78e53SAndroid Build Coastguard Worker
262*4dc78e53SAndroid Build Coastguard Worker if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
263*4dc78e53SAndroid Build Coastguard Worker 0, 0, CTRL_CMD_GETFAMILY, 1)) {
264*4dc78e53SAndroid Build Coastguard Worker BUG();
265*4dc78e53SAndroid Build Coastguard Worker goto out_cb_free;
266*4dc78e53SAndroid Build Coastguard Worker }
267*4dc78e53SAndroid Build Coastguard Worker
268*4dc78e53SAndroid Build Coastguard Worker if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
269*4dc78e53SAndroid Build Coastguard Worker goto out_cb_free;
270*4dc78e53SAndroid Build Coastguard Worker
271*4dc78e53SAndroid Build Coastguard Worker rc = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response,
272*4dc78e53SAndroid Build Coastguard Worker (void *) ret);
273*4dc78e53SAndroid Build Coastguard Worker if (rc < 0)
274*4dc78e53SAndroid Build Coastguard Worker goto out_cb_free;
275*4dc78e53SAndroid Build Coastguard Worker
276*4dc78e53SAndroid Build Coastguard Worker rc = nl_send_auto_complete(sk, msg);
277*4dc78e53SAndroid Build Coastguard Worker if (rc < 0)
278*4dc78e53SAndroid Build Coastguard Worker goto out_cb_free;
279*4dc78e53SAndroid Build Coastguard Worker
280*4dc78e53SAndroid Build Coastguard Worker rc = nl_recvmsgs(sk, cb);
281*4dc78e53SAndroid Build Coastguard Worker if (rc < 0)
282*4dc78e53SAndroid Build Coastguard Worker goto out_cb_free;
283*4dc78e53SAndroid Build Coastguard Worker
284*4dc78e53SAndroid Build Coastguard Worker /* If search was successful, request may be ACKed after data */
285*4dc78e53SAndroid Build Coastguard Worker rc = wait_for_ack(sk);
286*4dc78e53SAndroid Build Coastguard Worker if (rc < 0)
287*4dc78e53SAndroid Build Coastguard Worker goto out_cb_free;
288*4dc78e53SAndroid Build Coastguard Worker
289*4dc78e53SAndroid Build Coastguard Worker if (genl_family_get_id(ret) != 0) {
290*4dc78e53SAndroid Build Coastguard Worker nlmsg_free(msg);
291*4dc78e53SAndroid Build Coastguard Worker nl_cb_put(cb);
292*4dc78e53SAndroid Build Coastguard Worker return ret;
293*4dc78e53SAndroid Build Coastguard Worker }
294*4dc78e53SAndroid Build Coastguard Worker
295*4dc78e53SAndroid Build Coastguard Worker out_cb_free:
296*4dc78e53SAndroid Build Coastguard Worker nl_cb_put(cb);
297*4dc78e53SAndroid Build Coastguard Worker out_msg_free:
298*4dc78e53SAndroid Build Coastguard Worker nlmsg_free(msg);
299*4dc78e53SAndroid Build Coastguard Worker out_fam_free:
300*4dc78e53SAndroid Build Coastguard Worker genl_family_put(ret);
301*4dc78e53SAndroid Build Coastguard Worker ret = NULL;
302*4dc78e53SAndroid Build Coastguard Worker out:
303*4dc78e53SAndroid Build Coastguard Worker return ret;
304*4dc78e53SAndroid Build Coastguard Worker }
305*4dc78e53SAndroid Build Coastguard Worker
306*4dc78e53SAndroid Build Coastguard Worker
307*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
308*4dc78e53SAndroid Build Coastguard Worker
309*4dc78e53SAndroid Build Coastguard Worker /**
310*4dc78e53SAndroid Build Coastguard Worker * @name Controller Cache
311*4dc78e53SAndroid Build Coastguard Worker *
312*4dc78e53SAndroid Build Coastguard Worker * The controller cache allows to keep a local copy of the list of all
313*4dc78e53SAndroid Build Coastguard Worker * kernel side registered Generic Netlink families to quickly resolve
314*4dc78e53SAndroid Build Coastguard Worker * multiple Generic Netlink family names without requiring to communicate
315*4dc78e53SAndroid Build Coastguard Worker * with the kernel for each resolving iteration.
316*4dc78e53SAndroid Build Coastguard Worker *
317*4dc78e53SAndroid Build Coastguard Worker * @{
318*4dc78e53SAndroid Build Coastguard Worker */
319*4dc78e53SAndroid Build Coastguard Worker
320*4dc78e53SAndroid Build Coastguard Worker /**
321*4dc78e53SAndroid Build Coastguard Worker * Allocate a new controller cache
322*4dc78e53SAndroid Build Coastguard Worker * @arg sk Generic Netlink socket
323*4dc78e53SAndroid Build Coastguard Worker * @arg result Pointer to store resulting cache
324*4dc78e53SAndroid Build Coastguard Worker *
325*4dc78e53SAndroid Build Coastguard Worker * Allocates a new cache mirroring the state of the controller and stores it
326*4dc78e53SAndroid Build Coastguard Worker * in \c *result. The allocated cache will contain a list of all currently
327*4dc78e53SAndroid Build Coastguard Worker * registered kernel side Generic Netlink families. The cache is meant to be
328*4dc78e53SAndroid Build Coastguard Worker * used to resolve family names locally.
329*4dc78e53SAndroid Build Coastguard Worker *
330*4dc78e53SAndroid Build Coastguard Worker * @return 0 on success or a negative error code.
331*4dc78e53SAndroid Build Coastguard Worker */
genl_ctrl_alloc_cache(struct nl_sock * sk,struct nl_cache ** result)332*4dc78e53SAndroid Build Coastguard Worker int genl_ctrl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
333*4dc78e53SAndroid Build Coastguard Worker {
334*4dc78e53SAndroid Build Coastguard Worker return nl_cache_alloc_and_fill(&genl_ctrl_ops, sk, result);
335*4dc78e53SAndroid Build Coastguard Worker }
336*4dc78e53SAndroid Build Coastguard Worker
337*4dc78e53SAndroid Build Coastguard Worker /**
338*4dc78e53SAndroid Build Coastguard Worker * Search controller cache for a numeric address match
339*4dc78e53SAndroid Build Coastguard Worker * @arg cache Controller cache
340*4dc78e53SAndroid Build Coastguard Worker * @arg id Numeric family identifier.
341*4dc78e53SAndroid Build Coastguard Worker *
342*4dc78e53SAndroid Build Coastguard Worker * Searches a previously allocated controller cache and looks for an entry
343*4dc78e53SAndroid Build Coastguard Worker * that matches the specified numeric family identifier \c id. If a match
344*4dc78e53SAndroid Build Coastguard Worker * is found successfully, the reference count of the matching object is
345*4dc78e53SAndroid Build Coastguard Worker * increased by one before the objet is returned.
346*4dc78e53SAndroid Build Coastguard Worker *
347*4dc78e53SAndroid Build Coastguard Worker * @see genl_ctrl_alloc_cache()
348*4dc78e53SAndroid Build Coastguard Worker * @see genl_ctrl_search_by_name()
349*4dc78e53SAndroid Build Coastguard Worker * @see genl_family_put()
350*4dc78e53SAndroid Build Coastguard Worker *
351*4dc78e53SAndroid Build Coastguard Worker * @return Generic Netlink family object or NULL if no match was found.
352*4dc78e53SAndroid Build Coastguard Worker */
genl_ctrl_search(struct nl_cache * cache,int id)353*4dc78e53SAndroid Build Coastguard Worker struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
354*4dc78e53SAndroid Build Coastguard Worker {
355*4dc78e53SAndroid Build Coastguard Worker struct genl_family *fam;
356*4dc78e53SAndroid Build Coastguard Worker
357*4dc78e53SAndroid Build Coastguard Worker if (cache->c_ops != &genl_ctrl_ops)
358*4dc78e53SAndroid Build Coastguard Worker BUG();
359*4dc78e53SAndroid Build Coastguard Worker
360*4dc78e53SAndroid Build Coastguard Worker nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
361*4dc78e53SAndroid Build Coastguard Worker if (fam->gf_id == id) {
362*4dc78e53SAndroid Build Coastguard Worker nl_object_get((struct nl_object *) fam);
363*4dc78e53SAndroid Build Coastguard Worker return fam;
364*4dc78e53SAndroid Build Coastguard Worker }
365*4dc78e53SAndroid Build Coastguard Worker }
366*4dc78e53SAndroid Build Coastguard Worker
367*4dc78e53SAndroid Build Coastguard Worker return NULL;
368*4dc78e53SAndroid Build Coastguard Worker }
369*4dc78e53SAndroid Build Coastguard Worker
370*4dc78e53SAndroid Build Coastguard Worker /**
371*4dc78e53SAndroid Build Coastguard Worker * Search controller cache for a family name match
372*4dc78e53SAndroid Build Coastguard Worker * @arg cache Controller cache
373*4dc78e53SAndroid Build Coastguard Worker * @arg name Name of Generic Netlink family
374*4dc78e53SAndroid Build Coastguard Worker *
375*4dc78e53SAndroid Build Coastguard Worker * Searches a previously allocated controller cache and looks for an entry
376*4dc78e53SAndroid Build Coastguard Worker * that matches the specified family \c name. If a match is found successfully,
377*4dc78e53SAndroid Build Coastguard Worker * the reference count of the matching object is increased by one before the
378*4dc78e53SAndroid Build Coastguard Worker * objet is returned.
379*4dc78e53SAndroid Build Coastguard Worker *
380*4dc78e53SAndroid Build Coastguard Worker * @see genl_ctrl_alloc_cache()
381*4dc78e53SAndroid Build Coastguard Worker * @see genl_ctrl_search()
382*4dc78e53SAndroid Build Coastguard Worker * @see genl_family_put()
383*4dc78e53SAndroid Build Coastguard Worker *
384*4dc78e53SAndroid Build Coastguard Worker * @return Generic Netlink family object or NULL if no match was found.
385*4dc78e53SAndroid Build Coastguard Worker */
genl_ctrl_search_by_name(struct nl_cache * cache,const char * name)386*4dc78e53SAndroid Build Coastguard Worker struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
387*4dc78e53SAndroid Build Coastguard Worker const char *name)
388*4dc78e53SAndroid Build Coastguard Worker {
389*4dc78e53SAndroid Build Coastguard Worker struct genl_family *fam;
390*4dc78e53SAndroid Build Coastguard Worker
391*4dc78e53SAndroid Build Coastguard Worker if (cache->c_ops != &genl_ctrl_ops)
392*4dc78e53SAndroid Build Coastguard Worker BUG();
393*4dc78e53SAndroid Build Coastguard Worker
394*4dc78e53SAndroid Build Coastguard Worker nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
395*4dc78e53SAndroid Build Coastguard Worker if (!strcmp(name, fam->gf_name)) {
396*4dc78e53SAndroid Build Coastguard Worker nl_object_get((struct nl_object *) fam);
397*4dc78e53SAndroid Build Coastguard Worker return fam;
398*4dc78e53SAndroid Build Coastguard Worker }
399*4dc78e53SAndroid Build Coastguard Worker }
400*4dc78e53SAndroid Build Coastguard Worker
401*4dc78e53SAndroid Build Coastguard Worker return NULL;
402*4dc78e53SAndroid Build Coastguard Worker }
403*4dc78e53SAndroid Build Coastguard Worker
404*4dc78e53SAndroid Build Coastguard Worker /** @} */
405*4dc78e53SAndroid Build Coastguard Worker
406*4dc78e53SAndroid Build Coastguard Worker /**
407*4dc78e53SAndroid Build Coastguard Worker * @name Direct Resolvers
408*4dc78e53SAndroid Build Coastguard Worker *
409*4dc78e53SAndroid Build Coastguard Worker * These functions communicate directly with the kernel and do not require
410*4dc78e53SAndroid Build Coastguard Worker * a cache to be kept up to date.
411*4dc78e53SAndroid Build Coastguard Worker *
412*4dc78e53SAndroid Build Coastguard Worker * @{
413*4dc78e53SAndroid Build Coastguard Worker */
414*4dc78e53SAndroid Build Coastguard Worker
415*4dc78e53SAndroid Build Coastguard Worker /**
416*4dc78e53SAndroid Build Coastguard Worker * Resolve Generic Netlink family name to numeric identifier
417*4dc78e53SAndroid Build Coastguard Worker * @arg sk Generic Netlink socket.
418*4dc78e53SAndroid Build Coastguard Worker * @arg name Name of Generic Netlink family
419*4dc78e53SAndroid Build Coastguard Worker *
420*4dc78e53SAndroid Build Coastguard Worker * Resolves the Generic Netlink family name to the corresponding numeric
421*4dc78e53SAndroid Build Coastguard Worker * family identifier. This function queries the kernel directly, use
422*4dc78e53SAndroid Build Coastguard Worker * genl_ctrl_search_by_name() if you need to resolve multiple names.
423*4dc78e53SAndroid Build Coastguard Worker *
424*4dc78e53SAndroid Build Coastguard Worker * @see genl_ctrl_search_by_name()
425*4dc78e53SAndroid Build Coastguard Worker *
426*4dc78e53SAndroid Build Coastguard Worker * @return The numeric family identifier or a negative error code.
427*4dc78e53SAndroid Build Coastguard Worker */
genl_ctrl_resolve(struct nl_sock * sk,const char * name)428*4dc78e53SAndroid Build Coastguard Worker int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
429*4dc78e53SAndroid Build Coastguard Worker {
430*4dc78e53SAndroid Build Coastguard Worker struct genl_family *family;
431*4dc78e53SAndroid Build Coastguard Worker int err;
432*4dc78e53SAndroid Build Coastguard Worker
433*4dc78e53SAndroid Build Coastguard Worker family = genl_ctrl_probe_by_name(sk, name);
434*4dc78e53SAndroid Build Coastguard Worker if (family == NULL) {
435*4dc78e53SAndroid Build Coastguard Worker err = -NLE_OBJ_NOTFOUND;
436*4dc78e53SAndroid Build Coastguard Worker goto errout;
437*4dc78e53SAndroid Build Coastguard Worker }
438*4dc78e53SAndroid Build Coastguard Worker
439*4dc78e53SAndroid Build Coastguard Worker err = genl_family_get_id(family);
440*4dc78e53SAndroid Build Coastguard Worker genl_family_put(family);
441*4dc78e53SAndroid Build Coastguard Worker errout:
442*4dc78e53SAndroid Build Coastguard Worker return err;
443*4dc78e53SAndroid Build Coastguard Worker }
444*4dc78e53SAndroid Build Coastguard Worker
genl_ctrl_grp_by_name(const struct genl_family * family,const char * grp_name)445*4dc78e53SAndroid Build Coastguard Worker static int genl_ctrl_grp_by_name(const struct genl_family *family,
446*4dc78e53SAndroid Build Coastguard Worker const char *grp_name)
447*4dc78e53SAndroid Build Coastguard Worker {
448*4dc78e53SAndroid Build Coastguard Worker struct genl_family_grp *grp;
449*4dc78e53SAndroid Build Coastguard Worker
450*4dc78e53SAndroid Build Coastguard Worker nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
451*4dc78e53SAndroid Build Coastguard Worker if (!strcmp(grp->name, grp_name)) {
452*4dc78e53SAndroid Build Coastguard Worker return grp->id;
453*4dc78e53SAndroid Build Coastguard Worker }
454*4dc78e53SAndroid Build Coastguard Worker }
455*4dc78e53SAndroid Build Coastguard Worker
456*4dc78e53SAndroid Build Coastguard Worker return -NLE_OBJ_NOTFOUND;
457*4dc78e53SAndroid Build Coastguard Worker }
458*4dc78e53SAndroid Build Coastguard Worker
459*4dc78e53SAndroid Build Coastguard Worker /**
460*4dc78e53SAndroid Build Coastguard Worker * Resolve Generic Netlink family group name
461*4dc78e53SAndroid Build Coastguard Worker * @arg sk Generic Netlink socket
462*4dc78e53SAndroid Build Coastguard Worker * @arg family_name Name of Generic Netlink family
463*4dc78e53SAndroid Build Coastguard Worker * @arg grp_name Name of group to resolve
464*4dc78e53SAndroid Build Coastguard Worker *
465*4dc78e53SAndroid Build Coastguard Worker * Looks up the family object and resolves the group name to the numeric
466*4dc78e53SAndroid Build Coastguard Worker * group identifier.
467*4dc78e53SAndroid Build Coastguard Worker *
468*4dc78e53SAndroid Build Coastguard Worker * @return Numeric group identifier or a negative error code.
469*4dc78e53SAndroid Build Coastguard Worker */
genl_ctrl_resolve_grp(struct nl_sock * sk,const char * family_name,const char * grp_name)470*4dc78e53SAndroid Build Coastguard Worker int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
471*4dc78e53SAndroid Build Coastguard Worker const char *grp_name)
472*4dc78e53SAndroid Build Coastguard Worker {
473*4dc78e53SAndroid Build Coastguard Worker
474*4dc78e53SAndroid Build Coastguard Worker struct genl_family *family;
475*4dc78e53SAndroid Build Coastguard Worker int err;
476*4dc78e53SAndroid Build Coastguard Worker
477*4dc78e53SAndroid Build Coastguard Worker family = genl_ctrl_probe_by_name(sk, family_name);
478*4dc78e53SAndroid Build Coastguard Worker if (family == NULL) {
479*4dc78e53SAndroid Build Coastguard Worker err = -NLE_OBJ_NOTFOUND;
480*4dc78e53SAndroid Build Coastguard Worker goto errout;
481*4dc78e53SAndroid Build Coastguard Worker }
482*4dc78e53SAndroid Build Coastguard Worker
483*4dc78e53SAndroid Build Coastguard Worker err = genl_ctrl_grp_by_name(family, grp_name);
484*4dc78e53SAndroid Build Coastguard Worker genl_family_put(family);
485*4dc78e53SAndroid Build Coastguard Worker errout:
486*4dc78e53SAndroid Build Coastguard Worker return err;
487*4dc78e53SAndroid Build Coastguard Worker }
488*4dc78e53SAndroid Build Coastguard Worker
489*4dc78e53SAndroid Build Coastguard Worker /** @} */
490*4dc78e53SAndroid Build Coastguard Worker
491*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
492*4dc78e53SAndroid Build Coastguard Worker static struct genl_cmd genl_cmds[] = {
493*4dc78e53SAndroid Build Coastguard Worker {
494*4dc78e53SAndroid Build Coastguard Worker .c_id = CTRL_CMD_NEWFAMILY,
495*4dc78e53SAndroid Build Coastguard Worker .c_name = "NEWFAMILY" ,
496*4dc78e53SAndroid Build Coastguard Worker .c_maxattr = CTRL_ATTR_MAX,
497*4dc78e53SAndroid Build Coastguard Worker .c_attr_policy = ctrl_policy,
498*4dc78e53SAndroid Build Coastguard Worker .c_msg_parser = ctrl_msg_parser,
499*4dc78e53SAndroid Build Coastguard Worker },
500*4dc78e53SAndroid Build Coastguard Worker {
501*4dc78e53SAndroid Build Coastguard Worker .c_id = CTRL_CMD_DELFAMILY,
502*4dc78e53SAndroid Build Coastguard Worker .c_name = "DELFAMILY" ,
503*4dc78e53SAndroid Build Coastguard Worker },
504*4dc78e53SAndroid Build Coastguard Worker {
505*4dc78e53SAndroid Build Coastguard Worker .c_id = CTRL_CMD_GETFAMILY,
506*4dc78e53SAndroid Build Coastguard Worker .c_name = "GETFAMILY" ,
507*4dc78e53SAndroid Build Coastguard Worker },
508*4dc78e53SAndroid Build Coastguard Worker {
509*4dc78e53SAndroid Build Coastguard Worker .c_id = CTRL_CMD_NEWOPS,
510*4dc78e53SAndroid Build Coastguard Worker .c_name = "NEWOPS" ,
511*4dc78e53SAndroid Build Coastguard Worker },
512*4dc78e53SAndroid Build Coastguard Worker {
513*4dc78e53SAndroid Build Coastguard Worker .c_id = CTRL_CMD_DELOPS,
514*4dc78e53SAndroid Build Coastguard Worker .c_name = "DELOPS" ,
515*4dc78e53SAndroid Build Coastguard Worker },
516*4dc78e53SAndroid Build Coastguard Worker };
517*4dc78e53SAndroid Build Coastguard Worker
518*4dc78e53SAndroid Build Coastguard Worker static struct genl_ops genl_ops = {
519*4dc78e53SAndroid Build Coastguard Worker .o_cmds = genl_cmds,
520*4dc78e53SAndroid Build Coastguard Worker .o_ncmds = ARRAY_SIZE(genl_cmds),
521*4dc78e53SAndroid Build Coastguard Worker };
522*4dc78e53SAndroid Build Coastguard Worker
523*4dc78e53SAndroid Build Coastguard Worker extern struct nl_object_ops genl_family_ops;
524*4dc78e53SAndroid Build Coastguard Worker
525*4dc78e53SAndroid Build Coastguard Worker #define GENL_FAMILY(id, name) \
526*4dc78e53SAndroid Build Coastguard Worker { \
527*4dc78e53SAndroid Build Coastguard Worker { id, NL_ACT_UNSPEC, name }, \
528*4dc78e53SAndroid Build Coastguard Worker END_OF_MSGTYPES_LIST, \
529*4dc78e53SAndroid Build Coastguard Worker }
530*4dc78e53SAndroid Build Coastguard Worker
531*4dc78e53SAndroid Build Coastguard Worker static struct nl_cache_ops genl_ctrl_ops = {
532*4dc78e53SAndroid Build Coastguard Worker .co_name = "genl/family",
533*4dc78e53SAndroid Build Coastguard Worker .co_hdrsize = GENL_HDRSIZE(0),
534*4dc78e53SAndroid Build Coastguard Worker .co_msgtypes = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
535*4dc78e53SAndroid Build Coastguard Worker .co_genl = &genl_ops,
536*4dc78e53SAndroid Build Coastguard Worker .co_protocol = NETLINK_GENERIC,
537*4dc78e53SAndroid Build Coastguard Worker .co_request_update = ctrl_request_update,
538*4dc78e53SAndroid Build Coastguard Worker .co_obj_ops = &genl_family_ops,
539*4dc78e53SAndroid Build Coastguard Worker };
540*4dc78e53SAndroid Build Coastguard Worker
ctrl_init(void)541*4dc78e53SAndroid Build Coastguard Worker static void _nl_init ctrl_init(void)
542*4dc78e53SAndroid Build Coastguard Worker {
543*4dc78e53SAndroid Build Coastguard Worker genl_register(&genl_ctrl_ops);
544*4dc78e53SAndroid Build Coastguard Worker }
545*4dc78e53SAndroid Build Coastguard Worker
ctrl_exit(void)546*4dc78e53SAndroid Build Coastguard Worker static void _nl_exit ctrl_exit(void)
547*4dc78e53SAndroid Build Coastguard Worker {
548*4dc78e53SAndroid Build Coastguard Worker genl_unregister(&genl_ctrl_ops);
549*4dc78e53SAndroid Build Coastguard Worker }
550*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
551*4dc78e53SAndroid Build Coastguard Worker
552*4dc78e53SAndroid Build Coastguard Worker /** @} */
553