libnl  3.2.7
ctrl.c
1 /*
2  * lib/genl/ctrl.c Generic Netlink Controller
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup genl_mngt
14  * @defgroup ctrl Controller
15  * @brief
16  *
17  * @{
18  */
19 
20 #include <netlink-generic.h>
21 #include <netlink/netlink.h>
22 #include <netlink/genl/genl.h>
23 #include <netlink/genl/family.h>
24 #include <netlink/genl/mngt.h>
25 #include <netlink/genl/ctrl.h>
26 #include <netlink/utils.h>
27 
28 /** @cond SKIP */
29 #define CTRL_VERSION 0x0001
30 
31 static struct nl_cache_ops genl_ctrl_ops;
32 /** @endcond */
33 
34 static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
35 {
36  return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
37  CTRL_VERSION, NLM_F_DUMP);
38 }
39 
40 static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
41  [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
42  [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING,
43  .maxlen = GENL_NAMSIZ },
44  [CTRL_ATTR_VERSION] = { .type = NLA_U32 },
45  [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 },
46  [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 },
47  [CTRL_ATTR_OPS] = { .type = NLA_NESTED },
48  [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
49 };
50 
51 static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
52  [CTRL_ATTR_OP_ID] = { .type = NLA_U32 },
53  [CTRL_ATTR_OP_FLAGS] = { .type = NLA_U32 },
54 };
55 
56 static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
57  [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
58  [CTRL_ATTR_MCAST_GRP_ID] = { .type = NLA_U32 },
59 };
60 
61 static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
62  struct genl_info *info, void *arg)
63 {
64  struct genl_family *family;
65  struct nl_parser_param *pp = arg;
66  int err;
67 
68  family = genl_family_alloc();
69  if (family == NULL) {
70  err = -NLE_NOMEM;
71  goto errout;
72  }
73 
74  if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
75  err = -NLE_MISSING_ATTR;
76  goto errout;
77  }
78 
79  if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
80  err = -NLE_MISSING_ATTR;
81  goto errout;
82  }
83 
84  family->ce_msgtype = info->nlh->nlmsg_type;
85  genl_family_set_id(family,
86  nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
87  genl_family_set_name(family,
88  nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
89 
90  if (info->attrs[CTRL_ATTR_VERSION]) {
91  uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
92  genl_family_set_version(family, version);
93  }
94 
95  if (info->attrs[CTRL_ATTR_HDRSIZE]) {
96  uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
97  genl_family_set_hdrsize(family, hdrsize);
98  }
99 
100  if (info->attrs[CTRL_ATTR_MAXATTR]) {
101  uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
102  genl_family_set_maxattr(family, maxattr);
103  }
104 
105  if (info->attrs[CTRL_ATTR_OPS]) {
106  struct nlattr *nla, *nla_ops;
107  int remaining;
108 
109  nla_ops = info->attrs[CTRL_ATTR_OPS];
110  nla_for_each_nested(nla, nla_ops, remaining) {
111  struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
112  int flags = 0, id;
113 
114  err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
115  family_op_policy);
116  if (err < 0)
117  goto errout;
118 
119  if (tb[CTRL_ATTR_OP_ID] == NULL) {
120  err = -NLE_MISSING_ATTR;
121  goto errout;
122  }
123 
124  id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
125 
126  if (tb[CTRL_ATTR_OP_FLAGS])
127  flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
128 
129  err = genl_family_add_op(family, id, flags);
130  if (err < 0)
131  goto errout;
132 
133  }
134  }
135 
136  if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
137  struct nlattr *nla, *nla_grps;
138  int remaining;
139 
140  nla_grps = info->attrs[CTRL_ATTR_MCAST_GROUPS];
141  nla_for_each_nested(nla, nla_grps, remaining) {
142  struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
143  int id;
144  const char * name;
145 
146  err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
147  family_grp_policy);
148  if (err < 0)
149  goto errout;
150 
151  if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
152  err = -NLE_MISSING_ATTR;
153  goto errout;
154  }
155  id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
156 
157  if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
158  err = -NLE_MISSING_ATTR;
159  goto errout;
160  }
161  name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
162 
163  err = genl_family_add_grp(family, id, name);
164  if (err < 0)
165  goto errout;
166  }
167 
168  }
169 
170  err = pp->pp_cb((struct nl_object *) family, pp);
171 errout:
172  genl_family_put(family);
173  return err;
174 }
175 
176 /**
177  * @name Cache Management
178  * @{
179  */
180 
181 int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
182 {
183  return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
184 }
185 
186 /**
187  * Look up generic netlink family by id in the provided cache.
188  * @arg cache Generic netlink family cache.
189  * @arg id Family identifier.
190  *
191  * Searches through the cache looking for a registered family
192  * matching the specified identifier. The caller will own a
193  * reference on the returned object which needs to be given
194  * back after usage using genl_family_put().
195  *
196  * @return Generic netlink family object or NULL if no match was found.
197  */
198 struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
199 {
200  struct genl_family *fam;
201 
202  if (cache->c_ops != &genl_ctrl_ops)
203  BUG();
204 
205  nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
206  if (fam->gf_id == id) {
207  nl_object_get((struct nl_object *) fam);
208  return fam;
209  }
210  }
211 
212  return NULL;
213 }
214 
215 /**
216  * @name Resolver
217  * @{
218  */
219 
220 /**
221  * Look up generic netlink family by family name in the provided cache.
222  * @arg cache Generic netlink family cache.
223  * @arg name Family name.
224  *
225  * Searches through the cache looking for a registered family
226  * matching the specified name. The caller will own a reference
227  * on the returned object which needs to be given back after
228  * usage using genl_family_put().
229  *
230  * @return Generic netlink family object or NULL if no match was found.
231  */
232 struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
233  const char *name)
234 {
235  struct genl_family *fam;
236 
237  if (cache->c_ops != &genl_ctrl_ops)
238  BUG();
239 
240  nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
241  if (!strcmp(name, fam->gf_name)) {
242  nl_object_get((struct nl_object *) fam);
243  return fam;
244  }
245  }
246 
247  return NULL;
248 }
249 
250 /** @} */
251 
252 /**
253  * Resolve generic netlink family name to its identifier
254  * @arg sk Netlink socket.
255  * @arg name Name of generic netlink family
256  *
257  * Resolves the generic netlink family name to its identifer and returns
258  * it.
259  *
260  * @return A positive identifier or a negative error code.
261  */
262 int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
263 {
264  struct nl_cache *cache;
265  struct genl_family *family;
266  int err;
267 
268  if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
269  return err;
270 
271  family = genl_ctrl_search_by_name(cache, name);
272  if (family == NULL) {
273  err = -NLE_OBJ_NOTFOUND;
274  goto errout;
275  }
276 
277  err = genl_family_get_id(family);
278  genl_family_put(family);
279 errout:
280  nl_cache_free(cache);
281 
282  return err;
283 }
284 
285 static int genl_ctrl_grp_by_name(const struct genl_family *family,
286  const char *grp_name)
287 {
288  struct genl_family_grp *grp;
289 
290  nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
291  if (!strcmp(grp->name, grp_name)) {
292  return grp->id;
293  }
294  }
295 
296  return -NLE_OBJ_NOTFOUND;
297 }
298 
299 int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
300  const char *grp_name)
301 {
302  struct nl_cache *cache;
303  struct genl_family *family;
304  int err;
305 
306  if ((err = genl_ctrl_alloc_cache(sk, &cache)) < 0)
307  return err;
308 
309  family = genl_ctrl_search_by_name(cache, family_name);
310  if (family == NULL) {
311  err = -NLE_OBJ_NOTFOUND;
312  goto errout;
313  }
314 
315  err = genl_ctrl_grp_by_name(family, grp_name);
316  genl_family_put(family);
317 errout:
318  nl_cache_free(cache);
319 
320  return err;
321 }
322 
323 /** @} */
324 
325 static struct genl_cmd genl_cmds[] = {
326  {
327  .c_id = CTRL_CMD_NEWFAMILY,
328  .c_name = "NEWFAMILY" ,
329  .c_maxattr = CTRL_ATTR_MAX,
330  .c_attr_policy = ctrl_policy,
331  .c_msg_parser = ctrl_msg_parser,
332  },
333  {
334  .c_id = CTRL_CMD_DELFAMILY,
335  .c_name = "DELFAMILY" ,
336  },
337  {
338  .c_id = CTRL_CMD_GETFAMILY,
339  .c_name = "GETFAMILY" ,
340  },
341  {
342  .c_id = CTRL_CMD_NEWOPS,
343  .c_name = "NEWOPS" ,
344  },
345  {
346  .c_id = CTRL_CMD_DELOPS,
347  .c_name = "DELOPS" ,
348  },
349 };
350 
351 static struct genl_ops genl_ops = {
352  .o_cmds = genl_cmds,
353  .o_ncmds = ARRAY_SIZE(genl_cmds),
354 };
355 
356 /** @cond SKIP */
357 extern struct nl_object_ops genl_family_ops;
358 /** @endcond */
359 
360 static struct nl_cache_ops genl_ctrl_ops = {
361  .co_name = "genl/family",
362  .co_hdrsize = GENL_HDRSIZE(0),
363  .co_msgtypes = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
364  .co_genl = &genl_ops,
365  .co_protocol = NETLINK_GENERIC,
366  .co_request_update = ctrl_request_update,
367  .co_obj_ops = &genl_family_ops,
368 };
369 
370 static void __init ctrl_init(void)
371 {
372  genl_register(&genl_ctrl_ops);
373 }
374 
375 static void __exit ctrl_exit(void)
376 {
377  genl_unregister(&genl_ctrl_ops);
378 }
379 
380 /** @} */