xref: /aosp_15_r20/external/libnl/lib/genl/ctrl.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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