1/*
2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include <stdlib.h>
11#include <string.h> /* for memset */
12#include <errno.h>
13#include <assert.h>
14
15#include "internal/internal.h"
16
17/**
18 * \defgroup exp Expect object handling
19 * @{
20 */
21
22/**
23 * nfexp_new - allocate a new expectation
24 *
25 * In case of success, this function returns a valid pointer to a memory blob,
26 * otherwise NULL is returned and errno is set appropiately.
27 */
28struct nf_expect *nfexp_new(void)
29{
30	struct nf_expect *exp;
31
32	exp = malloc(sizeof(struct nf_expect));
33	if (!exp)
34		return NULL;
35
36	memset(exp, 0, sizeof(struct nf_expect));
37
38	return exp;
39}
40
41/**
42 * nfexp_destroy - release an expectation object
43 * \param exp pointer to the expectation object
44 */
45void nfexp_destroy(struct nf_expect *exp)
46{
47	assert(exp != NULL);
48	free(exp);
49	exp = NULL; /* bugtrap */
50}
51
52/**
53 * nfexp_sizeof - return the size in bytes of a certain expect object
54 * \param exp pointer to the expect object
55 */
56size_t nfexp_sizeof(const struct nf_expect *exp)
57{
58	assert(exp != NULL);
59	return sizeof(*exp);
60}
61
62/**
63 * nfexp_maxsize - return the maximum size in bytes of a expect object
64 *
65 * Use this function if you want to allocate a expect object in the stack
66 * instead of the heap. For example:
67 *
68 * char buf[nfexp_maxsize()];
69 * struct nf_expect *exp = (struct nf_expect *) buf;
70 * memset(exp, 0, nfexp_maxsize());
71 *
72 * Note: As for now this function returns the same size that nfexp_sizeof(exp)
73 * does although _this could change in the future_. Therefore, do not assume
74 * that nfexp_sizeof(exp) == nfexp_maxsize().
75 */
76size_t nfexp_maxsize(void)
77{
78	return sizeof(struct nf_expect);
79}
80
81/**
82 * nfexp_clone - clone a expectation object
83 * \param exp pointer to a valid expectation object
84 *
85 * On error, NULL is returned and errno is appropiately set. Otherwise,
86 * a valid pointer to the clone expect is returned.
87 */
88struct nf_expect *nfexp_clone(const struct nf_expect *exp)
89{
90	struct nf_expect *clone;
91
92	assert(exp != NULL);
93
94	if ((clone = nfexp_new()) == NULL)
95		return NULL;
96	memcpy(clone, exp, sizeof(*exp));
97
98	return clone;
99}
100
101/**
102 * nfexp_cmp - compare two expectation objects
103 * \param exp1 pointer to a valid expectation object
104 * \param exp2 pointer to a valid expectation object
105 * \param flags flags
106 *
107 * This function only compare attribute set in both objects, by default
108 * the comparison is not strict, ie. if a certain attribute is not set in one
109 * of the objects, then such attribute is not used in the comparison.
110 * If you want more strict comparisons, you can use the appropriate flags
111 * to modify this behaviour (see NFCT_CMP_STRICT and NFCT_CMP_MASK).
112 *
113 * The available flags are:
114 *      - NFCT_CMP_STRICT: the compared objects must have the same attributes
115 *      and the same values, otherwise it returns that the objects are
116 *      different.
117 *      - NFCT_CMP_MASK: the first object is used as mask, this means that
118 *      if an attribute is present in exp1 but not in exp2, this function
119 *      returns that the objects are different.
120 *
121 * Other existing flags that are used by nfct_cmp() are ignored.
122 *
123 * If both conntrack object are equal, this function returns 1, otherwise
124 * 0 is returned.
125 */
126int nfexp_cmp(const struct nf_expect *exp1, const struct nf_expect *exp2,
127	      unsigned int flags)
128{
129        assert(exp1 != NULL);
130        assert(exp2 != NULL);
131
132        return __cmp_expect(exp1, exp2, flags);
133}
134
135/**
136 * @}
137 */
138
139/**
140 * \defgroup LibrarySetup Library setup
141 * @{
142 */
143
144/**
145 * nfexp_callback_register - register a callback
146 * \param h library handler
147 * \param cb callback used to process expect received
148 * \param data data used by the callback, if any.
149 *
150 * This function register a callback to handle the expect received,
151 * in case of error -1 is returned and errno is set appropiately, otherwise
152 * 0 is returned.
153 *
154 * Note that the data parameter is optional, if you do not want to pass any
155 * data to your callback, then use NULL.
156 */
157int nfexp_callback_register(struct nfct_handle *h,
158			    enum nf_conntrack_msg_type type,
159			    int (*cb)(enum nf_conntrack_msg_type type,
160			   	      struct nf_expect *exp,
161				      void *data),
162			   void *data)
163{
164	struct __data_container *container;
165
166	assert(h != NULL);
167
168	container = malloc(sizeof(struct __data_container));
169	if (!container)
170		return -1;
171	memset(container, 0, sizeof(struct __data_container));
172
173	h->expect_cb = cb;
174	container->h = h;
175	container->type = type;
176	container->data = data;
177
178	h->nfnl_cb_exp.call = __callback;
179	h->nfnl_cb_exp.data = container;
180	h->nfnl_cb_exp.attr_count = CTA_EXPECT_MAX;
181
182	nfnl_callback_register(h->nfnlssh_exp,
183			       IPCTNL_MSG_EXP_NEW,
184			       &h->nfnl_cb_exp);
185
186	nfnl_callback_register(h->nfnlssh_exp,
187			       IPCTNL_MSG_EXP_DELETE,
188			       &h->nfnl_cb_exp);
189
190	return 0;
191}
192
193/**
194 * nfexp_callback_unregister - unregister a callback
195 * \param h library handler
196 */
197void nfexp_callback_unregister(struct nfct_handle *h)
198{
199	assert(h != NULL);
200
201	nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_NEW);
202	nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE);
203
204	h->expect_cb = NULL;
205	free(h->nfnl_cb_exp.data);
206
207	h->nfnl_cb_exp.call = NULL;
208	h->nfnl_cb_exp.data = NULL;
209	h->nfnl_cb_exp.attr_count = 0;
210}
211
212/**
213 * nfexp_callback_register2 - register a callback
214 * \param h library handler
215 * \param cb callback used to process expect received
216 * \param data data used by the callback, if any.
217 *
218 * This function register a callback to handle the expect received,
219 * in case of error -1 is returned and errno is set appropiately, otherwise
220 * 0 is returned.
221 *
222 * Note that the data parameter is optional, if you do not want to pass any
223 * data to your callback, then use NULL.
224 *
225 * NOTICE: The difference with nfexp_callback_register() is that this function
226 * uses the new callback interface that includes the Netlink header.
227 *
228 * WARNING: Don't mix nfexp_callback_register() and nfexp_callback_register2()
229 * calls, use only once at a time.
230 */
231int nfexp_callback_register2(struct nfct_handle *h,
232			     enum nf_conntrack_msg_type type,
233			     int (*cb)(const struct nlmsghdr *nlh,
234			     	       enum nf_conntrack_msg_type type,
235			   	       struct nf_expect *exp,
236				       void *data),
237			     void *data)
238{
239	struct __data_container *container;
240
241	assert(h != NULL);
242
243	container = malloc(sizeof(struct __data_container));
244	if (!container)
245		return -1;
246	memset(container, 0, sizeof(struct __data_container));
247
248	h->expect_cb2 = cb;
249	container->h = h;
250	container->type = type;
251	container->data = data;
252
253	h->nfnl_cb_exp.call = __callback;
254	h->nfnl_cb_exp.data = container;
255	h->nfnl_cb_exp.attr_count = CTA_EXPECT_MAX;
256
257	nfnl_callback_register(h->nfnlssh_exp,
258			       IPCTNL_MSG_EXP_NEW,
259			       &h->nfnl_cb_exp);
260
261	nfnl_callback_register(h->nfnlssh_exp,
262			       IPCTNL_MSG_EXP_DELETE,
263			       &h->nfnl_cb_exp);
264
265	return 0;
266}
267
268/**
269 * nfexp_callback_unregister2 - unregister a callback
270 * \param h library handler
271 */
272void nfexp_callback_unregister2(struct nfct_handle *h)
273{
274	assert(h != NULL);
275
276	nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_NEW);
277	nfnl_callback_unregister(h->nfnlssh_exp, IPCTNL_MSG_EXP_DELETE);
278
279	h->expect_cb2 = NULL;
280	free(h->nfnl_cb_exp.data);
281
282	h->nfnl_cb_exp.call = NULL;
283	h->nfnl_cb_exp.data = NULL;
284	h->nfnl_cb_exp.attr_count = 0;
285}
286
287/**
288 * @}
289 */
290
291/**
292 * \defgroup exp Expect object handling
293 * @{
294 */
295
296/**
297 * nfexp_set_attr - set the value of a certain expect attribute
298 * \param exp pointer to a valid expect
299 * \param type attribute type
300 * \param value pointer to the attribute value
301 *
302 * Note that certain attributes are unsettable:
303 * 	- ATTR_EXP_USE
304 * 	- ATTR_EXP_ID
305 * 	- ATTR_EXP_*_COUNTER_*
306 * The call of this function for such attributes do nothing.
307 */
308void nfexp_set_attr(struct nf_expect *exp,
309		    const enum nf_expect_attr type,
310		    const void *value)
311{
312	assert(exp != NULL);
313	assert(value != NULL);
314
315	if (type >= ATTR_EXP_MAX)
316		return;
317
318	if (set_exp_attr_array[type]) {
319		set_exp_attr_array[type](exp, value);
320		set_bit(type, exp->set);
321	}
322}
323
324/**
325 * nfexp_set_attr_u8 - set the value of a certain expect attribute
326 * \param exp pointer to a valid expect
327 * \param type attribute type
328 * \param value unsigned 8 bits attribute value
329 */
330void nfexp_set_attr_u8(struct nf_expect *exp,
331		       const enum nf_expect_attr type,
332		       uint8_t value)
333{
334	nfexp_set_attr(exp, type, &value);
335}
336
337/**
338 * nfexp_set_attr_u16 - set the value of a certain expect attribute
339 * \param exp pointer to a valid expect
340 * \param type attribute type
341 * \param value unsigned 16 bits attribute value
342 */
343void nfexp_set_attr_u16(struct nf_expect *exp,
344			const enum nf_expect_attr type,
345			uint16_t value)
346{
347	nfexp_set_attr(exp, type, &value);
348}
349
350/**
351 * nfexp_set_attr_u32 - set the value of a certain expect attribute
352 * \param exp pointer to a valid expect
353 * \param type attribute type
354 * \param value unsigned 32 bits attribute value
355 */
356void nfexp_set_attr_u32(struct nf_expect *exp,
357			const enum nf_expect_attr type,
358			uint32_t value)
359{
360	nfexp_set_attr(exp, type, &value);
361}
362
363/**
364 * nfexp_get_attr - get an expect attribute
365 * \param exp pointer to a valid expect
366 * \param type attribute type
367 *
368 * In case of success a valid pointer to the attribute requested is returned,
369 * on error NULL is returned and errno is set appropiately.
370 */
371const void *nfexp_get_attr(const struct nf_expect *exp,
372			   const enum nf_expect_attr type)
373{
374	assert(exp != NULL);
375
376	if (type >= ATTR_EXP_MAX) {
377		errno = EINVAL;
378		return NULL;
379	}
380
381	if (!test_bit(type, exp->set)) {
382		errno = ENODATA;
383		return NULL;
384	}
385
386	return get_exp_attr_array[type](exp);
387}
388
389/**
390 * nfexp_get_attr_u8 - get attribute of unsigned 8-bits long
391 * \param exp pointer to a valid expectation
392 * \param type attribute type
393 *
394 * Returns the value of the requested attribute, if the attribute is not
395 * set, 0 is returned. In order to check if the attribute is set or not,
396 * use nfexp_attr_is_set.
397 */
398uint8_t nfexp_get_attr_u8(const struct nf_expect *exp,
399			   const enum nf_expect_attr type)
400{
401	const uint8_t *ret = nfexp_get_attr(exp, type);
402	return ret == NULL ? 0 : *ret;
403}
404
405/**
406 * nfexp_get_attr_u16 - get attribute of unsigned 16-bits long
407 * \param exp pointer to a valid expectation
408 * \param type attribute type
409 *
410 * Returns the value of the requested attribute, if the attribute is not
411 * set, 0 is returned. In order to check if the attribute is set or not,
412 * use nfexp_attr_is_set.
413 */
414uint16_t nfexp_get_attr_u16(const struct nf_expect *exp,
415			     const enum nf_expect_attr type)
416{
417	const uint16_t *ret = nfexp_get_attr(exp, type);
418	return ret == NULL ? 0 : *ret;
419}
420
421/**
422 * nfexp_get_attr_u32 - get attribute of unsigned 32-bits long
423 * \param exp pointer to a valid expectation
424 * \param type attribute type
425 *
426 * Returns the value of the requested attribute, if the attribute is not
427 * set, 0 is returned. In order to check if the attribute is set or not,
428 * use nfexp_attr_is_set.
429 */
430uint32_t nfexp_get_attr_u32(const struct nf_expect *exp,
431			    const enum nf_expect_attr type)
432{
433	const uint32_t *ret = nfexp_get_attr(exp, type);
434	return ret == NULL ? 0 : *ret;
435}
436
437/**
438 * nfexp_attr_is_set - check if a certain attribute is set
439 * \param exp pointer to a valid expectation object
440 * \param type attribute type
441 *
442 * On error, -1 is returned and errno is set appropiately, otherwise
443 * the value of the attribute is returned.
444 */
445int nfexp_attr_is_set(const struct nf_expect *exp,
446		      const enum nf_expect_attr type)
447{
448	assert(exp != NULL);
449
450	if (type >= ATTR_EXP_MAX) {
451		errno = EINVAL;
452		return -1;
453	}
454	return test_bit(type, exp->set);
455}
456
457/**
458 * nfexp_attr_unset - unset a certain attribute
459 * \param type attribute type
460 * \param exp pointer to a valid expectation object
461 *
462 * On error, -1 is returned and errno is set appropiately, otherwise
463 * 0 is returned.
464 */
465int nfexp_attr_unset(struct nf_expect *exp,
466		     const enum nf_expect_attr type)
467{
468	assert(exp != NULL);
469
470	if (type >= ATTR_EXP_MAX) {
471		errno = EINVAL;
472		return -1;
473	}
474	unset_bit(type, exp->set);
475
476	return 0;
477}
478
479/**
480 * @}
481 */
482
483/**
484 * \defgroup nl Low level object to Netlink message
485 * @{
486 */
487
488/**
489 * nfexp_build_expect - build a netlink message from a conntrack object
490 * \param ssh nfnetlink subsystem handler
491 * \param req buffer used to build the netlink message
492 * \param size size of the buffer passed
493 * \param type netlink message type
494 * \param flags netlink flags
495 * \param exp pointer to a conntrack object
496 *
497 * This is a low level function for those that require to be close to
498 * netlink details via libnfnetlink. If you do want to obviate the netlink
499 * details then we suggest you to use nfexp_query.
500 *
501 * On error, -1 is returned and errno is appropiately set.
502 * On success, 0 is returned.
503 */
504int nfexp_build_expect(struct nfnl_subsys_handle *ssh,
505		       void *req,
506		       size_t size,
507		       uint16_t type,
508		       uint16_t flags,
509		       const struct nf_expect *exp)
510{
511	assert(ssh != NULL);
512	assert(req != NULL);
513	assert(exp != NULL);
514
515	return __build_expect(ssh, req, size, type, flags, exp);
516}
517
518static int
519__build_query_exp(struct nfnl_subsys_handle *ssh,
520		  const enum nf_conntrack_query qt,
521		  const void *data, void *buffer, unsigned int size)
522{
523	struct nfnlhdr *req = buffer;
524	const uint8_t *family = data;
525
526	assert(ssh != NULL);
527	assert(data != NULL);
528	assert(req != NULL);
529
530	memset(req, 0, size);
531
532	switch(qt) {
533	case NFCT_Q_CREATE:
534		__build_expect(ssh, req, size, IPCTNL_MSG_EXP_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL, data);
535		break;
536	case NFCT_Q_CREATE_UPDATE:
537		__build_expect(ssh, req, size, IPCTNL_MSG_EXP_NEW, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK, data);
538		break;
539	case NFCT_Q_GET:
540		__build_expect(ssh, req, size, IPCTNL_MSG_EXP_GET, NLM_F_REQUEST|NLM_F_ACK, data);
541		break;
542	case NFCT_Q_DESTROY:
543		__build_expect(ssh, req, size, IPCTNL_MSG_EXP_DELETE, NLM_F_REQUEST|NLM_F_ACK, data);
544		break;
545	case NFCT_Q_FLUSH:
546		nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_EXP_DELETE, NLM_F_REQUEST|NLM_F_ACK);
547		break;
548	case NFCT_Q_DUMP:
549		nfnl_fill_hdr(ssh, &req->nlh, 0, *family, 0, IPCTNL_MSG_EXP_GET, NLM_F_REQUEST|NLM_F_DUMP);
550		break;
551	default:
552		errno = ENOTSUP;
553		return -1;
554	}
555	return 1;
556}
557
558/**
559 * nfexp_build_query - build a query in netlink message format for ctnetlink
560 * \param ssh nfnetlink subsystem handler
561 * \param qt query type
562 * \param data data required to build the query
563 * \param req buffer to build the netlink message
564 * \param size size of the buffer passed
565 *
566 * This is a low level function, use it if you want to require to work
567 * with netlink details via libnfnetlink, otherwise we suggest you to
568 * use nfexp_query.
569 *
570 * The pointer to data can be a conntrack object or the protocol family
571 * depending on the request.
572 *
573 * For query types:
574 * 	NFEXP_Q_CREATE
575 * 	NFEXP_Q_DESTROY
576 *
577 * Pass a valid pointer to an expectation object.
578 *
579 * For query types:
580 * 	NFEXP_Q_FLUSH
581 * 	NFEXP_Q_DUMP
582 *
583 * Pass a valid pointer to the protocol family (uint8_t)
584 *
585 * On success, 0 is returned. On error, -1 is returned and errno is set
586 * appropiately.
587 */
588int nfexp_build_query(struct nfnl_subsys_handle *ssh,
589		      const enum nf_conntrack_query qt,
590		      const void *data,
591		      void *buffer,
592		      unsigned int size)
593{
594	return __build_query_exp(ssh, qt, data, buffer, size);
595}
596
597/**
598 * nfexp_parse_expect - translate a netlink message to a conntrack object
599 * \param type do the translation iif the message type is of a certain type
600 * \param nlh pointer to the netlink message
601 * \param exp pointer to the conntrack object
602 *
603 * This is a low level function, use it in case that you require to work
604 * with netlink details via libnfnetlink. Otherwise, we suggest you to
605 * use the high level API.
606 *
607 * The message types are:
608 *
609 * NFEXP_T_NEW: parse messages with new conntracks
610 * NFEXP_T_UPDATE: parse messages with conntrack updates
611 * NFEXP_T_DESTROY: parse messages with conntrack destroy
612 * NFEXP_T_ALL: all message types
613 *
614 * The message type is a flag, therefore the can be combined, ie.
615 * NFEXP_T_NEW | NFEXP_T_DESTROY to parse only new and destroy messages
616 *
617 * On error, NFEXP_T_ERROR is returned and errno is set appropiately. If
618 * the message received is not of the requested type then 0 is returned,
619 * otherwise this function returns the message type parsed.
620 */
621int nfexp_parse_expect(enum nf_conntrack_msg_type type,
622		       const struct nlmsghdr *nlh,
623		       struct nf_expect *exp)
624{
625	unsigned int flags;
626	int len = nlh->nlmsg_len;
627	struct nfgenmsg *nfhdr = NLMSG_DATA(nlh);
628	struct nfattr *cda[CTA_EXPECT_MAX];
629
630	assert(nlh != NULL);
631	assert(exp != NULL);
632
633	len -= NLMSG_LENGTH(sizeof(struct nfgenmsg));
634	if (len < 0) {
635		errno = EINVAL;
636		return NFCT_T_ERROR;
637	}
638
639	flags = __parse_expect_message_type(nlh);
640	if (!(flags & type))
641		return 0;
642
643	nfnl_parse_attr(cda, CTA_EXPECT_MAX, NFA_DATA(nfhdr), len);
644
645	__parse_expect(nlh, cda, exp);
646
647	return flags;
648}
649
650/**
651 * @}
652 */
653
654/**
655 * \defgroup cmd Send commands to kernel-space and receive replies
656 * @{
657 */
658
659/**
660 * nfexp_query - send a query to ctnetlink
661 * \param h library handler
662 * \param qt query type
663 * \param data data required to send the query
664 *
665 * On error, -1 is returned and errno is explicitely set. On success, 0
666 * is returned.
667 */
668int nfexp_query(struct nfct_handle *h,
669	        const enum nf_conntrack_query qt,
670	        const void *data)
671{
672	const size_t size = 4096;	/* enough for now */
673	union {
674		char buffer[size];
675		struct nfnlhdr req;
676	} u;
677
678	assert(h != NULL);
679	assert(data != NULL);
680
681	if (__build_query_exp(h->nfnlssh_exp, qt, data, &u.req, size) == -1)
682		return -1;
683
684	return nfnl_query(h->nfnlh, &u.req.nlh);
685}
686
687/**
688 * nfexp_send - send a query to ctnetlink
689 * \param h library handler
690 * \param qt query type
691 * \param data data required to send the query
692 *
693 * Like nfexp_query but we do not wait for the reply from ctnetlink.
694 * You can use nfexp_send() and nfexp_catch() to emulate nfexp_query().
695 * This is particularly useful when the socket is non-blocking.
696 *
697 * On error, -1 is returned and errno is explicitely set. On success, 0
698 * is returned.
699 */
700int nfexp_send(struct nfct_handle *h,
701	       const enum nf_conntrack_query qt,
702	       const void *data)
703{
704	const size_t size = 4096;	/* enough for now */
705	union {
706		char buffer[size];
707		struct nfnlhdr req;
708	} u;
709
710	assert(h != NULL);
711	assert(data != NULL);
712
713	if (__build_query_exp(h->nfnlssh_exp, qt, data, &u.req, size) == -1)
714		return -1;
715
716	return nfnl_send(h->nfnlh, &u.req.nlh);
717}
718
719/**
720 * nfexp_catch - catch events
721 * \param h library handler
722 *
723 * This function receives the event from the kernel and it invokes the
724 * callback that was registered to this handle.
725 *
726 * On error, -1 is returned and errno is set appropiately. On success,
727 * a value greater or equal to 0 is returned indicating the callback
728 * verdict: NFCT_CB_STOP, NFCT_CB_CONTINUE or NFCT_CB_STOLEN.
729 *
730 * Beware that this function is equivalent to nfct_catch(), so it handles both
731 * conntrack and expectation events.
732 */
733int nfexp_catch(struct nfct_handle *h)
734{
735	assert(h != NULL);
736
737	return nfnl_catch(h->nfnlh);
738}
739
740/**
741 * @}
742 */
743
744/**
745 * \defgroup exp Expect object handling
746 * @{
747 */
748
749/**
750 * nfexp_snprintf - print a conntrack object to a buffer
751 * \param buf buffer used to build the printable conntrack
752 * \param size size of the buffer
753 * \param exp pointer to a valid expectation object
754 * \param message_type print message type (NFEXP_T_UNKNOWN, NFEXP_T_NEW,...)
755 * \param output_type print type (NFEXP_O_DEFAULT, NFEXP_O_XML, ...)
756 * \param flags extra flags for the output type (NFEXP_OF_LAYER3)
757 *
758  * If you are listening to events, probably you want to display the message
759 * type as well. In that case, set the message type parameter to any of the
760 * known existing types, ie. NFEXP_T_NEW, NFEXP_T_UPDATE, NFEXP_T_DESTROY.
761 * If you pass NFEXP_T_UNKNOWN, the message type will not be output.
762 *
763 * Currently, the output available are:
764 * 	- NFEXP_O_DEFAULT: default /proc-like output
765 * 	- NFEXP_O_XML: XML output
766 *
767 * The output flags are:
768 * 	- NFEXP_O_LAYER: include layer 3 information in the output, this is
769 * 			*only* required by NFEXP_O_DEFAULT.
770 *
771 * On error, -1 is returned and errno is set appropiately. Otherwise,
772 * 0 is returned.
773 */
774int nfexp_snprintf(char *buf,
775		  unsigned int size,
776		  const struct nf_expect *exp,
777		  unsigned int msg_type,
778		  unsigned int out_type,
779		  unsigned int flags)
780{
781	assert(buf != NULL);
782	assert(size > 0);
783	assert(exp != NULL);
784
785	return __snprintf_expect(buf, size, exp, msg_type, out_type, flags);
786}
787
788/**
789 * @}
790 */
791