• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/conntrack-tools/libnetfilter_cttimeout-1.0.0/src/
1/*
2 * (C) 2012 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 Vyatta Inc. <http://www.vyatta.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
20#include <libmnl/libmnl.h>
21#include <linux/netfilter/nfnetlink.h>
22#include <linux/netfilter/nfnetlink_cttimeout.h>
23
24#include <libnetfilter_cttimeout/libnetfilter_cttimeout.h>
25
26static const char *const tcp_state_to_name[] = {
27	[NFCT_TIMEOUT_ATTR_TCP_SYN_SENT]	= "SYN_SENT",
28	[NFCT_TIMEOUT_ATTR_TCP_SYN_RECV]	= "SYN_RECV",
29	[NFCT_TIMEOUT_ATTR_TCP_ESTABLISHED]	= "ESTABLISHED",
30	[NFCT_TIMEOUT_ATTR_TCP_FIN_WAIT]	= "FIN_WAIT",
31	[NFCT_TIMEOUT_ATTR_TCP_CLOSE_WAIT]	= "CLOSE_WAIT",
32	[NFCT_TIMEOUT_ATTR_TCP_LAST_ACK]	= "LAST_ACK",
33	[NFCT_TIMEOUT_ATTR_TCP_TIME_WAIT]	= "TIME_WAIT",
34	[NFCT_TIMEOUT_ATTR_TCP_CLOSE]		= "CLOSE",
35	[NFCT_TIMEOUT_ATTR_TCP_SYN_SENT2]	= "SYN_SENT2",
36	[NFCT_TIMEOUT_ATTR_TCP_RETRANS]		= "RETRANS",
37	[NFCT_TIMEOUT_ATTR_TCP_UNACK]		= "UNACKNOWLEDGED",
38};
39
40static const char *const generic_state_to_name[] = {
41	[NFCT_TIMEOUT_ATTR_GENERIC]		= "TIMEOUT",
42};
43
44static const char *const udp_state_to_name[] = {
45	[NFCT_TIMEOUT_ATTR_UDP_UNREPLIED]	= "UNREPLIED",
46	[NFCT_TIMEOUT_ATTR_UDP_REPLIED]		= "REPLIED",
47};
48
49static const char *const sctp_state_to_name[] = {
50	[NFCT_TIMEOUT_ATTR_SCTP_CLOSED]			= "CLOSED",
51	[NFCT_TIMEOUT_ATTR_SCTP_COOKIE_WAIT]		= "COOKIE_WAIT",
52	[NFCT_TIMEOUT_ATTR_SCTP_COOKIE_ECHOED]		= "COOKIE_ECHOED",
53	[NFCT_TIMEOUT_ATTR_SCTP_ESTABLISHED]		= "ESTABLISHED",
54	[NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_SENT]		= "SHUTDOWN_SENT",
55	[NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_RECD]		= "SHUTDOWN_RECD",
56	[NFCT_TIMEOUT_ATTR_SCTP_SHUTDOWN_ACK_SENT]	= "SHUTDOWN_ACK_SENT",
57};
58
59static const char *const dccp_state_to_name[] = {
60	[NFCT_TIMEOUT_ATTR_DCCP_REQUEST]	= "REQUEST",
61	[NFCT_TIMEOUT_ATTR_DCCP_RESPOND]	= "RESPOND",
62	[NFCT_TIMEOUT_ATTR_DCCP_PARTOPEN]	= "PARTOPEN",
63	[NFCT_TIMEOUT_ATTR_DCCP_OPEN]		= "OPEN",
64	[NFCT_TIMEOUT_ATTR_DCCP_CLOSEREQ]	= "CLOSEREQ",
65	[NFCT_TIMEOUT_ATTR_DCCP_CLOSING]	= "CLOSING",
66	[NFCT_TIMEOUT_ATTR_DCCP_TIMEWAIT]	= "TIMEWAIT",
67};
68
69static const char *const icmp_state_to_name[] = {
70	[NFCT_TIMEOUT_ATTR_ICMP]		= "TIMEOUT",
71};
72
73static const char *const icmpv6_state_to_name[] = {
74	[NFCT_TIMEOUT_ATTR_ICMPV6]		= "TIMEOUT",
75};
76
77static struct {
78	uint32_t nlattr_max;
79	uint32_t attr_max;
80	const char *const *state_to_name;
81} timeout_protocol[IPPROTO_MAX] = {
82	[IPPROTO_ICMP]	= {
83		.nlattr_max	= __CTA_TIMEOUT_ICMP_MAX,
84		.attr_max	= NFCT_TIMEOUT_ATTR_ICMP_MAX,
85		.state_to_name	= icmp_state_to_name,
86	},
87	[IPPROTO_TCP]	= {
88		.nlattr_max	= __CTA_TIMEOUT_TCP_MAX,
89		.attr_max	= NFCT_TIMEOUT_ATTR_TCP_MAX,
90		.state_to_name	= tcp_state_to_name,
91	},
92	[IPPROTO_UDP]	= {
93		.nlattr_max	= __CTA_TIMEOUT_UDP_MAX,
94		.attr_max	= NFCT_TIMEOUT_ATTR_UDP_MAX,
95		.state_to_name	= udp_state_to_name,
96	},
97	[IPPROTO_GRE]	= {
98		.nlattr_max	= __CTA_TIMEOUT_GRE_MAX,
99		.attr_max	= NFCT_TIMEOUT_ATTR_GRE_MAX,
100		.state_to_name	= udp_state_to_name,
101	},
102	[IPPROTO_SCTP]	= {
103		.nlattr_max	= __CTA_TIMEOUT_SCTP_MAX,
104		.attr_max	= NFCT_TIMEOUT_ATTR_SCTP_MAX,
105		.state_to_name	= sctp_state_to_name,
106	},
107	[IPPROTO_DCCP]	= {
108		.nlattr_max	= __CTA_TIMEOUT_DCCP_MAX,
109		.attr_max	= NFCT_TIMEOUT_ATTR_DCCP_MAX,
110		.state_to_name	= dccp_state_to_name,
111	},
112	[IPPROTO_UDPLITE]	= {
113		.nlattr_max	= __CTA_TIMEOUT_UDPLITE_MAX,
114		.attr_max	= NFCT_TIMEOUT_ATTR_UDPLITE_MAX,
115		.state_to_name	= udp_state_to_name,
116	},
117	[IPPROTO_ICMPV6]	= {
118		.nlattr_max	= __CTA_TIMEOUT_ICMPV6_MAX,
119		.attr_max	= NFCT_TIMEOUT_ATTR_ICMPV6_MAX,
120		.state_to_name	= icmpv6_state_to_name,
121	},
122	/* add your new supported protocol tracker here. */
123	[IPPROTO_RAW]	= {
124		.nlattr_max	= __CTA_TIMEOUT_GENERIC_MAX,
125		.attr_max	= NFCT_TIMEOUT_ATTR_GENERIC_MAX,
126		.state_to_name	= generic_state_to_name,
127	},
128};
129
130
131struct nfct_timeout {
132	char				name[32];	/* object name. */
133	uint16_t			l3num;		/* AF_INET, ... */
134	uint8_t				l4num;		/* UDP, TCP, ... */
135	uint16_t			attrset;
136
137	uint32_t			*timeout;	/* array of timeout. */
138	uint16_t			polset;
139};
140
141/**
142 * \mainpage
143 *
144 * libnetfilter_cttimeout is the userspace library that provides a programming
145 * interface (API) to the in-kernel cttimeout infrastructure. This
146 * infrastructure allows you to define fine-grain connection tracking timeout
147 * policies that can be attached to traffic flows via iptables CT target.
148 * Before the existence of this infrastructure, you could only set global
149 * timeout policies per protocol. This library is currently used by the nfct
150 * utility that is part of the conntrack-tools.
151 *
152 * libnetfilter_cttimeout homepage is:
153 *      http://netfilter.org/projects/libnetfilter_cttimeout/
154 *
155 * \section Dependencies
156 * libnetfilter_cttimeout requires libmnl and a kernel that includes the
157 * nfnetlink_cttimeout subsystem (i.e. 3.4.0 or later).
158 *
159 * \section Main Features
160 *  - listing/retrieving entries from the timeout policy table.
161 *  - inserting/modifying/deleting entries from the timeout policy table.
162 *
163 * \section Git Tree
164 * The current development version of libnetfilter_cttimeout can be accessed at
165 * https://git.netfilter.org/cgi-bin/gitweb.cgi?p=libnetfilter_cttimeout.git
166 *
167 * \section Privileges
168 * You need the CAP_NET_ADMIN capability in order to allow your application
169 * to receive events from and to send commands to kernel-space, excepting
170 * the timeout policy table dumping operation.
171 *
172 * \section Authors
173 * libnetfilter_conntrack has been written by Pablo Neira Ayuso.
174 */
175
176/**
177 * \defgroup nfcttimeout Timeout policy object handling
178 * @{
179 */
180
181/**
182 * nfct_timeout_alloc - allocate a new conntrack timeout object
183 * \param protonum layer 4 protocol number (use IPPROTO_* constants)
184 *
185 * You can use IPPROTO_MAX to set the timeout for the generic protocol tracker.
186 *
187 * In case of success, this function returns a valid pointer, otherwise NULL
188 * s returned and errno is appropriately set.
189 */
190struct nfct_timeout *nfct_timeout_alloc(void)
191{
192	struct nfct_timeout *t;
193
194	t = calloc(1, sizeof(struct nfct_timeout));
195	if (t == NULL)
196		return NULL;
197
198	return t;
199}
200EXPORT_SYMBOL(nfct_timeout_alloc);
201
202/**
203 * nfct_timeout_free - release one conntrack timeout object
204 * \param t pointer to the conntrack timeout object
205 */
206void nfct_timeout_free(struct nfct_timeout *t)
207{
208	if (t->timeout)
209		free(t->timeout);
210	free(t);
211}
212EXPORT_SYMBOL(nfct_timeout_free);
213
214/**
215 * nfct_timeout_attr_set - set one attribute of the conntrack timeout object
216 * \param t pointer to the conntrack timeout object
217 * \param type attribute type you want to set
218 * \param data pointer to data that will be used to set this attribute
219 */
220int
221nfct_timeout_attr_set(struct nfct_timeout *t, uint32_t type, const void *data)
222{
223	switch(type) {
224	case NFCT_TIMEOUT_ATTR_NAME:
225		strncpy(t->name, data, sizeof(t->name));
226		t->name[sizeof(t->name)-1] = '\0';
227		break;
228	case NFCT_TIMEOUT_ATTR_L3PROTO:
229		t->l3num = *((uint16_t *) data);
230		break;
231	case NFCT_TIMEOUT_ATTR_L4PROTO:
232		t->l4num = *((uint8_t *) data);
233		break;
234	/* NFCT_TIMEOUT_ATTR_POLICY is set by nfct_timeout_policy_attr_set. */
235	}
236	t->attrset |= (1 << type);
237	return 0;
238}
239EXPORT_SYMBOL(nfct_timeout_attr_set);
240
241/**
242 * nfct_timeout_attr_set_u8 - set one attribute of the conntrack timeout object
243 * \param t pointer to the conntrack timeout object
244 * \param type attribute type you want to set
245 * \param data pointer to data that will be used to set this attribute
246 */
247int
248nfct_timeout_attr_set_u8(struct nfct_timeout *t, uint32_t type, uint8_t data)
249{
250	return nfct_timeout_attr_set(t, type, &data);
251}
252EXPORT_SYMBOL(nfct_timeout_attr_set_u8);
253
254/**
255 * nfct_timeout_attr_set_u16 - set one attribute of the conntrack timeout object
256 * \param t pointer to the conntrack timeout object
257 * \param type attribute type you want to set
258 * \param data pointer to data that will be used to set this attribute
259 */
260int
261nfct_timeout_attr_set_u16(struct nfct_timeout *t, uint32_t type, uint16_t data)
262{
263	return nfct_timeout_attr_set(t, type, &data);
264}
265EXPORT_SYMBOL(nfct_timeout_attr_set_u16);
266
267/**
268 * nfct_timeout_attr_unset - unset one attribute of the conntrack timeout object
269 * \param t pointer to the conntrack timeout object
270 * \param type attribute type you want to set
271 */
272void nfct_timeout_attr_unset(struct nfct_timeout *t, uint32_t type)
273{
274	t->attrset &= ~(1 << type);
275}
276EXPORT_SYMBOL(nfct_timeout_attr_unset);
277
278/**
279 * nfct_timeout_policy_attr_set_u32 - set one attribute of the policy
280 * \param t pointer to the conntrack timeout object
281 * \param type attribute type you want to set
282 * \param data data that will be used to set this attribute
283 */
284int
285nfct_timeout_policy_attr_set_u32(struct nfct_timeout *t,
286				 uint32_t type, uint32_t data)
287{
288	size_t timeout_array_size;
289
290	/* Layer 4 protocol needs to be already set. */
291	if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)))
292		return -1;
293
294	if (t->timeout == NULL) {
295		/* if not supported, default to generic protocol tracker. */
296		if (timeout_protocol[t->l4num].attr_max != 0) {
297			timeout_array_size =
298				sizeof(uint32_t) *
299					timeout_protocol[t->l4num].attr_max;
300		} else {
301			timeout_array_size =
302				sizeof(uint32_t) *
303					timeout_protocol[IPPROTO_RAW].attr_max;
304		}
305		t->timeout = calloc(1, timeout_array_size);
306		if (t->timeout == NULL)
307			return -1;
308	}
309
310	/* this state does not exists in this protocol tracker. */
311	if (type > timeout_protocol[t->l4num].attr_max)
312		return -1;
313
314	t->timeout[type] = data;
315	t->polset |= (1 << type);
316
317	if (!(t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY)))
318		t->attrset |= (1 << NFCT_TIMEOUT_ATTR_POLICY);
319
320	return 0;
321}
322EXPORT_SYMBOL(nfct_timeout_policy_attr_set_u32);
323
324/**
325 * nfct_timeout_policy_attr_unset - unset one attribute of the policy
326 * \param t pointer to the conntrack timeout object
327 * \param type attribute type you want to set
328 */
329void nfct_timeout_policy_attr_unset(struct nfct_timeout *t, uint32_t type)
330{
331	t->attrset &= ~(1 << type);
332}
333EXPORT_SYMBOL(nfct_timeout_policy_attr_unset);
334
335/**
336 * nfct_timeout_policy_attr_to_name - get state name from protocol state number
337 * \param l4proto protocol, ie. IPPROTO_*
338 * \param state state number that you want to get the state name
339 *
340 * This function returns NULL if unsupported protocol or state number is passed.
341 * Otherwise, a pointer to valid string is returned.
342 */
343const char *nfct_timeout_policy_attr_to_name(uint8_t l4proto, uint32_t state)
344{
345	if (timeout_protocol[l4proto].state_to_name == NULL) {
346		printf("no array state name\n");
347		return NULL;
348	}
349
350	if (timeout_protocol[l4proto].state_to_name[state] == NULL) {
351		printf("state %d does not exists\n", state);
352		return NULL;
353	}
354
355	return timeout_protocol[l4proto].state_to_name[state];
356}
357EXPORT_SYMBOL(nfct_timeout_policy_attr_to_name);
358
359/**
360 * @}
361 */
362
363/**
364 * \defgroup nfcttimeout_output Timeout policy object output
365 * @{
366 */
367
368static int
369nfct_timeout_snprintf_default(char *buf, size_t size,
370			      const struct nfct_timeout *t,
371			      unsigned int flags)
372{
373	int ret = 0;
374	unsigned int offset = 0;
375
376	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME)) {
377		ret = snprintf(buf+offset, size, ".%s = {\n", t->name);
378		offset += ret;
379		size -= ret;
380	}
381	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO)) {
382		ret = snprintf(buf+offset, size, "\t.l3proto = %u,\n",
383				t->l3num);
384		offset += ret;
385		size -= ret;
386	}
387	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO)) {
388		ret = snprintf(buf+offset, size, "\t.l4proto = %u,\n",
389				t->l4num);
390		offset += ret;
391		size -= ret;
392	}
393	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY)) {
394		uint8_t l4num = t->l4num;
395		int i;
396
397		/* default to generic protocol tracker. */
398		if (timeout_protocol[t->l4num].attr_max == 0)
399			l4num = IPPROTO_RAW;
400
401		ret = snprintf(buf+offset, size, "\t.policy = {\n");
402		offset += ret;
403		size -= ret;
404
405		for (i=0; i<timeout_protocol[l4num].attr_max; i++) {
406			const char *state_name =
407				timeout_protocol[l4num].state_to_name[i][0] ?
408				timeout_protocol[l4num].state_to_name[i] :
409				"UNKNOWN";
410
411			ret = snprintf(buf+offset, size,
412				"\t\t.%s = %u,\n", state_name, t->timeout[i]);
413			offset += ret;
414			size -= ret;
415		}
416
417		ret = snprintf(buf+offset, size, "\t},\n");
418		offset += ret;
419		size -= ret;
420	}
421	ret = snprintf(buf+offset, size, "};");
422	offset += ret;
423	size -= ret;
424
425	buf[offset]='\0';
426
427	return ret;
428}
429
430/**
431 * nfct_timeout_snprintf - print conntrack timeout object into one buffer
432 * \param buf: pointer to buffer that is used to print the object
433 * \param size: size of the buffer (or remaining room in it).
434 * \param t: pointer to a valid conntrack timeout object.
435 * \param type: output type (see NFCT_TIMEOUT_O_*)
436 * \param flags: output flags (always set this to zero).
437 *
438 * This function returns -1 in case that some mandatory attributes are
439 * missing. On sucess, it returns 0.
440 */
441int nfct_timeout_snprintf(char *buf, size_t size, const struct nfct_timeout *t,
442			  unsigned int type, unsigned int flags)
443{
444	int ret = 0;
445
446	switch(type) {
447	case NFCT_TIMEOUT_O_DEFAULT:
448		ret = nfct_timeout_snprintf_default(buf, size, t, flags);
449		break;
450	/* add your new output here. */
451	default:
452		break;
453	}
454
455	return ret;
456}
457EXPORT_SYMBOL(nfct_timeout_snprintf);
458
459/**
460 * @}
461 */
462
463/**
464 * \defgroup nlmsg Netlink message helper functions
465 * @{
466 */
467
468/**
469 * nfct_timeout_nlmsg_build_hdr - build netlink message header for ct timeout
470 * \param buf: buffer where this function outputs the netlink message.
471 * \param cmd: nfct_timeout nfnetlink command.
472 * \param flags: netlink flags.
473 * \param seq: sequence number for this message.
474 *
475 * Possible commands:
476 * - CTNL_MSG_TIMEOUT_NEW: new conntrack timeout object.
477 * - CTNL_MSG_TIMEOUT_GET: get conntrack timeout object.
478 * - CTNL_MSG_TIMEOUT_DEL: delete conntrack timeout object.
479 */
480struct nlmsghdr *
481nfct_timeout_nlmsg_build_hdr(char *buf, uint8_t cmd,
482			     uint16_t flags, uint32_t seq)
483{
484	struct nlmsghdr *nlh;
485	struct nfgenmsg *nfh;
486
487	nlh = mnl_nlmsg_put_header(buf);
488	nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8) | cmd;
489	nlh->nlmsg_flags = NLM_F_REQUEST | flags;
490	nlh->nlmsg_seq = seq;
491
492	nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
493	nfh->nfgen_family = AF_UNSPEC;
494	nfh->version = NFNETLINK_V0;
495	nfh->res_id = 0;
496
497	return nlh;
498}
499EXPORT_SYMBOL(nfct_timeout_nlmsg_build_hdr);
500
501/**
502 * nfct_timeout_nlmsg_build_payload - build payload from ct timeout object
503 * \param nlh: netlink message that you want to use to add the payload.
504 * \param t: pointer to a conntrack timeout object
505 */
506void
507nfct_timeout_nlmsg_build_payload(struct nlmsghdr *nlh,
508				 const struct nfct_timeout *t)
509{
510	int i;
511	struct nlattr *nest;
512
513	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_NAME))
514		mnl_attr_put_strz(nlh, CTA_TIMEOUT_NAME, t->name);
515
516	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L3PROTO))
517		mnl_attr_put_u16(nlh, CTA_TIMEOUT_L3PROTO, htons(t->l3num));
518
519	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_L4PROTO))
520		mnl_attr_put_u8(nlh, CTA_TIMEOUT_L4PROTO, t->l4num);
521
522	if (t->attrset & (1 << NFCT_TIMEOUT_ATTR_POLICY) && t->polset) {
523		nest = mnl_attr_nest_start(nlh, CTA_TIMEOUT_DATA);
524
525		for (i=0; i<timeout_protocol[t->l4num].attr_max; i++) {
526			if (t->polset & (1 << i)) {
527				mnl_attr_put_u32(nlh, i+1,
528						 htonl(t->timeout[i]));
529			}
530		}
531		mnl_attr_nest_end(nlh, nest);
532	}
533
534}
535EXPORT_SYMBOL(nfct_timeout_nlmsg_build_payload);
536
537static int
538timeout_nlmsg_parse_attr_cb(const struct nlattr *attr, void *data)
539{
540	const struct nlattr **tb = data;
541	uint16_t type = mnl_attr_get_type(attr);
542
543	if (mnl_attr_type_valid(attr, CTA_TIMEOUT_MAX) < 0)
544		return MNL_CB_OK;
545
546	switch(type) {
547	case CTA_TIMEOUT_NAME:
548		if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
549			perror("mnl_attr_validate");
550			return MNL_CB_ERROR;
551		}
552		break;
553	case CTA_TIMEOUT_L3PROTO:
554		if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
555			perror("mnl_attr_validate");
556			return MNL_CB_ERROR;
557		}
558		break;
559	case CTA_TIMEOUT_L4PROTO:
560		if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
561			perror("mnl_attr_validate");
562			return MNL_CB_ERROR;
563		}
564		break;
565	case CTA_TIMEOUT_DATA:
566		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
567			perror("mnl_attr_validate");
568			return MNL_CB_ERROR;
569		}
570		break;
571	}
572	tb[type] = attr;
573	return MNL_CB_OK;
574}
575
576struct _container_policy_cb {
577	unsigned int nlattr_max;
578	void *tb;
579};
580
581static int
582parse_timeout_attr_policy_cb(const struct nlattr *attr, void *data)
583{
584	struct _container_policy_cb *data_cb = data;
585        const struct nlattr **tb = data_cb->tb;
586	uint16_t type = mnl_attr_get_type(attr);
587
588        if (mnl_attr_type_valid(attr, data_cb->nlattr_max) < 0)
589                return MNL_CB_OK;
590
591	if (type <= data_cb->nlattr_max) {
592		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
593			perror("mnl_attr_validate");
594			return MNL_CB_ERROR;
595		}
596		tb[type] = attr;
597	}
598	return MNL_CB_OK;
599}
600
601static void
602timeout_parse_attr_data(struct nfct_timeout *t, const struct nlattr *nest)
603{
604	unsigned int nlattr_max = timeout_protocol[t->l4num].nlattr_max;
605	struct nlattr *tb[nlattr_max];
606	struct _container_policy_cb cnt = {
607		.nlattr_max = nlattr_max,
608		.tb = tb,
609	};
610	unsigned int i;
611
612	memset(tb, 0, sizeof(struct nlattr *) * nlattr_max);
613
614	mnl_attr_parse_nested(nest, parse_timeout_attr_policy_cb, &cnt);
615
616	for (i=1; i<nlattr_max; i++) {
617		if (tb[i]) {
618			nfct_timeout_policy_attr_set_u32(t, i-1,
619				ntohl(mnl_attr_get_u32(tb[i])));
620		}
621	}
622}
623
624/**
625 * nfct_timeout_nlmsg_parse_payload - set timeout object attributes from message
626 * \param nlh: netlink message that you want to use to add the payload.
627 * \param t: pointer to a conntrack timeout object
628 *
629 * This function returns -1 in case that some mandatory attributes are
630 * missing. On sucess, it returns 0.
631 */
632int
633nfct_timeout_nlmsg_parse_payload(const struct nlmsghdr *nlh,
634				 struct nfct_timeout *t)
635{
636	struct nlattr *tb[CTA_TIMEOUT_MAX+1] = {};
637	struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
638
639	mnl_attr_parse(nlh, sizeof(*nfg), timeout_nlmsg_parse_attr_cb, tb);
640	if (tb[CTA_TIMEOUT_NAME]) {
641		nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME,
642			mnl_attr_get_str(tb[CTA_TIMEOUT_NAME]));
643	}
644	if (tb[CTA_TIMEOUT_L3PROTO]) {
645		nfct_timeout_attr_set_u16(t, NFCT_TIMEOUT_ATTR_L3PROTO,
646			ntohs(mnl_attr_get_u16(tb[CTA_TIMEOUT_L3PROTO])));
647	}
648	if (tb[CTA_TIMEOUT_L4PROTO]) {
649		nfct_timeout_attr_set_u8(t, NFCT_TIMEOUT_ATTR_L4PROTO,
650			mnl_attr_get_u8(tb[CTA_TIMEOUT_L4PROTO]));
651	}
652	if (tb[CTA_TIMEOUT_DATA]) {
653		timeout_parse_attr_data(t, tb[CTA_TIMEOUT_DATA]);
654	}
655	return 0;
656}
657EXPORT_SYMBOL(nfct_timeout_nlmsg_parse_payload);
658
659/**
660 * @}
661 */
662