libnftnl  1.0.2
set_elem.c
1 /*
2  * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This code has been sponsored by Sophos Astaro <http://www.sophos.com>
10  */
11 #include "internal.h"
12 
13 #include <time.h>
14 #include <endian.h>
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <netinet/in.h>
19 #include <errno.h>
20 
21 #include <libmnl/libmnl.h>
22 #include <linux/netfilter/nfnetlink.h>
23 #include <linux/netfilter/nf_tables.h>
24 
25 #include <libnftnl/set.h>
26 #include <libnftnl/rule.h>
27 
28 #include "linux_list.h"
29 #include "expr/data_reg.h"
30 
31 struct nft_set_elem *nft_set_elem_alloc(void)
32 {
33  struct nft_set_elem *s;
34 
35  s = calloc(1, sizeof(struct nft_set_elem));
36  if (s == NULL)
37  return NULL;
38 
39  return s;
40 }
41 EXPORT_SYMBOL(nft_set_elem_alloc);
42 
43 void nft_set_elem_free(struct nft_set_elem *s)
44 {
45  if (s->flags & (1 << NFT_SET_ELEM_ATTR_CHAIN)) {
46  if (s->data.chain) {
47  xfree(s->data.chain);
48  s->data.chain = NULL;
49  }
50  }
51  xfree(s);
52 }
53 EXPORT_SYMBOL(nft_set_elem_free);
54 
55 bool nft_set_elem_attr_is_set(const struct nft_set_elem *s, uint16_t attr)
56 {
57  return s->flags & (1 << attr);
58 }
59 EXPORT_SYMBOL(nft_set_elem_attr_is_set);
60 
61 void nft_set_elem_attr_unset(struct nft_set_elem *s, uint16_t attr)
62 {
63  switch (attr) {
64  case NFT_SET_ELEM_ATTR_CHAIN:
65  if (s->flags & (1 << NFT_SET_ELEM_ATTR_CHAIN)) {
66  if (s->data.chain) {
67  xfree(s->data.chain);
68  s->data.chain = NULL;
69  }
70  }
71  break;
72  case NFT_SET_ELEM_ATTR_FLAGS:
73  case NFT_SET_ELEM_ATTR_KEY: /* NFTA_SET_ELEM_KEY */
74  case NFT_SET_ELEM_ATTR_VERDICT: /* NFTA_SET_ELEM_DATA */
75  case NFT_SET_ELEM_ATTR_DATA: /* NFTA_SET_ELEM_DATA */
76  break;
77  default:
78  return;
79  }
80 
81  s->flags &= ~(1 << attr);
82 }
83 EXPORT_SYMBOL(nft_set_elem_attr_unset);
84 
85 void nft_set_elem_attr_set(struct nft_set_elem *s, uint16_t attr,
86  const void *data, uint32_t data_len)
87 {
88  switch(attr) {
89  case NFT_SET_ELEM_ATTR_FLAGS:
90  s->set_elem_flags = *((uint32_t *)data);
91  break;
92  case NFT_SET_ELEM_ATTR_KEY: /* NFTA_SET_ELEM_KEY */
93  memcpy(&s->key.val, data, data_len);
94  s->key.len = data_len;
95  break;
96  case NFT_SET_ELEM_ATTR_VERDICT: /* NFTA_SET_ELEM_DATA */
97  s->data.verdict = *((uint32_t *)data);
98  break;
99  case NFT_SET_ELEM_ATTR_CHAIN: /* NFTA_SET_ELEM_DATA */
100  if (s->data.chain)
101  xfree(s->data.chain);
102 
103  s->data.chain = strdup(data);
104  break;
105  case NFT_SET_ELEM_ATTR_DATA: /* NFTA_SET_ELEM_DATA */
106  memcpy(s->data.val, data, data_len);
107  s->data.len = data_len;
108  break;
109  default:
110  return;
111  }
112  s->flags |= (1 << attr);
113 }
114 EXPORT_SYMBOL(nft_set_elem_attr_set);
115 
116 void nft_set_elem_attr_set_u32(struct nft_set_elem *s, uint16_t attr, uint32_t val)
117 {
118  nft_set_elem_attr_set(s, attr, &val, sizeof(uint32_t));
119 }
120 EXPORT_SYMBOL(nft_set_elem_attr_set_u32);
121 
122 void nft_set_elem_attr_set_str(struct nft_set_elem *s, uint16_t attr, const char *str)
123 {
124  nft_set_elem_attr_set(s, attr, str, strlen(str));
125 }
126 EXPORT_SYMBOL(nft_set_elem_attr_set_str);
127 
128 const void *nft_set_elem_attr_get(struct nft_set_elem *s, uint16_t attr, uint32_t *data_len)
129 {
130  if (!(s->flags & (1 << attr)))
131  return NULL;
132 
133  switch(attr) {
134  case NFT_SET_ELEM_ATTR_FLAGS:
135  return &s->set_elem_flags;
136  case NFT_SET_ELEM_ATTR_KEY: /* NFTA_SET_ELEM_KEY */
137  *data_len = s->key.len;
138  return &s->key.val;
139  case NFT_SET_ELEM_ATTR_VERDICT: /* NFTA_SET_ELEM_DATA */
140  return &s->data.verdict;
141  case NFT_SET_ELEM_ATTR_CHAIN: /* NFTA_SET_ELEM_DATA */
142  return s->data.chain;
143  case NFT_SET_ELEM_ATTR_DATA: /* NFTA_SET_ELEM_DATA */
144  *data_len = s->data.len;
145  return &s->data.val;
146  }
147  return NULL;
148 }
149 EXPORT_SYMBOL(nft_set_elem_attr_get);
150 
151 const char *nft_set_elem_attr_get_str(struct nft_set_elem *s, uint16_t attr)
152 {
153  uint32_t size;
154 
155  return nft_set_elem_attr_get(s, attr, &size);
156 }
157 EXPORT_SYMBOL(nft_set_elem_attr_get_str);
158 
159 uint32_t nft_set_elem_attr_get_u32(struct nft_set_elem *s, uint16_t attr)
160 {
161  uint32_t size;
162  uint32_t val = *((uint32_t *)nft_set_elem_attr_get(s, attr, &size));
163  return val;
164 }
165 EXPORT_SYMBOL(nft_set_elem_attr_get_u32);
166 
167 void nft_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh,
168  struct nft_set_elem *e)
169 {
170  if (e->flags & (1 << NFT_SET_ELEM_ATTR_FLAGS))
171  mnl_attr_put_u32(nlh, NFTA_SET_ELEM_FLAGS, htonl(e->set_elem_flags));
172  if (e->flags & (1 << NFT_SET_ELEM_ATTR_KEY)) {
173  struct nlattr *nest1;
174 
175  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_KEY);
176  mnl_attr_put(nlh, NFTA_DATA_VALUE, e->key.len, e->key.val);
177  mnl_attr_nest_end(nlh, nest1);
178  }
179  if (e->flags & (1 << NFT_SET_ELEM_ATTR_VERDICT)) {
180  struct nlattr *nest1, *nest2;
181 
182  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_DATA);
183  nest2 = mnl_attr_nest_start(nlh, NFTA_DATA_VERDICT);
184  mnl_attr_put_u32(nlh, NFTA_VERDICT_CODE, htonl(e->data.verdict));
185  if (e->flags & (1 << NFT_SET_ELEM_ATTR_CHAIN))
186  mnl_attr_put_strz(nlh, NFTA_VERDICT_CHAIN, e->data.chain);
187 
188  mnl_attr_nest_end(nlh, nest1);
189  mnl_attr_nest_end(nlh, nest2);
190  }
191  if (e->flags & (1 << NFT_SET_ELEM_ATTR_DATA)) {
192  struct nlattr *nest1;
193 
194  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_DATA);
195  mnl_attr_put(nlh, NFTA_DATA_VALUE, e->data.len, e->data.val);
196  mnl_attr_nest_end(nlh, nest1);
197  }
198 }
199 
200 void nft_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nft_set *s)
201 {
202  struct nft_set_elem *elem;
203  struct nlattr *nest1;
204  int i = 0;
205 
206  if (s->flags & (1 << NFT_SET_ATTR_NAME))
207  mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_SET, s->name);
208  if (s->flags & (1 << NFT_SET_ATTR_ID))
209  mnl_attr_put_u32(nlh, NFTA_SET_ELEM_LIST_SET_ID, htonl(s->id));
210  if (s->flags & (1 << NFT_SET_ATTR_TABLE))
211  mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE, s->table);
212 
213  nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
214  list_for_each_entry(elem, &s->element_list, head) {
215  struct nlattr *nest2;
216 
217  nest2 = mnl_attr_nest_start(nlh, ++i);
218  nft_set_elem_nlmsg_build_payload(nlh, elem);
219  mnl_attr_nest_end(nlh, nest2);
220  }
221  mnl_attr_nest_end(nlh, nest1);
222 }
223 EXPORT_SYMBOL(nft_set_elems_nlmsg_build_payload);
224 
225 static int nft_set_elem_parse_attr_cb(const struct nlattr *attr, void *data)
226 {
227  const struct nlattr **tb = data;
228  int type = mnl_attr_get_type(attr);
229 
230  if (mnl_attr_type_valid(attr, NFTA_SET_MAX) < 0)
231  return MNL_CB_OK;
232 
233  switch(type) {
234  case NFTA_SET_ELEM_FLAGS:
235  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
236  perror("mnl_attr_validate");
237  return MNL_CB_ERROR;
238  }
239  break;
240  case NFTA_SET_ELEM_KEY:
241  case NFTA_SET_ELEM_DATA:
242  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
243  perror("mnl_attr_validate");
244  return MNL_CB_ERROR;
245  }
246  break;
247  }
248 
249  tb[type] = attr;
250  return MNL_CB_OK;
251 }
252 
253 static int nft_set_elems_parse2(struct nft_set *s, const struct nlattr *nest)
254 {
255  struct nlattr *tb[NFTA_SET_ELEM_MAX+1] = {};
256  struct nft_set_elem *e;
257  int ret = 0, type;
258 
259  e = nft_set_elem_alloc();
260  if (e == NULL)
261  return -1;
262 
263  if (mnl_attr_parse_nested(nest, nft_set_elem_parse_attr_cb, tb) < 0) {
264  nft_set_elem_free(e);
265  return -1;
266  }
267 
268  if (tb[NFTA_SET_ELEM_FLAGS]) {
269  e->set_elem_flags =
270  ntohl(mnl_attr_get_u32(tb[NFTA_SET_ELEM_FLAGS]));
271  e->flags |= (1 << NFT_SET_ELEM_ATTR_FLAGS);
272  }
273  if (tb[NFTA_SET_ELEM_KEY]) {
274  ret = nft_parse_data(&e->key, tb[NFTA_SET_ELEM_KEY], &type);
275  e->flags |= (1 << NFT_SET_ELEM_ATTR_KEY);
276  }
277  if (tb[NFTA_SET_ELEM_DATA]) {
278  ret = nft_parse_data(&e->data, tb[NFTA_SET_ELEM_DATA], &type);
279  switch(type) {
280  case DATA_VERDICT:
281  e->flags |= (1 << NFT_SET_ELEM_ATTR_VERDICT);
282  break;
283  case DATA_CHAIN:
284  e->flags |= (1 << NFT_SET_ELEM_ATTR_VERDICT) |
285  (1 << NFT_SET_ELEM_ATTR_CHAIN);
286  break;
287  case DATA_VALUE:
288  e->flags |= (1 << NFT_SET_ELEM_ATTR_DATA);
289  break;
290  }
291  }
292  if (ret < 0) {
293  xfree(e);
294  return -1;
295  }
296 
297  /* Add this new element to this set */
298  list_add_tail(&e->head, &s->element_list);
299 
300  return ret;
301 }
302 
303 static int
304 nft_set_elem_list_parse_attr_cb(const struct nlattr *attr, void *data)
305 {
306  const struct nlattr **tb = data;
307  int type = mnl_attr_get_type(attr);
308 
309  if (mnl_attr_type_valid(attr, NFTA_SET_ELEM_LIST_MAX) < 0)
310  return MNL_CB_OK;
311 
312  switch(type) {
313  case NFTA_SET_ELEM_LIST_TABLE:
314  case NFTA_SET_ELEM_LIST_SET:
315  if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
316  perror("mnl_attr_validate");
317  return MNL_CB_ERROR;
318  }
319  break;
320  case NFTA_SET_ELEM_LIST_ELEMENTS:
321  if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
322  perror("mnl_attr_validate");
323  return MNL_CB_ERROR;
324  }
325  break;
326  }
327 
328  tb[type] = attr;
329  return MNL_CB_OK;
330 }
331 
332 static int nft_set_elems_parse(struct nft_set *s, const struct nlattr *nest)
333 {
334  struct nlattr *attr;
335  int ret = 0;
336 
337  mnl_attr_for_each_nested(attr, nest) {
338  if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM)
339  return -1;
340 
341  ret = nft_set_elems_parse2(s, attr);
342  }
343  return ret;
344 }
345 
346 int nft_set_elems_nlmsg_parse(const struct nlmsghdr *nlh, struct nft_set *s)
347 {
348  struct nlattr *tb[NFTA_SET_ELEM_LIST_MAX+1] = {};
349  struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
350  int ret = 0;
351 
352  if (mnl_attr_parse(nlh, sizeof(*nfg),
353  nft_set_elem_list_parse_attr_cb, tb) < 0)
354  return -1;
355 
356  if (tb[NFTA_SET_ELEM_LIST_TABLE]) {
357  s->table =
358  strdup(mnl_attr_get_str(tb[NFTA_SET_ELEM_LIST_TABLE]));
359  s->flags |= (1 << NFT_SET_ATTR_TABLE);
360  }
361  if (tb[NFTA_SET_ELEM_LIST_SET]) {
362  s->name =
363  strdup(mnl_attr_get_str(tb[NFTA_SET_ELEM_LIST_SET]));
364  s->flags |= (1 << NFT_SET_ATTR_NAME);
365  }
366  if (tb[NFTA_SET_ELEM_LIST_SET_ID]) {
367  s->id = ntohl(mnl_attr_get_u32(tb[NFTA_SET_ELEM_LIST_SET_ID]));
368  s->flags |= (1 << NFT_SET_ATTR_ID);
369  }
370  if (tb[NFTA_SET_ELEM_LIST_ELEMENTS])
371  ret = nft_set_elems_parse(s, tb[NFTA_SET_ELEM_LIST_ELEMENTS]);
372 
373  s->family = nfg->nfgen_family;
374  s->flags |= (1 << NFT_SET_ATTR_FAMILY);
375 
376  return ret;
377 }
378 EXPORT_SYMBOL(nft_set_elems_nlmsg_parse);
379 
380 #ifdef XML_PARSING
381 int nft_mxml_set_elem_parse(mxml_node_t *tree, struct nft_set_elem *e,
382  struct nft_parse_err *err)
383 {
384  int set_elem_data;
385  uint32_t set_elem_flags;
386 
387  if (nft_mxml_num_parse(tree, "flags", MXML_DESCEND_FIRST, BASE_DEC,
388  &set_elem_flags, NFT_TYPE_U32, NFT_XML_MAND,
389  err) == 0)
390  nft_set_elem_attr_set_u32(e, NFT_SET_ELEM_ATTR_FLAGS, set_elem_flags);
391 
392  if (nft_mxml_data_reg_parse(tree, "key", &e->key,
393  NFT_XML_MAND, err) == DATA_VALUE)
394  e->flags |= (1 << NFT_SET_ELEM_ATTR_KEY);
395 
396  /* <set_elem_data> is not mandatory */
397  set_elem_data = nft_mxml_data_reg_parse(tree, "data",
398  &e->data, NFT_XML_OPT, err);
399  switch (set_elem_data) {
400  case DATA_VALUE:
401  e->flags |= (1 << NFT_SET_ELEM_ATTR_DATA);
402  break;
403  case DATA_VERDICT:
404  e->flags |= (1 << NFT_SET_ELEM_ATTR_VERDICT);
405  if (e->data.chain != NULL)
406  e->flags |= (1 << NFT_SET_ELEM_ATTR_CHAIN);
407 
408  break;
409  }
410 
411  return 0;
412 }
413 #endif
414 
415 static int nft_set_elem_xml_parse(struct nft_set_elem *e, const void *xml,
416  struct nft_parse_err *err,
417  enum nft_parse_input input)
418 {
419 #ifdef XML_PARSING
420  mxml_node_t *tree;
421  int ret;
422 
423  tree = nft_mxml_build_tree(xml, "set_elem", err, input);
424  if (tree == NULL)
425  return -1;
426 
427  ret = nft_mxml_set_elem_parse(tree, e, err);
428  mxmlDelete(tree);
429  return ret;
430 #else
431  errno = EOPNOTSUPP;
432  return -1;
433 #endif
434 }
435 
436 static int nft_set_elem_json_parse(struct nft_set_elem *e, const void *json,
437  struct nft_parse_err *err,
438  enum nft_parse_input input)
439 {
440 #ifdef JSON_PARSING
441  json_t *tree;
442  json_error_t error;
443 
444  tree = nft_jansson_create_root(json, &error, err, input);
445  if (tree == NULL)
446  return -1;
447 
448  return nft_jansson_set_elem_parse(e, tree, err);
449 #else
450  errno = EOPNOTSUPP;
451  return -1;
452 #endif
453 }
454 
455 static int
456 nft_set_elem_do_parse(struct nft_set_elem *e, enum nft_parse_type type,
457  const void *data, struct nft_parse_err *err,
458  enum nft_parse_input input)
459 {
460  int ret;
461 
462  switch (type) {
463  case NFT_PARSE_XML:
464  ret = nft_set_elem_xml_parse(e, data, err, input);
465  break;
466  case NFT_PARSE_JSON:
467  ret = nft_set_elem_json_parse(e, data, err, input);
468  break;
469  default:
470  errno = EOPNOTSUPP;
471  ret = -1;
472  break;
473  }
474 
475  return ret;
476 }
477 int nft_set_elem_parse(struct nft_set_elem *e, enum nft_parse_type type,
478  const char *data, struct nft_parse_err *err)
479 {
480  return nft_set_elem_do_parse(e, type, data, err, NFT_PARSE_BUFFER);
481 }
482 EXPORT_SYMBOL(nft_set_elem_parse);
483 
484 int nft_set_elem_parse_file(struct nft_set_elem *e, enum nft_parse_type type,
485  FILE *fp, struct nft_parse_err *err)
486 {
487  return nft_set_elem_do_parse(e, type, fp, err, NFT_PARSE_FILE);
488 }
489 EXPORT_SYMBOL(nft_set_elem_parse_file);
490 
491 static int nft_set_elem_snprintf_json(char *buf, size_t size,
492  struct nft_set_elem *e, uint32_t flags)
493 {
494  int ret, len = size, offset = 0, type = -1;
495 
496  if (e->flags & (1 << NFT_SET_ELEM_ATTR_FLAGS)) {
497  ret = snprintf(buf, len, "\"flags\":%u,", e->set_elem_flags);
498  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
499  }
500 
501  ret = snprintf(buf + offset, len, "\"key\":{");
502  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
503 
504  ret = nft_data_reg_snprintf(buf + offset, len, &e->key,
505  NFT_OUTPUT_JSON, flags, DATA_VALUE);
506  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
507 
508  ret = snprintf(buf + offset, len, "}");
509  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
510 
511  if (e->flags & (1 << NFT_SET_ELEM_ATTR_DATA))
512  type = DATA_VALUE;
513  else if (e->flags & (1 << NFT_SET_ELEM_ATTR_CHAIN))
514  type = DATA_CHAIN;
515  else if (e->flags & (1 << NFT_SET_ELEM_ATTR_VERDICT))
516  type = DATA_VERDICT;
517 
518  if (type != -1) {
519  ret = snprintf(buf + offset, len, ",\"data\":{");
520  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
521 
522  ret = nft_data_reg_snprintf(buf + offset, len, &e->data,
523  NFT_OUTPUT_JSON, flags, type);
524  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
525 
526  ret = snprintf(buf + offset, len, "}");
527  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
528  }
529 
530  return offset;
531 }
532 
533 static int nft_set_elem_snprintf_default(char *buf, size_t size,
534  struct nft_set_elem *e)
535 {
536  int ret, len = size, offset = 0, i;
537 
538  ret = snprintf(buf, len, "element ");
539  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
540 
541  for (i = 0; i < div_round_up(e->key.len, sizeof(uint32_t)); i++) {
542  ret = snprintf(buf+offset, len, "%.8x ", e->key.val[i]);
543  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
544  }
545 
546  ret = snprintf(buf+offset, len, " : ");
547  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
548 
549  for (i = 0; i < div_round_up(e->data.len, sizeof(uint32_t)); i++) {
550  ret = snprintf(buf+offset, len, "%.8x ", e->data.val[i]);
551  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
552  }
553 
554  ret = snprintf(buf+offset, len, "%u [end]", e->set_elem_flags);
555  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
556 
557  return offset;
558 }
559 
560 static int nft_set_elem_snprintf_xml(char *buf, size_t size,
561  struct nft_set_elem *e, uint32_t flags)
562 {
563  int ret, len = size, offset = 0, type = DATA_NONE;
564 
565  ret = snprintf(buf, size, "<set_elem>");
566  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
567 
568  if (e->flags & (1 << NFT_SET_ELEM_ATTR_FLAGS)) {
569  ret = snprintf(buf + offset, size, "<flags>%u</flags>",
570  e->set_elem_flags);
571  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
572  }
573 
574  if (e->flags & (1 << NFT_SET_ELEM_ATTR_KEY)) {
575  ret = snprintf(buf + offset, len, "<key>");
576  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
577 
578  ret = nft_data_reg_snprintf(buf + offset, len, &e->key,
579  NFT_OUTPUT_XML, flags, DATA_VALUE);
580  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
581 
582  ret = snprintf(buf + offset, len, "</key>");
583  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
584  }
585 
586  if (e->flags & (1 << NFT_SET_ELEM_ATTR_DATA))
587  type = DATA_VALUE;
588  else if (e->flags & (1 << NFT_SET_ELEM_ATTR_CHAIN))
589  type = DATA_CHAIN;
590  else if (e->flags & (1 << NFT_SET_ELEM_ATTR_VERDICT))
591  type = DATA_VERDICT;
592 
593  if (type != DATA_NONE) {
594  ret = snprintf(buf + offset, len, "<data>");
595  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
596 
597  ret = nft_data_reg_snprintf(buf + offset, len, &e->data,
598  NFT_OUTPUT_XML, flags, type);
599  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
600 
601  ret = snprintf(buf + offset, len, "</data>");
602  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
603  }
604 
605  ret = snprintf(buf + offset, len, "</set_elem>");
606  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
607 
608  return offset;
609 }
610 
611 int nft_set_elem_snprintf(char *buf, size_t size, struct nft_set_elem *e,
612  uint32_t type, uint32_t flags)
613 {
614  int ret, len = size, offset = 0;
615 
616  ret = nft_event_header_snprintf(buf+offset, len, type, flags);
617  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
618 
619  switch(type) {
620  case NFT_OUTPUT_DEFAULT:
621  ret = nft_set_elem_snprintf_default(buf+offset, len, e);
622  break;
623  case NFT_OUTPUT_XML:
624  ret = nft_set_elem_snprintf_xml(buf+offset, len, e, flags);
625  break;
626  case NFT_OUTPUT_JSON:
627  ret = nft_set_elem_snprintf_json(buf+offset, len, e, flags);
628  break;
629  default:
630  return -1;
631  }
632 
633  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
634 
635  ret = nft_event_footer_snprintf(buf+offset, len, type, flags);
636  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
637 
638  return offset;
639 }
640 EXPORT_SYMBOL(nft_set_elem_snprintf);
641 
642 static inline int nft_set_elem_do_snprintf(char *buf, size_t size, void *e,
643  uint32_t type, uint32_t flags)
644 {
645  return nft_set_elem_snprintf(buf, size, e, type, flags);
646 }
647 
648 int nft_set_elem_fprintf(FILE *fp, struct nft_set_elem *se, uint32_t type,
649  uint32_t flags)
650 {
651  return nft_fprintf(fp, se, type, flags, nft_set_elem_do_snprintf);
652 }
653 EXPORT_SYMBOL(nft_set_elem_fprintf);
654 
655 int nft_set_elem_foreach(struct nft_set *s,
656  int (*cb)(struct nft_set_elem *e, void *data),
657  void *data)
658 {
659  struct nft_set_elem *elem;
660  int ret;
661 
662  list_for_each_entry(elem, &s->element_list, head) {
663  ret = cb(elem, data);
664  if (ret < 0)
665  return ret;
666  }
667  return 0;
668 }
669 EXPORT_SYMBOL(nft_set_elem_foreach);
670 
672  struct list_head *list;
673  struct nft_set_elem *cur;
674 };
675 
676 struct nft_set_elems_iter *nft_set_elems_iter_create(struct nft_set *s)
677 {
678  struct nft_set_elems_iter *iter;
679 
680  iter = calloc(1, sizeof(struct nft_set_elems_iter));
681  if (iter == NULL)
682  return NULL;
683 
684  iter->list = &s->element_list;
685  iter->cur = list_entry(s->element_list.next, struct nft_set_elem, head);
686 
687  return iter;
688 }
689 EXPORT_SYMBOL(nft_set_elems_iter_create);
690 
691 struct nft_set_elem *nft_set_elems_iter_cur(struct nft_set_elems_iter *iter)
692 {
693  return iter->cur;
694 }
695 EXPORT_SYMBOL(nft_set_elems_iter_cur);
696 
697 struct nft_set_elem *nft_set_elems_iter_next(struct nft_set_elems_iter *iter)
698 {
699  struct nft_set_elem *s = iter->cur;
700 
701  iter->cur = list_entry(iter->cur->head.next, struct nft_set_elem, head);
702  if (&iter->cur->head == iter->list->next)
703  return NULL;
704 
705  return s;
706 }
707 EXPORT_SYMBOL(nft_set_elems_iter_next);
708 
709 void nft_set_elems_iter_destroy(struct nft_set_elems_iter *iter)
710 {
711  xfree(iter);
712 }
713 EXPORT_SYMBOL(nft_set_elems_iter_destroy);