xref: /aosp_15_r20/external/libnfnetlink/src/libnfnetlink.c (revision a376eb3279f225b393114c4820c780cbda860a6c)
1*a376eb32SXin Li /* libnfnetlink.c: generic library for communication with netfilter
2*a376eb32SXin Li  *
3*a376eb32SXin Li  * (C) 2002-2006 by Harald Welte <[email protected]>
4*a376eb32SXin Li  * (C) 2006-2011 by Pablo Neira Ayuso <[email protected]>
5*a376eb32SXin Li  *
6*a376eb32SXin Li  * Based on some original ideas from Jay Schulist <[email protected]>
7*a376eb32SXin Li  *
8*a376eb32SXin Li  * Development of this code funded by Astaro AG (http://www.astaro.com)
9*a376eb32SXin Li  *
10*a376eb32SXin Li  * This program is free software; you can redistribute it and/or modify it
11*a376eb32SXin Li  * under the terms of the GNU General Public License version 2 as published
12*a376eb32SXin Li  * by the Free Software Foundation.
13*a376eb32SXin Li  *
14*a376eb32SXin Li  * 2005-09-14 Pablo Neira Ayuso <[email protected]>:
15*a376eb32SXin Li  * 	Define structure nfnlhdr
16*a376eb32SXin Li  * 	Added __be64_to_cpu function
17*a376eb32SXin Li  *	Use NFA_TYPE macro to get the attribute type
18*a376eb32SXin Li  *
19*a376eb32SXin Li  * 2006-01-14 Harald Welte <[email protected]>:
20*a376eb32SXin Li  * 	introduce nfnl_subsys_handle
21*a376eb32SXin Li  *
22*a376eb32SXin Li  * 2006-01-15 Pablo Neira Ayuso <[email protected]>:
23*a376eb32SXin Li  * 	set missing subsys_id in nfnl_subsys_open
24*a376eb32SXin Li  * 	set missing nfnlh->local.nl_pid in nfnl_open
25*a376eb32SXin Li  *
26*a376eb32SXin Li  * 2006-01-26 Harald Welte <[email protected]>:
27*a376eb32SXin Li  * 	remove bogus nfnlh->local.nl_pid from nfnl_open ;)
28*a376eb32SXin Li  * 	add 16bit attribute functions
29*a376eb32SXin Li  *
30*a376eb32SXin Li  * 2006-07-03 Pablo Neira Ayuso <[email protected]>:
31*a376eb32SXin Li  * 	add iterator API
32*a376eb32SXin Li  * 	add replacements for nfnl_listen and nfnl_talk
33*a376eb32SXin Li  * 	fix error handling
34*a376eb32SXin Li  * 	add assertions
35*a376eb32SXin Li  * 	add documentation
36*a376eb32SXin Li  * 	minor cleanups
37*a376eb32SXin Li  */
38*a376eb32SXin Li 
39*a376eb32SXin Li #include <stdlib.h>
40*a376eb32SXin Li #include <stdio.h>
41*a376eb32SXin Li #include <unistd.h>
42*a376eb32SXin Li #include <errno.h>
43*a376eb32SXin Li #include <string.h>
44*a376eb32SXin Li #include <time.h>
45*a376eb32SXin Li #include <netinet/in.h>
46*a376eb32SXin Li #include <assert.h>
47*a376eb32SXin Li #include <linux/types.h>
48*a376eb32SXin Li #include <sys/socket.h>
49*a376eb32SXin Li #include <sys/uio.h>
50*a376eb32SXin Li 
51*a376eb32SXin Li #include <linux/netlink.h>
52*a376eb32SXin Li 
53*a376eb32SXin Li #include <libnfnetlink/libnfnetlink.h>
54*a376eb32SXin Li 
55*a376eb32SXin Li #ifndef NETLINK_ADD_MEMBERSHIP
56*a376eb32SXin Li #define NETLINK_ADD_MEMBERSHIP 1
57*a376eb32SXin Li #endif
58*a376eb32SXin Li 
59*a376eb32SXin Li #ifndef SOL_NETLINK
60*a376eb32SXin Li #define SOL_NETLINK 270
61*a376eb32SXin Li #endif
62*a376eb32SXin Li 
63*a376eb32SXin Li 
64*a376eb32SXin Li #define nfnl_error(format, args...) \
65*a376eb32SXin Li 	fprintf(stderr, "%s: " format "\n", __FUNCTION__, ## args)
66*a376eb32SXin Li 
67*a376eb32SXin Li #ifdef _NFNL_DEBUG
68*a376eb32SXin Li #define nfnl_debug_dump_packet nfnl_dump_packet
69*a376eb32SXin Li #else
70*a376eb32SXin Li #define nfnl_debug_dump_packet(a, b, ...)
71*a376eb32SXin Li #endif
72*a376eb32SXin Li 
73*a376eb32SXin Li struct nfnl_subsys_handle {
74*a376eb32SXin Li 	struct nfnl_handle 	*nfnlh;
75*a376eb32SXin Li 	u_int32_t		subscriptions;
76*a376eb32SXin Li 	u_int8_t		subsys_id;
77*a376eb32SXin Li 	u_int8_t		cb_count;
78*a376eb32SXin Li 	struct nfnl_callback 	*cb;	/* array of callbacks */
79*a376eb32SXin Li };
80*a376eb32SXin Li 
81*a376eb32SXin Li #define		NFNL_MAX_SUBSYS			16 /* enough for now */
82*a376eb32SXin Li 
83*a376eb32SXin Li #define NFNL_F_SEQTRACK_ENABLED		(1 << 0)
84*a376eb32SXin Li 
85*a376eb32SXin Li struct nfnl_handle {
86*a376eb32SXin Li 	int			fd;
87*a376eb32SXin Li 	struct sockaddr_nl	local;
88*a376eb32SXin Li 	struct sockaddr_nl	peer;
89*a376eb32SXin Li 	u_int32_t		subscriptions;
90*a376eb32SXin Li 	u_int32_t		seq;
91*a376eb32SXin Li 	u_int32_t		dump;
92*a376eb32SXin Li 	u_int32_t		rcv_buffer_size;	/* for nfnl_catch */
93*a376eb32SXin Li 	u_int32_t		flags;
94*a376eb32SXin Li 	struct nlmsghdr 	*last_nlhdr;
95*a376eb32SXin Li 	struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1];
96*a376eb32SXin Li };
97*a376eb32SXin Li 
nfnl_dump_packet(struct nlmsghdr * nlh,int received_len,char * desc)98*a376eb32SXin Li void nfnl_dump_packet(struct nlmsghdr *nlh, int received_len, char *desc)
99*a376eb32SXin Li {
100*a376eb32SXin Li 	void *nlmsg_data = NLMSG_DATA(nlh);
101*a376eb32SXin Li 	struct nfattr *nfa = NFM_NFA(NLMSG_DATA(nlh));
102*a376eb32SXin Li 	int len = NFM_PAYLOAD(nlh);
103*a376eb32SXin Li 
104*a376eb32SXin Li 	printf("%s called from %s\n", __FUNCTION__, desc);
105*a376eb32SXin Li 	printf("  nlmsghdr = %p, received_len = %u\n", nlh, received_len);
106*a376eb32SXin Li 	printf("  NLMSG_DATA(nlh) = %p (+%td bytes)\n", nlmsg_data,
107*a376eb32SXin Li 	       (nlmsg_data - (void *)nlh));
108*a376eb32SXin Li 	printf("  NFM_NFA(NLMSG_DATA(nlh)) = %p (+%td bytes)\n",
109*a376eb32SXin Li 		nfa, ((void *)nfa - (void *)nlh));
110*a376eb32SXin Li 	printf("  NFM_PAYLOAD(nlh) = %u\n", len);
111*a376eb32SXin Li 	printf("  nlmsg_type = %u, nlmsg_len = %u, nlmsg_seq = %u "
112*a376eb32SXin Li 		"nlmsg_flags = 0x%x\n", nlh->nlmsg_type, nlh->nlmsg_len,
113*a376eb32SXin Li 		nlh->nlmsg_seq, nlh->nlmsg_flags);
114*a376eb32SXin Li 
115*a376eb32SXin Li 	while (NFA_OK(nfa, len)) {
116*a376eb32SXin Li 		printf("    nfa@%p: nfa_type=%u, nfa_len=%u\n",
117*a376eb32SXin Li 			nfa, NFA_TYPE(nfa), nfa->nfa_len);
118*a376eb32SXin Li 		nfa = NFA_NEXT(nfa,len);
119*a376eb32SXin Li 	}
120*a376eb32SXin Li }
121*a376eb32SXin Li 
122*a376eb32SXin Li /**
123*a376eb32SXin Li  * nfnl_fd - returns the descriptor that identifies the socket
124*a376eb32SXin Li  * @nfnlh: nfnetlink handler
125*a376eb32SXin Li  *
126*a376eb32SXin Li  * Use this function if you need to interact with the socket. Common
127*a376eb32SXin Li  * scenarios are the use of poll()/select() to achieve multiplexation.
128*a376eb32SXin Li  */
nfnl_fd(struct nfnl_handle * h)129*a376eb32SXin Li int nfnl_fd(struct nfnl_handle *h)
130*a376eb32SXin Li {
131*a376eb32SXin Li 	assert(h);
132*a376eb32SXin Li 	return h->fd;
133*a376eb32SXin Li }
134*a376eb32SXin Li 
135*a376eb32SXin Li /**
136*a376eb32SXin Li  * nfnl_portid - returns the Netlink port ID of this socket
137*a376eb32SXin Li  * @h: nfnetlink handler
138*a376eb32SXin Li  */
nfnl_portid(const struct nfnl_handle * h)139*a376eb32SXin Li unsigned int nfnl_portid(const struct nfnl_handle *h)
140*a376eb32SXin Li {
141*a376eb32SXin Li 	assert(h);
142*a376eb32SXin Li 	return h->local.nl_pid;
143*a376eb32SXin Li }
144*a376eb32SXin Li 
recalc_rebind_subscriptions(struct nfnl_handle * nfnlh)145*a376eb32SXin Li static int recalc_rebind_subscriptions(struct nfnl_handle *nfnlh)
146*a376eb32SXin Li {
147*a376eb32SXin Li 	int i, err;
148*a376eb32SXin Li 	u_int32_t new_subscriptions = nfnlh->subscriptions;
149*a376eb32SXin Li 
150*a376eb32SXin Li 	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
151*a376eb32SXin Li 		new_subscriptions |= nfnlh->subsys[i].subscriptions;
152*a376eb32SXin Li 
153*a376eb32SXin Li 	nfnlh->local.nl_groups = new_subscriptions;
154*a376eb32SXin Li 	err = bind(nfnlh->fd, (struct sockaddr *)&nfnlh->local,
155*a376eb32SXin Li 		   sizeof(nfnlh->local));
156*a376eb32SXin Li 	if (err == -1)
157*a376eb32SXin Li 		return -1;
158*a376eb32SXin Li 
159*a376eb32SXin Li 	nfnlh->subscriptions = new_subscriptions;
160*a376eb32SXin Li 
161*a376eb32SXin Li 	return 0;
162*a376eb32SXin Li }
163*a376eb32SXin Li 
recalc_subscriptions(struct nfnl_handle * nfnlh)164*a376eb32SXin Li static void recalc_subscriptions(struct nfnl_handle *nfnlh)
165*a376eb32SXin Li {
166*a376eb32SXin Li 	int i;
167*a376eb32SXin Li 	u_int32_t new_subscriptions = nfnlh->subscriptions;
168*a376eb32SXin Li 
169*a376eb32SXin Li 	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
170*a376eb32SXin Li 		new_subscriptions |= nfnlh->subsys[i].subscriptions;
171*a376eb32SXin Li 
172*a376eb32SXin Li 	nfnlh->local.nl_groups = new_subscriptions;
173*a376eb32SXin Li 	nfnlh->subscriptions = new_subscriptions;
174*a376eb32SXin Li }
175*a376eb32SXin Li 
176*a376eb32SXin Li /**
177*a376eb32SXin Li  * nfnl_open - open a nfnetlink handler
178*a376eb32SXin Li  *
179*a376eb32SXin Li  * This function creates a nfnetlink handler, this is required to establish
180*a376eb32SXin Li  * a communication between the userspace and the nfnetlink system.
181*a376eb32SXin Li  *
182*a376eb32SXin Li  * On success, a valid address that points to a nfnl_handle structure
183*a376eb32SXin Li  * is returned. On error, NULL is returned and errno is set approapiately.
184*a376eb32SXin Li  */
nfnl_open(void)185*a376eb32SXin Li struct nfnl_handle *nfnl_open(void)
186*a376eb32SXin Li {
187*a376eb32SXin Li 	struct nfnl_handle *nfnlh;
188*a376eb32SXin Li 	int fd;
189*a376eb32SXin Li 
190*a376eb32SXin Li 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
191*a376eb32SXin Li 	if (fd == -1)
192*a376eb32SXin Li 		return NULL;
193*a376eb32SXin Li 	nfnlh = nfnl_open2(fd, true);
194*a376eb32SXin Li 	if (nfnlh == NULL)
195*a376eb32SXin Li 		close(fd);
196*a376eb32SXin Li 	return nfnlh;
197*a376eb32SXin Li }
198*a376eb32SXin Li 
199*a376eb32SXin Li /**
200*a376eb32SXin Li  * nfnl_open2 - open a nfnetlink handler
201*a376eb32SXin Li  * @fd: passing file descriptor
202*a376eb32SXin Li  * @bind:  indicate the passing fd needs to be binded or not
203*a376eb32SXin Li  *
204*a376eb32SXin Li  * This function creates a nfnetlink handler, this is required to establish
205*a376eb32SXin Li  * a communication between the userspace and the nfnetlink system.
206*a376eb32SXin Li  *
207*a376eb32SXin Li  * On success, a valid address that points to a nfnl_handle structure
208*a376eb32SXin Li  * is returned. On error, NULL is returned and errno is set approapiately.
209*a376eb32SXin Li  */
nfnl_open2(int fd,bool bind)210*a376eb32SXin Li struct nfnl_handle *nfnl_open2(int fd, bool bind)
211*a376eb32SXin Li {
212*a376eb32SXin Li 	struct nfnl_handle *nfnlh;
213*a376eb32SXin Li 	unsigned int addr_len;
214*a376eb32SXin Li 
215*a376eb32SXin Li 	if (fd < 0)
216*a376eb32SXin Li 		goto err;
217*a376eb32SXin Li 
218*a376eb32SXin Li 	nfnlh = malloc(sizeof(*nfnlh));
219*a376eb32SXin Li 	if (!nfnlh)
220*a376eb32SXin Li 		return NULL;
221*a376eb32SXin Li 
222*a376eb32SXin Li 	memset(nfnlh, 0, sizeof(*nfnlh));
223*a376eb32SXin Li 	nfnlh->fd = fd;
224*a376eb32SXin Li 
225*a376eb32SXin Li 	nfnlh->local.nl_family = AF_NETLINK;
226*a376eb32SXin Li 	nfnlh->peer.nl_family = AF_NETLINK;
227*a376eb32SXin Li 
228*a376eb32SXin Li 	addr_len = sizeof(nfnlh->local);
229*a376eb32SXin Li 	getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
230*a376eb32SXin Li 	if (addr_len != sizeof(nfnlh->local)) {
231*a376eb32SXin Li 		errno = EINVAL;
232*a376eb32SXin Li 		goto err_free;
233*a376eb32SXin Li 	}
234*a376eb32SXin Li 	if (nfnlh->local.nl_family != AF_NETLINK) {
235*a376eb32SXin Li 		errno = EINVAL;
236*a376eb32SXin Li 		goto err_free;
237*a376eb32SXin Li 	}
238*a376eb32SXin Li 	nfnlh->seq = time(NULL);
239*a376eb32SXin Li 	nfnlh->rcv_buffer_size = NFNL_BUFFSIZE;
240*a376eb32SXin Li 
241*a376eb32SXin Li 	/* don't set pid here, only first socket of process has real pid !!!
242*a376eb32SXin Li 	 * binding to pid '0' will default */
243*a376eb32SXin Li 
244*a376eb32SXin Li 	/* let us do the initial bind */
245*a376eb32SXin Li 	if (bind) {
246*a376eb32SXin Li 		if (recalc_rebind_subscriptions(nfnlh) < 0)
247*a376eb32SXin Li 			goto err_free;
248*a376eb32SXin Li 	} else {
249*a376eb32SXin Li 		recalc_subscriptions(nfnlh);
250*a376eb32SXin Li 	}
251*a376eb32SXin Li 
252*a376eb32SXin Li 	/* use getsockname to get the netlink pid that the kernel assigned us */
253*a376eb32SXin Li 	addr_len = sizeof(nfnlh->local);
254*a376eb32SXin Li 	getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
255*a376eb32SXin Li 	if (addr_len != sizeof(nfnlh->local)) {
256*a376eb32SXin Li 		errno = EINVAL;
257*a376eb32SXin Li 		goto err_free;
258*a376eb32SXin Li 	}
259*a376eb32SXin Li 	/* sequence tracking enabled by default */
260*a376eb32SXin Li 	nfnlh->flags |= NFNL_F_SEQTRACK_ENABLED;
261*a376eb32SXin Li 
262*a376eb32SXin Li 	return nfnlh;
263*a376eb32SXin Li 
264*a376eb32SXin Li err_free:
265*a376eb32SXin Li 	free(nfnlh);
266*a376eb32SXin Li err:
267*a376eb32SXin Li 	return NULL;
268*a376eb32SXin Li }
269*a376eb32SXin Li 
270*a376eb32SXin Li /**
271*a376eb32SXin Li  * nfnl_set_sequence_tracking - set netlink sequence tracking
272*a376eb32SXin Li  * @h: nfnetlink handler
273*a376eb32SXin Li  */
nfnl_set_sequence_tracking(struct nfnl_handle * h)274*a376eb32SXin Li void nfnl_set_sequence_tracking(struct nfnl_handle *h)
275*a376eb32SXin Li {
276*a376eb32SXin Li 	h->flags |= NFNL_F_SEQTRACK_ENABLED;
277*a376eb32SXin Li }
278*a376eb32SXin Li 
279*a376eb32SXin Li /**
280*a376eb32SXin Li  * nfnl_unset_sequence_tracking - set netlink sequence tracking
281*a376eb32SXin Li  * @h: nfnetlink handler
282*a376eb32SXin Li  */
nfnl_unset_sequence_tracking(struct nfnl_handle * h)283*a376eb32SXin Li void nfnl_unset_sequence_tracking(struct nfnl_handle *h)
284*a376eb32SXin Li {
285*a376eb32SXin Li 	h->flags &= ~NFNL_F_SEQTRACK_ENABLED;
286*a376eb32SXin Li }
287*a376eb32SXin Li 
288*a376eb32SXin Li /**
289*a376eb32SXin Li  * nfnl_set_rcv_buffer_size - set the size of the receive buffer
290*a376eb32SXin Li  * @h: libnfnetlink handler
291*a376eb32SXin Li  * @size: buffer size
292*a376eb32SXin Li  *
293*a376eb32SXin Li  * This function sets the size of the receive buffer size, i.e. the size
294*a376eb32SXin Li  * of the buffer used by nfnl_recv. Default value is 4096 bytes.
295*a376eb32SXin Li  */
nfnl_set_rcv_buffer_size(struct nfnl_handle * h,unsigned int size)296*a376eb32SXin Li void nfnl_set_rcv_buffer_size(struct nfnl_handle *h, unsigned int size)
297*a376eb32SXin Li {
298*a376eb32SXin Li 	h->rcv_buffer_size = size;
299*a376eb32SXin Li }
300*a376eb32SXin Li 
301*a376eb32SXin Li /**
302*a376eb32SXin Li  * nfnl_subsys_open - open a netlink subsystem
303*a376eb32SXin Li  * @nfnlh: libnfnetlink handle
304*a376eb32SXin Li  * @subsys_id: which nfnetlink subsystem we are interested in
305*a376eb32SXin Li  * @cb_count: number of callbacks that are used maximum.
306*a376eb32SXin Li  * @subscriptions: netlink groups we want to be subscribed to
307*a376eb32SXin Li  *
308*a376eb32SXin Li  * This function creates a subsystem handler that contains the set of
309*a376eb32SXin Li  * callbacks that handle certain types of messages coming from a netfilter
310*a376eb32SXin Li  * subsystem. Initially the callback set is empty, you can register callbacks
311*a376eb32SXin Li  * via nfnl_callback_register().
312*a376eb32SXin Li  *
313*a376eb32SXin Li  * On error, NULL is returned and errno is set appropiately. On success,
314*a376eb32SXin Li  * a valid address that points to a nfnl_subsys_handle structure is returned.
315*a376eb32SXin Li  */
316*a376eb32SXin Li struct nfnl_subsys_handle *
nfnl_subsys_open(struct nfnl_handle * nfnlh,u_int8_t subsys_id,u_int8_t cb_count,u_int32_t subscriptions)317*a376eb32SXin Li nfnl_subsys_open(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
318*a376eb32SXin Li 		 u_int8_t cb_count, u_int32_t subscriptions)
319*a376eb32SXin Li {
320*a376eb32SXin Li 	return nfnl_subsys_open2 (nfnlh, subsys_id, cb_count, subscriptions, true);
321*a376eb32SXin Li }
322*a376eb32SXin Li 
323*a376eb32SXin Li /**
324*a376eb32SXin Li  * nfnl_subsys_open2 - open a netlink subsystem
325*a376eb32SXin Li  * @nfnlh: libnfnetlink handle
326*a376eb32SXin Li  * @subsys_id: which nfnetlink subsystem we are interested in
327*a376eb32SXin Li  * @cb_count: number of callbacks that are used maximum.
328*a376eb32SXin Li  * @subscriptions: netlink groups we want to be subscribed to
329*a376eb32SXin Li  * @bind: indicate the passing fd needs to be binded or not
330*a376eb32SXin Li  *
331*a376eb32SXin Li  * This function creates a subsystem handler that contains the set of
332*a376eb32SXin Li  * callbacks that handle certain types of messages coming from a netfilter
333*a376eb32SXin Li  * subsystem. Initially the callback set is empty, you can register callbacks
334*a376eb32SXin Li  * via nfnl_callback_register().
335*a376eb32SXin Li  *
336*a376eb32SXin Li  * On error, NULL is returned and errno is set appropiately. On success,
337*a376eb32SXin Li  * a valid address that points to a nfnl_subsys_handle structure is returned.
338*a376eb32SXin Li  */
339*a376eb32SXin Li struct nfnl_subsys_handle *
nfnl_subsys_open2(struct nfnl_handle * nfnlh,u_int8_t subsys_id,u_int8_t cb_count,u_int32_t subscriptions,bool bind)340*a376eb32SXin Li nfnl_subsys_open2(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
341*a376eb32SXin Li 		 u_int8_t cb_count, u_int32_t subscriptions, bool bind)
342*a376eb32SXin Li {
343*a376eb32SXin Li 	struct nfnl_subsys_handle *ssh;
344*a376eb32SXin Li 	int err = 0;
345*a376eb32SXin Li 
346*a376eb32SXin Li 	assert(nfnlh);
347*a376eb32SXin Li 
348*a376eb32SXin Li 	if (subsys_id > NFNL_MAX_SUBSYS) {
349*a376eb32SXin Li 		errno = ENOENT;
350*a376eb32SXin Li 		return NULL;
351*a376eb32SXin Li 	}
352*a376eb32SXin Li 
353*a376eb32SXin Li 	ssh = &nfnlh->subsys[subsys_id];
354*a376eb32SXin Li 	if (ssh->cb) {
355*a376eb32SXin Li 		errno = EBUSY;
356*a376eb32SXin Li 		return NULL;
357*a376eb32SXin Li 	}
358*a376eb32SXin Li 
359*a376eb32SXin Li 	ssh->cb = calloc(cb_count, sizeof(*(ssh->cb)));
360*a376eb32SXin Li 	if (!ssh->cb)
361*a376eb32SXin Li 		return NULL;
362*a376eb32SXin Li 
363*a376eb32SXin Li 	ssh->nfnlh = nfnlh;
364*a376eb32SXin Li 	ssh->cb_count = cb_count;
365*a376eb32SXin Li 	ssh->subscriptions = subscriptions;
366*a376eb32SXin Li 	ssh->subsys_id = subsys_id;
367*a376eb32SXin Li 
368*a376eb32SXin Li 	/* although now we have nfnl_join to subscribe to certain
369*a376eb32SXin Li 	 * groups, just keep this to ensure compatibility */
370*a376eb32SXin Li 	if (bind)
371*a376eb32SXin Li 		err = recalc_rebind_subscriptions(nfnlh);
372*a376eb32SXin Li 	else
373*a376eb32SXin Li 		recalc_subscriptions(nfnlh);
374*a376eb32SXin Li 	if (err < 0) {
375*a376eb32SXin Li 		free(ssh->cb);
376*a376eb32SXin Li 		ssh->cb = NULL;
377*a376eb32SXin Li 		return NULL;
378*a376eb32SXin Li 	}
379*a376eb32SXin Li 	return ssh;
380*a376eb32SXin Li }
381*a376eb32SXin Li 
382*a376eb32SXin Li /**
383*a376eb32SXin Li  * nfnl_subsys_close - close a nfnetlink subsys handler
384*a376eb32SXin Li  * @ssh: nfnetlink subsystem handler
385*a376eb32SXin Li  *
386*a376eb32SXin Li  * Release all the callbacks registered in a subsystem handler.
387*a376eb32SXin Li  */
nfnl_subsys_close(struct nfnl_subsys_handle * ssh)388*a376eb32SXin Li void nfnl_subsys_close(struct nfnl_subsys_handle *ssh)
389*a376eb32SXin Li {
390*a376eb32SXin Li 	assert(ssh);
391*a376eb32SXin Li 
392*a376eb32SXin Li 	ssh->subscriptions = 0;
393*a376eb32SXin Li 	ssh->cb_count = 0;
394*a376eb32SXin Li 	if (ssh->cb) {
395*a376eb32SXin Li 		free(ssh->cb);
396*a376eb32SXin Li 		ssh->cb = NULL;
397*a376eb32SXin Li 	}
398*a376eb32SXin Li }
399*a376eb32SXin Li 
400*a376eb32SXin Li /**
401*a376eb32SXin Li  * nfnl_close - close a nfnetlink handler
402*a376eb32SXin Li  * @nfnlh: nfnetlink handler
403*a376eb32SXin Li  *
404*a376eb32SXin Li  * This function closes the nfnetlink handler. On success, 0 is returned.
405*a376eb32SXin Li  * On error, -1 is returned and errno is set appropiately.
406*a376eb32SXin Li  */
nfnl_close(struct nfnl_handle * nfnlh)407*a376eb32SXin Li int nfnl_close(struct nfnl_handle *nfnlh)
408*a376eb32SXin Li {
409*a376eb32SXin Li 	int ret;
410*a376eb32SXin Li 
411*a376eb32SXin Li 	assert(nfnlh);
412*a376eb32SXin Li 	ret = close(nfnlh->fd);
413*a376eb32SXin Li 	if (ret < 0)
414*a376eb32SXin Li 		return ret;
415*a376eb32SXin Li 	return nfnl_close2(nfnlh);
416*a376eb32SXin Li }
417*a376eb32SXin Li 
418*a376eb32SXin Li /**
419*a376eb32SXin Li  * nfnl_close2 - close a nfnetlink handler but keep fd
420*a376eb32SXin Li  * @nfnlh: nfnetlink handler
421*a376eb32SXin Li  *
422*a376eb32SXin Li  * This function closes the nfnetlink handler. On success, 0 is returned.
423*a376eb32SXin Li  * On error, -1 is returned and errno is set appropiately.
424*a376eb32SXin Li  */
nfnl_close2(struct nfnl_handle * nfnlh)425*a376eb32SXin Li int nfnl_close2(struct nfnl_handle *nfnlh)
426*a376eb32SXin Li {
427*a376eb32SXin Li 	int i;
428*a376eb32SXin Li 
429*a376eb32SXin Li 	assert(nfnlh);
430*a376eb32SXin Li 
431*a376eb32SXin Li 	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
432*a376eb32SXin Li 		nfnl_subsys_close(&nfnlh->subsys[i]);
433*a376eb32SXin Li 
434*a376eb32SXin Li 	free(nfnlh);
435*a376eb32SXin Li 
436*a376eb32SXin Li 	return 0;
437*a376eb32SXin Li }
438*a376eb32SXin Li 
439*a376eb32SXin Li /**
440*a376eb32SXin Li  * nfnl_join - join a nfnetlink multicast group
441*a376eb32SXin Li  * @nfnlh: nfnetlink handler
442*a376eb32SXin Li  * @group: group we want to join
443*a376eb32SXin Li  *
444*a376eb32SXin Li  * This function is used to join a certain multicast group. It must be
445*a376eb32SXin Li  * called once the nfnetlink handler has been created. If any doubt,
446*a376eb32SXin Li  * just use it if you have to listen to nfnetlink events.
447*a376eb32SXin Li  *
448*a376eb32SXin Li  * On success, 0 is returned. On error, -1 is returned and errno is set
449*a376eb32SXin Li  * approapiately.
450*a376eb32SXin Li  */
nfnl_join(const struct nfnl_handle * nfnlh,unsigned int group)451*a376eb32SXin Li int nfnl_join(const struct nfnl_handle *nfnlh, unsigned int group)
452*a376eb32SXin Li {
453*a376eb32SXin Li 	assert(nfnlh);
454*a376eb32SXin Li 	return setsockopt(nfnlh->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
455*a376eb32SXin Li 			  &group, sizeof(group));
456*a376eb32SXin Li }
457*a376eb32SXin Li 
458*a376eb32SXin Li /**
459*a376eb32SXin Li  * nfnl_send - send a nfnetlink message through netlink socket
460*a376eb32SXin Li  * @nfnlh: nfnetlink handler
461*a376eb32SXin Li  * @n: netlink message
462*a376eb32SXin Li  *
463*a376eb32SXin Li  * On success, the number of bytes is returned. On error, -1 is returned
464*a376eb32SXin Li  * and errno is set appropiately.
465*a376eb32SXin Li  */
nfnl_send(struct nfnl_handle * nfnlh,struct nlmsghdr * n)466*a376eb32SXin Li int nfnl_send(struct nfnl_handle *nfnlh, struct nlmsghdr *n)
467*a376eb32SXin Li {
468*a376eb32SXin Li 	assert(nfnlh);
469*a376eb32SXin Li 	assert(n);
470*a376eb32SXin Li 
471*a376eb32SXin Li 	nfnl_debug_dump_packet(n, n->nlmsg_len+sizeof(*n), "nfnl_send");
472*a376eb32SXin Li 
473*a376eb32SXin Li 	return sendto(nfnlh->fd, n, n->nlmsg_len, 0,
474*a376eb32SXin Li 		      (struct sockaddr *)&nfnlh->peer, sizeof(nfnlh->peer));
475*a376eb32SXin Li }
476*a376eb32SXin Li 
nfnl_sendmsg(const struct nfnl_handle * nfnlh,const struct msghdr * msg,unsigned int flags)477*a376eb32SXin Li int nfnl_sendmsg(const struct nfnl_handle *nfnlh, const struct msghdr *msg,
478*a376eb32SXin Li 		 unsigned int flags)
479*a376eb32SXin Li {
480*a376eb32SXin Li 	assert(nfnlh);
481*a376eb32SXin Li 	assert(msg);
482*a376eb32SXin Li 
483*a376eb32SXin Li 	return sendmsg(nfnlh->fd, msg, flags);
484*a376eb32SXin Li }
485*a376eb32SXin Li 
nfnl_sendiov(const struct nfnl_handle * nfnlh,const struct iovec * iov,unsigned int num,unsigned int flags)486*a376eb32SXin Li int nfnl_sendiov(const struct nfnl_handle *nfnlh, const struct iovec *iov,
487*a376eb32SXin Li 		 unsigned int num, unsigned int flags)
488*a376eb32SXin Li {
489*a376eb32SXin Li 	struct msghdr msg;
490*a376eb32SXin Li 
491*a376eb32SXin Li 	assert(nfnlh);
492*a376eb32SXin Li 
493*a376eb32SXin Li 	msg.msg_name = (struct sockaddr *) &nfnlh->peer;
494*a376eb32SXin Li 	msg.msg_namelen = sizeof(nfnlh->peer);
495*a376eb32SXin Li 	msg.msg_iov = (struct iovec *) iov;
496*a376eb32SXin Li 	msg.msg_iovlen = num;
497*a376eb32SXin Li 	msg.msg_control = NULL;
498*a376eb32SXin Li 	msg.msg_controllen = 0;
499*a376eb32SXin Li 	msg.msg_flags = 0;
500*a376eb32SXin Li 
501*a376eb32SXin Li 	return nfnl_sendmsg(nfnlh, &msg, flags);
502*a376eb32SXin Li }
503*a376eb32SXin Li 
504*a376eb32SXin Li /**
505*a376eb32SXin Li  * nfnl_fill_hdr - fill in netlink and nfnetlink header
506*a376eb32SXin Li  * @nfnlh: nfnetlink handle
507*a376eb32SXin Li  * @nlh: netlink message to be filled in
508*a376eb32SXin Li  * @len: length of _payload_ bytes (not including nfgenmsg)
509*a376eb32SXin Li  * @family: AF_INET / ...
510*a376eb32SXin Li  * @res_id: resource id
511*a376eb32SXin Li  * @msg_type: nfnetlink message type (without subsystem)
512*a376eb32SXin Li  * @msg_flags: netlink message flags
513*a376eb32SXin Li  *
514*a376eb32SXin Li  * This function sets up appropiately the nfnetlink header. See that the
515*a376eb32SXin Li  * pointer to the netlink message passed must point to a memory region of
516*a376eb32SXin Li  * at least the size of struct nlmsghdr + struct nfgenmsg.
517*a376eb32SXin Li  */
nfnl_fill_hdr(struct nfnl_subsys_handle * ssh,struct nlmsghdr * nlh,unsigned int len,u_int8_t family,u_int16_t res_id,u_int16_t msg_type,u_int16_t msg_flags)518*a376eb32SXin Li void nfnl_fill_hdr(struct nfnl_subsys_handle *ssh,
519*a376eb32SXin Li 		    struct nlmsghdr *nlh, unsigned int len,
520*a376eb32SXin Li 		    u_int8_t family,
521*a376eb32SXin Li 		    u_int16_t res_id,
522*a376eb32SXin Li 		    u_int16_t msg_type,
523*a376eb32SXin Li 		    u_int16_t msg_flags)
524*a376eb32SXin Li {
525*a376eb32SXin Li 	assert(ssh);
526*a376eb32SXin Li 	assert(nlh);
527*a376eb32SXin Li 
528*a376eb32SXin Li 	struct nfgenmsg *nfg = (void *)nlh + sizeof(*nlh);
529*a376eb32SXin Li 
530*a376eb32SXin Li 	nlh->nlmsg_len = NLMSG_LENGTH(len+sizeof(*nfg));
531*a376eb32SXin Li 	nlh->nlmsg_type = (ssh->subsys_id<<8)|msg_type;
532*a376eb32SXin Li 	nlh->nlmsg_flags = msg_flags;
533*a376eb32SXin Li 	nlh->nlmsg_pid = 0;
534*a376eb32SXin Li 
535*a376eb32SXin Li 	if (ssh->nfnlh->flags & NFNL_F_SEQTRACK_ENABLED) {
536*a376eb32SXin Li 		nlh->nlmsg_seq = ++ssh->nfnlh->seq;
537*a376eb32SXin Li 		/* kernel uses sequence number zero for events */
538*a376eb32SXin Li 		if (!ssh->nfnlh->seq)
539*a376eb32SXin Li 			nlh->nlmsg_seq = ssh->nfnlh->seq = time(NULL);
540*a376eb32SXin Li 	} else {
541*a376eb32SXin Li 		/* unset sequence number, ignore it */
542*a376eb32SXin Li 		nlh->nlmsg_seq = 0;
543*a376eb32SXin Li 	}
544*a376eb32SXin Li 
545*a376eb32SXin Li 	nfg->nfgen_family = family;
546*a376eb32SXin Li 	nfg->version = NFNETLINK_V0;
547*a376eb32SXin Li 	nfg->res_id = htons(res_id);
548*a376eb32SXin Li }
549*a376eb32SXin Li 
550*a376eb32SXin Li struct nfattr *
nfnl_parse_hdr(const struct nfnl_handle * nfnlh,const struct nlmsghdr * nlh,struct nfgenmsg ** genmsg)551*a376eb32SXin Li nfnl_parse_hdr(const struct nfnl_handle *nfnlh,
552*a376eb32SXin Li 		const struct nlmsghdr *nlh,
553*a376eb32SXin Li 		struct nfgenmsg **genmsg)
554*a376eb32SXin Li {
555*a376eb32SXin Li 	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg)))
556*a376eb32SXin Li 		return NULL;
557*a376eb32SXin Li 
558*a376eb32SXin Li 	if (nlh->nlmsg_len == NLMSG_LENGTH(sizeof(struct nfgenmsg))) {
559*a376eb32SXin Li 		if (genmsg)
560*a376eb32SXin Li 			*genmsg = (void *)nlh + sizeof(*nlh);
561*a376eb32SXin Li 		return NULL;
562*a376eb32SXin Li 	}
563*a376eb32SXin Li 
564*a376eb32SXin Li 	if (genmsg)
565*a376eb32SXin Li 		*genmsg = (void *)nlh + sizeof(*nlh);
566*a376eb32SXin Li 
567*a376eb32SXin Li 	return (void *)nlh + NLMSG_LENGTH(sizeof(struct nfgenmsg));
568*a376eb32SXin Li }
569*a376eb32SXin Li 
570*a376eb32SXin Li /**
571*a376eb32SXin Li  * nfnl_recv - receive data from a nfnetlink subsystem
572*a376eb32SXin Li  * @h: nfnetlink handler
573*a376eb32SXin Li  * @buf: buffer where the data will be stored
574*a376eb32SXin Li  * @len: size of the buffer
575*a376eb32SXin Li  *
576*a376eb32SXin Li  * This function doesn't perform any sanity checking. So do no expect
577*a376eb32SXin Li  * that the data is well-formed. Such checkings are done by the parsing
578*a376eb32SXin Li  * functions.
579*a376eb32SXin Li  *
580*a376eb32SXin Li  * On success, 0 is returned. On error, -1 is returned and errno is set
581*a376eb32SXin Li  * appropiately.
582*a376eb32SXin Li  *
583*a376eb32SXin Li  * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
584*a376eb32SXin Li  * that case is possible that the information requested is incomplete.
585*a376eb32SXin Li  */
586*a376eb32SXin Li ssize_t
nfnl_recv(const struct nfnl_handle * h,unsigned char * buf,size_t len)587*a376eb32SXin Li nfnl_recv(const struct nfnl_handle *h, unsigned char *buf, size_t len)
588*a376eb32SXin Li {
589*a376eb32SXin Li 	socklen_t addrlen;
590*a376eb32SXin Li 	int status;
591*a376eb32SXin Li 	struct sockaddr_nl peer;
592*a376eb32SXin Li 
593*a376eb32SXin Li 	assert(h);
594*a376eb32SXin Li 	assert(buf);
595*a376eb32SXin Li 	assert(len > 0);
596*a376eb32SXin Li 
597*a376eb32SXin Li 	if (len < sizeof(struct nlmsgerr)
598*a376eb32SXin Li 	    || len < sizeof(struct nlmsghdr)) {
599*a376eb32SXin Li 	    	errno = EBADMSG;
600*a376eb32SXin Li 		return -1;
601*a376eb32SXin Li 	}
602*a376eb32SXin Li 
603*a376eb32SXin Li 	addrlen = sizeof(h->peer);
604*a376eb32SXin Li 	status = recvfrom(h->fd, buf, len, 0, (struct sockaddr *)&peer,
605*a376eb32SXin Li 			&addrlen);
606*a376eb32SXin Li 	if (status <= 0)
607*a376eb32SXin Li 		return status;
608*a376eb32SXin Li 
609*a376eb32SXin Li 	if (addrlen != sizeof(peer)) {
610*a376eb32SXin Li 		errno = EINVAL;
611*a376eb32SXin Li 		return -1;
612*a376eb32SXin Li 	}
613*a376eb32SXin Li 
614*a376eb32SXin Li 	if (peer.nl_pid != 0) {
615*a376eb32SXin Li 		errno = ENOMSG;
616*a376eb32SXin Li 		return -1;
617*a376eb32SXin Li 	}
618*a376eb32SXin Li 
619*a376eb32SXin Li 	return status;
620*a376eb32SXin Li }
621*a376eb32SXin Li /**
622*a376eb32SXin Li  * nfnl_listen: listen for one or more netlink messages
623*a376eb32SXin Li  * @nfnhl: libnfnetlink handle
624*a376eb32SXin Li  * @handler: callback function to be called for every netlink message
625*a376eb32SXin Li  *          - the callback handler should normally return 0
626*a376eb32SXin Li  *          - but may return a negative error code which will cause
627*a376eb32SXin Li  *            nfnl_listen to return immediately with the same error code
628*a376eb32SXin Li  *          - or return a postivie error code which will cause
629*a376eb32SXin Li  *            nfnl_listen to return after it has finished processing all
630*a376eb32SXin Li  *            the netlink messages in the current packet
631*a376eb32SXin Li  *          Thus a positive error code will terminate nfnl_listen "soon"
632*a376eb32SXin Li  *          without any loss of data, a negative error code will terminate
633*a376eb32SXin Li  *          nfnl_listen "very soon" and throw away data already read from
634*a376eb32SXin Li  *          the netlink socket.
635*a376eb32SXin Li  * @jarg: opaque argument passed on to callback
636*a376eb32SXin Li  *
637*a376eb32SXin Li  * This function is used to receive and process messages coming from an open
638*a376eb32SXin Li  * nfnetlink handler like events or information request via nfnl_send().
639*a376eb32SXin Li  *
640*a376eb32SXin Li  * On error, -1 is returned, unfortunately errno is not always set
641*a376eb32SXin Li  * appropiately. For that reason, the use of this function is DEPRECATED.
642*a376eb32SXin Li  * Please, use nfnl_receive_process() instead.
643*a376eb32SXin Li  */
nfnl_listen(struct nfnl_handle * nfnlh,int (* handler)(struct sockaddr_nl *,struct nlmsghdr * n,void *),void * jarg)644*a376eb32SXin Li int nfnl_listen(struct nfnl_handle *nfnlh,
645*a376eb32SXin Li 		int (*handler)(struct sockaddr_nl *, struct nlmsghdr *n,
646*a376eb32SXin Li 			       void *), void *jarg)
647*a376eb32SXin Li {
648*a376eb32SXin Li 	struct sockaddr_nl nladdr;
649*a376eb32SXin Li 	char buf[NFNL_BUFFSIZE] __attribute__ ((aligned));
650*a376eb32SXin Li 	struct iovec iov;
651*a376eb32SXin Li 	int remain;
652*a376eb32SXin Li 	struct nlmsghdr *h;
653*a376eb32SXin Li 	struct nlmsgerr *msgerr;
654*a376eb32SXin Li 	int quit=0;
655*a376eb32SXin Li 
656*a376eb32SXin Li 	struct msghdr msg = {
657*a376eb32SXin Li 		.msg_name    = &nladdr,
658*a376eb32SXin Li 		.msg_namelen = sizeof(nladdr),
659*a376eb32SXin Li 		.msg_iov     = &iov,
660*a376eb32SXin Li 		.msg_iovlen  = 1,
661*a376eb32SXin Li 	};
662*a376eb32SXin Li 
663*a376eb32SXin Li 	memset(&nladdr, 0, sizeof(nladdr));
664*a376eb32SXin Li 	nladdr.nl_family = AF_NETLINK;
665*a376eb32SXin Li 	iov.iov_base = buf;
666*a376eb32SXin Li 	iov.iov_len = sizeof(buf);
667*a376eb32SXin Li 
668*a376eb32SXin Li 	while (! quit) {
669*a376eb32SXin Li 		remain = recvmsg(nfnlh->fd, &msg, 0);
670*a376eb32SXin Li 		if (remain < 0) {
671*a376eb32SXin Li 			if (errno == EINTR)
672*a376eb32SXin Li 				continue;
673*a376eb32SXin Li 			/* Bad file descriptor */
674*a376eb32SXin Li 			else if (errno == EBADF)
675*a376eb32SXin Li 				break;
676*a376eb32SXin Li 			else if (errno == EAGAIN)
677*a376eb32SXin Li 				break;
678*a376eb32SXin Li 			nfnl_error("recvmsg overrun: %s", strerror(errno));
679*a376eb32SXin Li 			continue;
680*a376eb32SXin Li 		}
681*a376eb32SXin Li 		if (remain == 0) {
682*a376eb32SXin Li 			nfnl_error("EOF on netlink");
683*a376eb32SXin Li 			return -1;
684*a376eb32SXin Li 		}
685*a376eb32SXin Li 		if (msg.msg_namelen != sizeof(nladdr)) {
686*a376eb32SXin Li 			nfnl_error("Bad sender address len (%d)",
687*a376eb32SXin Li 				   msg.msg_namelen);
688*a376eb32SXin Li 			return -1;
689*a376eb32SXin Li 		}
690*a376eb32SXin Li 
691*a376eb32SXin Li 		for (h = (struct nlmsghdr *)buf; remain >= sizeof(*h);) {
692*a376eb32SXin Li 			int err;
693*a376eb32SXin Li 			int len = h->nlmsg_len;
694*a376eb32SXin Li 			int l = len - sizeof(*h);
695*a376eb32SXin Li 
696*a376eb32SXin Li 			if (l < 0 || len > remain) {
697*a376eb32SXin Li 				if (msg.msg_flags & MSG_TRUNC) {
698*a376eb32SXin Li 					nfnl_error("MSG_TRUNC");
699*a376eb32SXin Li 					return -1;
700*a376eb32SXin Li 				}
701*a376eb32SXin Li 				nfnl_error("Malformed msg (len=%d)", len);
702*a376eb32SXin Li 				return -1;
703*a376eb32SXin Li 			}
704*a376eb32SXin Li 
705*a376eb32SXin Li 			/* end of messages reached, let's return */
706*a376eb32SXin Li 			if (h->nlmsg_type == NLMSG_DONE)
707*a376eb32SXin Li 				return 0;
708*a376eb32SXin Li 
709*a376eb32SXin Li 			/* Break the loop if success is explicitely
710*a376eb32SXin Li 			 * reported via NLM_F_ACK flag set */
711*a376eb32SXin Li 			if (h->nlmsg_type == NLMSG_ERROR) {
712*a376eb32SXin Li 				msgerr = NLMSG_DATA(h);
713*a376eb32SXin Li 				return msgerr->error;
714*a376eb32SXin Li 			}
715*a376eb32SXin Li 
716*a376eb32SXin Li 			err = handler(&nladdr, h, jarg);
717*a376eb32SXin Li 			if (err < 0)
718*a376eb32SXin Li 				return err;
719*a376eb32SXin Li 			quit |= err;
720*a376eb32SXin Li 
721*a376eb32SXin Li 			/* FIXME: why not _NEXT macros, etc.? */
722*a376eb32SXin Li 			//h = NLMSG_NEXT(h, remain);
723*a376eb32SXin Li 			remain -= NLMSG_ALIGN(len);
724*a376eb32SXin Li 			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
725*a376eb32SXin Li 		}
726*a376eb32SXin Li 		if (msg.msg_flags & MSG_TRUNC) {
727*a376eb32SXin Li 			nfnl_error("MSG_TRUNC");
728*a376eb32SXin Li 			continue;
729*a376eb32SXin Li 		}
730*a376eb32SXin Li 		if (remain) {
731*a376eb32SXin Li 			nfnl_error("remnant size %d", remain);
732*a376eb32SXin Li 			return -1;
733*a376eb32SXin Li 		}
734*a376eb32SXin Li 	}
735*a376eb32SXin Li 
736*a376eb32SXin Li 	return quit;
737*a376eb32SXin Li }
738*a376eb32SXin Li 
739*a376eb32SXin Li /**
740*a376eb32SXin Li  * nfnl_talk - send a request and then receive and process messages returned
741*a376eb32SXin Li  * @nfnlh: nfnetelink handler
742*a376eb32SXin Li  * @n: netlink message that contains the request
743*a376eb32SXin Li  * @peer: peer PID
744*a376eb32SXin Li  * @groups: netlink groups
745*a376eb32SXin Li  * @junk: callback called if out-of-sequence messages were received
746*a376eb32SXin Li  * @jarg: data for the junk callback
747*a376eb32SXin Li  *
748*a376eb32SXin Li  * This function is used to request an action that does not returns any
749*a376eb32SXin Li  * information. On error, a negative value is returned, errno could be
750*a376eb32SXin Li  * set appropiately. For that reason, the use of this function is DEPRECATED.
751*a376eb32SXin Li  * Please, use nfnl_query() instead.
752*a376eb32SXin Li  */
nfnl_talk(struct nfnl_handle * nfnlh,struct nlmsghdr * n,pid_t peer,unsigned groups,struct nlmsghdr * answer,int (* junk)(struct sockaddr_nl *,struct nlmsghdr * n,void *),void * jarg)753*a376eb32SXin Li int nfnl_talk(struct nfnl_handle *nfnlh, struct nlmsghdr *n, pid_t peer,
754*a376eb32SXin Li 	      unsigned groups, struct nlmsghdr *answer,
755*a376eb32SXin Li 	      int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
756*a376eb32SXin Li 	      void *jarg)
757*a376eb32SXin Li {
758*a376eb32SXin Li 	char buf[NFNL_BUFFSIZE] __attribute__ ((aligned));
759*a376eb32SXin Li 	struct sockaddr_nl nladdr;
760*a376eb32SXin Li 	struct nlmsghdr *h;
761*a376eb32SXin Li 	unsigned int seq;
762*a376eb32SXin Li 	int status;
763*a376eb32SXin Li 	struct iovec iov = {
764*a376eb32SXin Li 		n, n->nlmsg_len
765*a376eb32SXin Li 	};
766*a376eb32SXin Li 	struct msghdr msg = {
767*a376eb32SXin Li 		.msg_name    = &nladdr,
768*a376eb32SXin Li 		.msg_namelen = sizeof(nladdr),
769*a376eb32SXin Li 		.msg_iov     = &iov,
770*a376eb32SXin Li 		.msg_iovlen  = 1,
771*a376eb32SXin Li 	};
772*a376eb32SXin Li 
773*a376eb32SXin Li 	memset(&nladdr, 0, sizeof(nladdr));
774*a376eb32SXin Li 	nladdr.nl_family = AF_NETLINK;
775*a376eb32SXin Li 	nladdr.nl_pid = peer;
776*a376eb32SXin Li 	nladdr.nl_groups = groups;
777*a376eb32SXin Li 
778*a376eb32SXin Li 	n->nlmsg_seq = seq = ++nfnlh->seq;
779*a376eb32SXin Li 	/* FIXME: why ? */
780*a376eb32SXin Li 	if (!answer)
781*a376eb32SXin Li 		n->nlmsg_flags |= NLM_F_ACK;
782*a376eb32SXin Li 
783*a376eb32SXin Li 	status = sendmsg(nfnlh->fd, &msg, 0);
784*a376eb32SXin Li 	if (status < 0) {
785*a376eb32SXin Li 		nfnl_error("sendmsg(netlink) %s", strerror(errno));
786*a376eb32SXin Li 		return -1;
787*a376eb32SXin Li 	}
788*a376eb32SXin Li 	iov.iov_base = buf;
789*a376eb32SXin Li 	iov.iov_len = sizeof(buf);
790*a376eb32SXin Li 
791*a376eb32SXin Li 	while (1) {
792*a376eb32SXin Li 		status = recvmsg(nfnlh->fd, &msg, 0);
793*a376eb32SXin Li 		if (status < 0) {
794*a376eb32SXin Li 			if (errno == EINTR)
795*a376eb32SXin Li 				continue;
796*a376eb32SXin Li 			nfnl_error("recvmsg over-run");
797*a376eb32SXin Li 			continue;
798*a376eb32SXin Li 		}
799*a376eb32SXin Li 		if (status == 0) {
800*a376eb32SXin Li 			nfnl_error("EOF on netlink");
801*a376eb32SXin Li 			return -1;
802*a376eb32SXin Li 		}
803*a376eb32SXin Li 		if (msg.msg_namelen != sizeof(nladdr)) {
804*a376eb32SXin Li 			nfnl_error("Bad sender address len %d",
805*a376eb32SXin Li 				   msg.msg_namelen);
806*a376eb32SXin Li 			return -1;
807*a376eb32SXin Li 		}
808*a376eb32SXin Li 
809*a376eb32SXin Li 		for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
810*a376eb32SXin Li 			int len = h->nlmsg_len;
811*a376eb32SXin Li 			int l = len - sizeof(*h);
812*a376eb32SXin Li 			int err;
813*a376eb32SXin Li 
814*a376eb32SXin Li 			if (l < 0 || len > status) {
815*a376eb32SXin Li 				if (msg.msg_flags & MSG_TRUNC) {
816*a376eb32SXin Li 					nfnl_error("Truncated message\n");
817*a376eb32SXin Li 					return -1;
818*a376eb32SXin Li 				}
819*a376eb32SXin Li 				nfnl_error("Malformed message: len=%d\n", len);
820*a376eb32SXin Li 				return -1; /* FIXME: libnetlink exits here */
821*a376eb32SXin Li 			}
822*a376eb32SXin Li 
823*a376eb32SXin Li 			if (h->nlmsg_pid != nfnlh->local.nl_pid ||
824*a376eb32SXin Li 			    h->nlmsg_seq != seq) {
825*a376eb32SXin Li 				if (junk) {
826*a376eb32SXin Li 					err = junk(&nladdr, h, jarg);
827*a376eb32SXin Li 					if (err < 0)
828*a376eb32SXin Li 						return err;
829*a376eb32SXin Li 				}
830*a376eb32SXin Li 				goto cont;
831*a376eb32SXin Li 			}
832*a376eb32SXin Li 
833*a376eb32SXin Li 			if (h->nlmsg_type == NLMSG_ERROR) {
834*a376eb32SXin Li 				struct nlmsgerr *err = NLMSG_DATA(h);
835*a376eb32SXin Li 				if (l < sizeof(struct nlmsgerr))
836*a376eb32SXin Li 					nfnl_error("ERROR truncated\n");
837*a376eb32SXin Li 				else {
838*a376eb32SXin Li 					errno = -err->error;
839*a376eb32SXin Li 					if (errno == 0) {
840*a376eb32SXin Li 						if (answer)
841*a376eb32SXin Li 							memcpy(answer, h, h->nlmsg_len);
842*a376eb32SXin Li 						return 0;
843*a376eb32SXin Li 					}
844*a376eb32SXin Li 					perror("NFNETLINK answers");
845*a376eb32SXin Li 				}
846*a376eb32SXin Li 				return err->error;
847*a376eb32SXin Li 			}
848*a376eb32SXin Li 			if (answer) {
849*a376eb32SXin Li 				memcpy(answer, h, h->nlmsg_len);
850*a376eb32SXin Li 				return 0;
851*a376eb32SXin Li 			}
852*a376eb32SXin Li 
853*a376eb32SXin Li 			nfnl_error("Unexpected reply!\n");
854*a376eb32SXin Li cont:
855*a376eb32SXin Li 			status -= NLMSG_ALIGN(len);
856*a376eb32SXin Li 			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
857*a376eb32SXin Li 		}
858*a376eb32SXin Li 		if (msg.msg_flags & MSG_TRUNC) {
859*a376eb32SXin Li 			nfnl_error("Messages truncated\n");
860*a376eb32SXin Li 			continue;
861*a376eb32SXin Li 		}
862*a376eb32SXin Li 		if (status)
863*a376eb32SXin Li 			nfnl_error("Remnant of size %d\n", status);
864*a376eb32SXin Li 	}
865*a376eb32SXin Li }
866*a376eb32SXin Li 
867*a376eb32SXin Li /**
868*a376eb32SXin Li  * nfnl_addattr_l - Add variable length attribute to nlmsghdr
869*a376eb32SXin Li  * @n: netlink message header to which attribute is to be added
870*a376eb32SXin Li  * @maxlen: maximum length of netlink message header
871*a376eb32SXin Li  * @type: type of new attribute
872*a376eb32SXin Li  * @data: content of new attribute
873*a376eb32SXin Li  * @len: attribute length
874*a376eb32SXin Li  */
nfnl_addattr_l(struct nlmsghdr * n,int maxlen,int type,const void * data,int alen)875*a376eb32SXin Li int nfnl_addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
876*a376eb32SXin Li 		   int alen)
877*a376eb32SXin Li {
878*a376eb32SXin Li 	int len = NFA_LENGTH(alen);
879*a376eb32SXin Li 	struct nfattr *nfa;
880*a376eb32SXin Li 
881*a376eb32SXin Li 	assert(n);
882*a376eb32SXin Li 	assert(maxlen > 0);
883*a376eb32SXin Li 	assert(type >= 0);
884*a376eb32SXin Li 
885*a376eb32SXin Li 	if ((NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
886*a376eb32SXin Li 		errno = ENOSPC;
887*a376eb32SXin Li 		return -1;
888*a376eb32SXin Li 	}
889*a376eb32SXin Li 
890*a376eb32SXin Li 	nfa = NLMSG_TAIL(n);
891*a376eb32SXin Li 	nfa->nfa_type = type;
892*a376eb32SXin Li 	nfa->nfa_len = len;
893*a376eb32SXin Li 	memcpy(NFA_DATA(nfa), data, alen);
894*a376eb32SXin Li 	n->nlmsg_len = (NLMSG_ALIGN(n->nlmsg_len) + NFA_ALIGN(len));
895*a376eb32SXin Li 	return 0;
896*a376eb32SXin Li }
897*a376eb32SXin Li 
898*a376eb32SXin Li /**
899*a376eb32SXin Li  * nfnl_nfa_addattr_l - Add variable length attribute to struct nfattr
900*a376eb32SXin Li  *
901*a376eb32SXin Li  * @nfa: struct nfattr
902*a376eb32SXin Li  * @maxlen: maximal length of nfattr buffer
903*a376eb32SXin Li  * @type: type for new attribute
904*a376eb32SXin Li  * @data: content of new attribute
905*a376eb32SXin Li  * @alen: length of new attribute
906*a376eb32SXin Li  *
907*a376eb32SXin Li  */
nfnl_nfa_addattr_l(struct nfattr * nfa,int maxlen,int type,const void * data,int alen)908*a376eb32SXin Li int nfnl_nfa_addattr_l(struct nfattr *nfa, int maxlen, int type,
909*a376eb32SXin Li 		       const void *data, int alen)
910*a376eb32SXin Li {
911*a376eb32SXin Li 	struct nfattr *subnfa;
912*a376eb32SXin Li 	int len = NFA_LENGTH(alen);
913*a376eb32SXin Li 
914*a376eb32SXin Li 	assert(nfa);
915*a376eb32SXin Li 	assert(maxlen > 0);
916*a376eb32SXin Li 	assert(type >= 0);
917*a376eb32SXin Li 
918*a376eb32SXin Li 	if (NFA_ALIGN(nfa->nfa_len) + len > maxlen) {
919*a376eb32SXin Li 		errno = ENOSPC;
920*a376eb32SXin Li 		return -1;
921*a376eb32SXin Li 	}
922*a376eb32SXin Li 
923*a376eb32SXin Li 	subnfa = (struct nfattr *)(((char *)nfa) + NFA_ALIGN(nfa->nfa_len));
924*a376eb32SXin Li 	subnfa->nfa_type = type;
925*a376eb32SXin Li 	subnfa->nfa_len = len;
926*a376eb32SXin Li 	memcpy(NFA_DATA(subnfa), data, alen);
927*a376eb32SXin Li 	nfa->nfa_len = NFA_ALIGN(nfa->nfa_len) + len;
928*a376eb32SXin Li 
929*a376eb32SXin Li 	return 0;
930*a376eb32SXin Li }
931*a376eb32SXin Li 
932*a376eb32SXin Li /**
933*a376eb32SXin Li  * nfnl_addattr8 - Add u_int8_t attribute to nlmsghdr
934*a376eb32SXin Li  *
935*a376eb32SXin Li  * @n: netlink message header to which attribute is to be added
936*a376eb32SXin Li  * @maxlen: maximum length of netlink message header
937*a376eb32SXin Li  * @type: type of new attribute
938*a376eb32SXin Li  * @data: content of new attribute
939*a376eb32SXin Li  */
nfnl_addattr8(struct nlmsghdr * n,int maxlen,int type,u_int8_t data)940*a376eb32SXin Li int nfnl_addattr8(struct nlmsghdr *n, int maxlen, int type, u_int8_t data)
941*a376eb32SXin Li {
942*a376eb32SXin Li 	assert(n);
943*a376eb32SXin Li 	assert(maxlen > 0);
944*a376eb32SXin Li 	assert(type >= 0);
945*a376eb32SXin Li 
946*a376eb32SXin Li 	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
947*a376eb32SXin Li }
948*a376eb32SXin Li 
949*a376eb32SXin Li /**
950*a376eb32SXin Li  * nfnl_nfa_addattr16 - Add u_int16_t attribute to struct nfattr
951*a376eb32SXin Li  *
952*a376eb32SXin Li  * @nfa: struct nfattr
953*a376eb32SXin Li  * @maxlen: maximal length of nfattr buffer
954*a376eb32SXin Li  * @type: type for new attribute
955*a376eb32SXin Li  * @data: content of new attribute
956*a376eb32SXin Li  *
957*a376eb32SXin Li  */
nfnl_nfa_addattr16(struct nfattr * nfa,int maxlen,int type,u_int16_t data)958*a376eb32SXin Li int nfnl_nfa_addattr16(struct nfattr *nfa, int maxlen, int type,
959*a376eb32SXin Li 		       u_int16_t data)
960*a376eb32SXin Li {
961*a376eb32SXin Li 	assert(nfa);
962*a376eb32SXin Li 	assert(maxlen > 0);
963*a376eb32SXin Li 	assert(type >= 0);
964*a376eb32SXin Li 
965*a376eb32SXin Li 	return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data));
966*a376eb32SXin Li }
967*a376eb32SXin Li 
968*a376eb32SXin Li /**
969*a376eb32SXin Li  * nfnl_addattr16 - Add u_int16_t attribute to nlmsghdr
970*a376eb32SXin Li  *
971*a376eb32SXin Li  * @n: netlink message header to which attribute is to be added
972*a376eb32SXin Li  * @maxlen: maximum length of netlink message header
973*a376eb32SXin Li  * @type: type of new attribute
974*a376eb32SXin Li  * @data: content of new attribute
975*a376eb32SXin Li  *
976*a376eb32SXin Li  */
nfnl_addattr16(struct nlmsghdr * n,int maxlen,int type,u_int16_t data)977*a376eb32SXin Li int nfnl_addattr16(struct nlmsghdr *n, int maxlen, int type,
978*a376eb32SXin Li 		   u_int16_t data)
979*a376eb32SXin Li {
980*a376eb32SXin Li 	assert(n);
981*a376eb32SXin Li 	assert(maxlen > 0);
982*a376eb32SXin Li 	assert(type >= 0);
983*a376eb32SXin Li 
984*a376eb32SXin Li 	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
985*a376eb32SXin Li }
986*a376eb32SXin Li 
987*a376eb32SXin Li /**
988*a376eb32SXin Li  * nfnl_nfa_addattr32 - Add u_int32_t attribute to struct nfattr
989*a376eb32SXin Li  *
990*a376eb32SXin Li  * @nfa: struct nfattr
991*a376eb32SXin Li  * @maxlen: maximal length of nfattr buffer
992*a376eb32SXin Li  * @type: type for new attribute
993*a376eb32SXin Li  * @data: content of new attribute
994*a376eb32SXin Li  *
995*a376eb32SXin Li  */
nfnl_nfa_addattr32(struct nfattr * nfa,int maxlen,int type,u_int32_t data)996*a376eb32SXin Li int nfnl_nfa_addattr32(struct nfattr *nfa, int maxlen, int type,
997*a376eb32SXin Li 		       u_int32_t data)
998*a376eb32SXin Li {
999*a376eb32SXin Li 	assert(nfa);
1000*a376eb32SXin Li 	assert(maxlen > 0);
1001*a376eb32SXin Li 	assert(type >= 0);
1002*a376eb32SXin Li 
1003*a376eb32SXin Li 	return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data));
1004*a376eb32SXin Li }
1005*a376eb32SXin Li 
1006*a376eb32SXin Li /**
1007*a376eb32SXin Li  * nfnl_addattr32 - Add u_int32_t attribute to nlmsghdr
1008*a376eb32SXin Li  *
1009*a376eb32SXin Li  * @n: netlink message header to which attribute is to be added
1010*a376eb32SXin Li  * @maxlen: maximum length of netlink message header
1011*a376eb32SXin Li  * @type: type of new attribute
1012*a376eb32SXin Li  * @data: content of new attribute
1013*a376eb32SXin Li  *
1014*a376eb32SXin Li  */
nfnl_addattr32(struct nlmsghdr * n,int maxlen,int type,u_int32_t data)1015*a376eb32SXin Li int nfnl_addattr32(struct nlmsghdr *n, int maxlen, int type,
1016*a376eb32SXin Li 		   u_int32_t data)
1017*a376eb32SXin Li {
1018*a376eb32SXin Li 	assert(n);
1019*a376eb32SXin Li 	assert(maxlen > 0);
1020*a376eb32SXin Li 	assert(type >= 0);
1021*a376eb32SXin Li 
1022*a376eb32SXin Li 	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
1023*a376eb32SXin Li }
1024*a376eb32SXin Li 
1025*a376eb32SXin Li /**
1026*a376eb32SXin Li  * nfnl_parse_attr - Parse a list of nfattrs into a pointer array
1027*a376eb32SXin Li  *
1028*a376eb32SXin Li  * @tb: pointer array, will be filled in (output)
1029*a376eb32SXin Li  * @max: size of pointer array
1030*a376eb32SXin Li  * @nfa: pointer to list of nfattrs
1031*a376eb32SXin Li  * @len: length of 'nfa'
1032*a376eb32SXin Li  *
1033*a376eb32SXin Li  * The returned value is equal to the number of remaining bytes of the netlink
1034*a376eb32SXin Li  * message that cannot be parsed.
1035*a376eb32SXin Li  */
nfnl_parse_attr(struct nfattr * tb[],int max,struct nfattr * nfa,int len)1036*a376eb32SXin Li int nfnl_parse_attr(struct nfattr *tb[], int max, struct nfattr *nfa, int len)
1037*a376eb32SXin Li {
1038*a376eb32SXin Li 	assert(tb);
1039*a376eb32SXin Li 	assert(max > 0);
1040*a376eb32SXin Li 	assert(nfa);
1041*a376eb32SXin Li 
1042*a376eb32SXin Li 	memset(tb, 0, sizeof(struct nfattr *) * max);
1043*a376eb32SXin Li 
1044*a376eb32SXin Li 	while (NFA_OK(nfa, len)) {
1045*a376eb32SXin Li 		if (NFA_TYPE(nfa) <= max)
1046*a376eb32SXin Li 			tb[NFA_TYPE(nfa)-1] = nfa;
1047*a376eb32SXin Li                 nfa = NFA_NEXT(nfa,len);
1048*a376eb32SXin Li 	}
1049*a376eb32SXin Li 
1050*a376eb32SXin Li 	return len;
1051*a376eb32SXin Li }
1052*a376eb32SXin Li 
1053*a376eb32SXin Li /**
1054*a376eb32SXin Li  * nfnl_build_nfa_iovec - Build two iovec's from tag, length and value
1055*a376eb32SXin Li  *
1056*a376eb32SXin Li  * @iov: pointer to array of two 'struct iovec' (caller-allocated)
1057*a376eb32SXin Li  * @nfa: pointer to 'struct nfattr' (caller-allocated)
1058*a376eb32SXin Li  * @type: type (tag) of attribute
1059*a376eb32SXin Li  * @len: length of value
1060*a376eb32SXin Li  * @val: pointer to buffer containing 'value'
1061*a376eb32SXin Li  *
1062*a376eb32SXin Li  */
nfnl_build_nfa_iovec(struct iovec * iov,struct nfattr * nfa,u_int16_t type,u_int32_t len,unsigned char * val)1063*a376eb32SXin Li void nfnl_build_nfa_iovec(struct iovec *iov, struct nfattr *nfa,
1064*a376eb32SXin Li 			  u_int16_t type, u_int32_t len, unsigned char *val)
1065*a376eb32SXin Li {
1066*a376eb32SXin Li 	assert(iov);
1067*a376eb32SXin Li 	assert(nfa);
1068*a376eb32SXin Li 
1069*a376eb32SXin Li         /* Set the attribut values */
1070*a376eb32SXin Li         nfa->nfa_len = sizeof(struct nfattr) + len;
1071*a376eb32SXin Li         nfa->nfa_type = type;
1072*a376eb32SXin Li 
1073*a376eb32SXin Li 	iov[0].iov_base = nfa;
1074*a376eb32SXin Li 	iov[0].iov_len = sizeof(*nfa);
1075*a376eb32SXin Li 	iov[1].iov_base = val;
1076*a376eb32SXin Li 	iov[1].iov_len = NFA_ALIGN(len);
1077*a376eb32SXin Li }
1078*a376eb32SXin Li 
1079*a376eb32SXin Li #ifndef SO_RCVBUFFORCE
1080*a376eb32SXin Li #define SO_RCVBUFFORCE	(33)
1081*a376eb32SXin Li #endif
1082*a376eb32SXin Li 
1083*a376eb32SXin Li /**
1084*a376eb32SXin Li  * nfnl_rcvbufsiz - set the socket buffer size
1085*a376eb32SXin Li  * @h: nfnetlink handler
1086*a376eb32SXin Li  * @size: size of the buffer we want to set
1087*a376eb32SXin Li  *
1088*a376eb32SXin Li  * This function sets the new size of the socket buffer. Use this setting
1089*a376eb32SXin Li  * to increase the socket buffer size if your system is reporting ENOBUFS
1090*a376eb32SXin Li  * errors.
1091*a376eb32SXin Li  *
1092*a376eb32SXin Li  * This function returns the new size of the socket buffer.
1093*a376eb32SXin Li  */
nfnl_rcvbufsiz(const struct nfnl_handle * h,unsigned int size)1094*a376eb32SXin Li unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, unsigned int size)
1095*a376eb32SXin Li {
1096*a376eb32SXin Li 	int status;
1097*a376eb32SXin Li 	socklen_t socklen = sizeof(size);
1098*a376eb32SXin Li 	unsigned int read_size = 0;
1099*a376eb32SXin Li 
1100*a376eb32SXin Li 	assert(h);
1101*a376eb32SXin Li 
1102*a376eb32SXin Li 	/* first we try the FORCE option, which is introduced in kernel
1103*a376eb32SXin Li 	 * 2.6.14 to give "root" the ability to override the system wide
1104*a376eb32SXin Li 	 * maximum */
1105*a376eb32SXin Li 	status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, socklen);
1106*a376eb32SXin Li 	if (status < 0) {
1107*a376eb32SXin Li 		/* if this didn't work, we try at least to get the system
1108*a376eb32SXin Li 		 * wide maximum (or whatever the user requested) */
1109*a376eb32SXin Li 		setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &size, socklen);
1110*a376eb32SXin Li 	}
1111*a376eb32SXin Li 	getsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &read_size, &socklen);
1112*a376eb32SXin Li 
1113*a376eb32SXin Li 	return read_size;
1114*a376eb32SXin Li }
1115*a376eb32SXin Li 
1116*a376eb32SXin Li /**
1117*a376eb32SXin Li  * nfnl_get_msg_first - get the first message of a multipart netlink message
1118*a376eb32SXin Li  * @h: nfnetlink handle
1119*a376eb32SXin Li  * @buf: data received that we want to process
1120*a376eb32SXin Li  * @len: size of the data received
1121*a376eb32SXin Li  *
1122*a376eb32SXin Li  * This function returns a pointer to the first netlink message contained
1123*a376eb32SXin Li  * in the chunk of data received from certain nfnetlink subsystem.
1124*a376eb32SXin Li  *
1125*a376eb32SXin Li  * On success, a valid address that points to the netlink message is returned.
1126*a376eb32SXin Li  * On error, NULL is returned.
1127*a376eb32SXin Li  */
nfnl_get_msg_first(struct nfnl_handle * h,const unsigned char * buf,size_t len)1128*a376eb32SXin Li struct nlmsghdr *nfnl_get_msg_first(struct nfnl_handle *h,
1129*a376eb32SXin Li 				    const unsigned char *buf,
1130*a376eb32SXin Li 				    size_t len)
1131*a376eb32SXin Li {
1132*a376eb32SXin Li 	struct nlmsghdr *nlh;
1133*a376eb32SXin Li 
1134*a376eb32SXin Li 	assert(h);
1135*a376eb32SXin Li 	assert(buf);
1136*a376eb32SXin Li 	assert(len > 0);
1137*a376eb32SXin Li 
1138*a376eb32SXin Li 	/* first message in buffer */
1139*a376eb32SXin Li 	nlh = (struct nlmsghdr *)buf;
1140*a376eb32SXin Li 	if (!NLMSG_OK(nlh, len))
1141*a376eb32SXin Li 		return NULL;
1142*a376eb32SXin Li 	h->last_nlhdr = nlh;
1143*a376eb32SXin Li 
1144*a376eb32SXin Li 	return nlh;
1145*a376eb32SXin Li }
1146*a376eb32SXin Li 
nfnl_get_msg_next(struct nfnl_handle * h,const unsigned char * buf,size_t len)1147*a376eb32SXin Li struct nlmsghdr *nfnl_get_msg_next(struct nfnl_handle *h,
1148*a376eb32SXin Li 				   const unsigned char *buf,
1149*a376eb32SXin Li 				   size_t len)
1150*a376eb32SXin Li {
1151*a376eb32SXin Li 	struct nlmsghdr *nlh;
1152*a376eb32SXin Li 	size_t remain_len;
1153*a376eb32SXin Li 
1154*a376eb32SXin Li 	assert(h);
1155*a376eb32SXin Li 	assert(buf);
1156*a376eb32SXin Li 	assert(len > 0);
1157*a376eb32SXin Li 
1158*a376eb32SXin Li 	/* if last header in handle not inside this buffer,
1159*a376eb32SXin Li 	 * drop reference to last header */
1160*a376eb32SXin Li 	if (!h->last_nlhdr ||
1161*a376eb32SXin Li 	    (unsigned char *)h->last_nlhdr >= (buf + len)  ||
1162*a376eb32SXin Li 	    (unsigned char *)h->last_nlhdr < buf) {
1163*a376eb32SXin Li 		h->last_nlhdr = NULL;
1164*a376eb32SXin Li 		return NULL;
1165*a376eb32SXin Li 	}
1166*a376eb32SXin Li 
1167*a376eb32SXin Li 	/* n-th part of multipart message */
1168*a376eb32SXin Li 	if (h->last_nlhdr->nlmsg_type == NLMSG_DONE ||
1169*a376eb32SXin Li 	    h->last_nlhdr->nlmsg_flags & NLM_F_MULTI) {
1170*a376eb32SXin Li 		/* if last part in multipart message or no
1171*a376eb32SXin Li 		 * multipart message at all, return */
1172*a376eb32SXin Li 		h->last_nlhdr = NULL;
1173*a376eb32SXin Li 		return NULL;
1174*a376eb32SXin Li 	}
1175*a376eb32SXin Li 
1176*a376eb32SXin Li 	remain_len = (len - ((unsigned char *)h->last_nlhdr - buf));
1177*a376eb32SXin Li 	nlh = NLMSG_NEXT(h->last_nlhdr, remain_len);
1178*a376eb32SXin Li 
1179*a376eb32SXin Li 	if (!NLMSG_OK(nlh, remain_len)) {
1180*a376eb32SXin Li 		h->last_nlhdr = NULL;
1181*a376eb32SXin Li 		return NULL;
1182*a376eb32SXin Li 	}
1183*a376eb32SXin Li 
1184*a376eb32SXin Li 	h->last_nlhdr = nlh;
1185*a376eb32SXin Li 
1186*a376eb32SXin Li 	return nlh;
1187*a376eb32SXin Li }
1188*a376eb32SXin Li 
1189*a376eb32SXin Li /**
1190*a376eb32SXin Li  * nfnl_callback_register - register a callback for a certain message type
1191*a376eb32SXin Li  * @ssh: nfnetlink subsys handler
1192*a376eb32SXin Li  * @type: subsys call
1193*a376eb32SXin Li  * @cb: nfnetlink callback to be registered
1194*a376eb32SXin Li  *
1195*a376eb32SXin Li  * On success, 0 is returned. On error, -1 is returned and errno is set
1196*a376eb32SXin Li  * appropiately.
1197*a376eb32SXin Li  */
nfnl_callback_register(struct nfnl_subsys_handle * ssh,u_int8_t type,struct nfnl_callback * cb)1198*a376eb32SXin Li int nfnl_callback_register(struct nfnl_subsys_handle *ssh,
1199*a376eb32SXin Li 			   u_int8_t type, struct nfnl_callback *cb)
1200*a376eb32SXin Li {
1201*a376eb32SXin Li 	assert(ssh);
1202*a376eb32SXin Li 	assert(cb);
1203*a376eb32SXin Li 
1204*a376eb32SXin Li 	if (type >= ssh->cb_count) {
1205*a376eb32SXin Li 		errno = EINVAL;
1206*a376eb32SXin Li 		return -1;
1207*a376eb32SXin Li 	}
1208*a376eb32SXin Li 
1209*a376eb32SXin Li 	memcpy(&ssh->cb[type], cb, sizeof(*cb));
1210*a376eb32SXin Li 
1211*a376eb32SXin Li 	return 0;
1212*a376eb32SXin Li }
1213*a376eb32SXin Li 
1214*a376eb32SXin Li /**
1215*a376eb32SXin Li  * nfnl_callback_unregister - unregister a certain callback
1216*a376eb32SXin Li  * @ssh: nfnetlink subsys handler
1217*a376eb32SXin Li  * @type: subsys call
1218*a376eb32SXin Li  *
1219*a376eb32SXin Li  * On sucess, 0 is returned. On error, -1 is returned and errno is
1220*a376eb32SXin Li  * set appropiately.
1221*a376eb32SXin Li  */
nfnl_callback_unregister(struct nfnl_subsys_handle * ssh,u_int8_t type)1222*a376eb32SXin Li int nfnl_callback_unregister(struct nfnl_subsys_handle *ssh, u_int8_t type)
1223*a376eb32SXin Li {
1224*a376eb32SXin Li 	assert(ssh);
1225*a376eb32SXin Li 
1226*a376eb32SXin Li 	if (type >= ssh->cb_count) {
1227*a376eb32SXin Li 		errno = EINVAL;
1228*a376eb32SXin Li 		return -1;
1229*a376eb32SXin Li 	}
1230*a376eb32SXin Li 
1231*a376eb32SXin Li 	ssh->cb[type].call = NULL;
1232*a376eb32SXin Li 
1233*a376eb32SXin Li 	return 0;
1234*a376eb32SXin Li }
1235*a376eb32SXin Li 
nfnl_check_attributes(const struct nfnl_handle * h,const struct nlmsghdr * nlh,struct nfattr * nfa[])1236*a376eb32SXin Li int nfnl_check_attributes(const struct nfnl_handle *h,
1237*a376eb32SXin Li 			 const struct nlmsghdr *nlh,
1238*a376eb32SXin Li 			 struct nfattr *nfa[])
1239*a376eb32SXin Li {
1240*a376eb32SXin Li 	assert(h);
1241*a376eb32SXin Li 	assert(nlh);
1242*a376eb32SXin Li 	assert(nfa);
1243*a376eb32SXin Li 
1244*a376eb32SXin Li 	int min_len;
1245*a376eb32SXin Li 	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
1246*a376eb32SXin Li 	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
1247*a376eb32SXin Li 	const struct nfnl_subsys_handle *ssh;
1248*a376eb32SXin Li 	struct nfnl_callback *cb;
1249*a376eb32SXin Li 
1250*a376eb32SXin Li 	if (subsys_id > NFNL_MAX_SUBSYS)
1251*a376eb32SXin Li 		return -EINVAL;
1252*a376eb32SXin Li 
1253*a376eb32SXin Li 	ssh = &h->subsys[subsys_id];
1254*a376eb32SXin Li  	cb = &ssh->cb[type];
1255*a376eb32SXin Li 
1256*a376eb32SXin Li #if 1
1257*a376eb32SXin Li 	/* checks need to be enabled as soon as this is called from
1258*a376eb32SXin Li 	 * somebody else than __nfnl_handle_msg */
1259*a376eb32SXin Li 	if (type >= ssh->cb_count)
1260*a376eb32SXin Li 		return -EINVAL;
1261*a376eb32SXin Li 
1262*a376eb32SXin Li 	min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
1263*a376eb32SXin Li 	if (nlh->nlmsg_len < min_len)
1264*a376eb32SXin Li 		return -EINVAL;
1265*a376eb32SXin Li #endif
1266*a376eb32SXin Li 	memset(nfa, 0, sizeof(struct nfattr *) * cb->attr_count);
1267*a376eb32SXin Li 
1268*a376eb32SXin Li 	if (nlh->nlmsg_len > min_len) {
1269*a376eb32SXin Li 		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
1270*a376eb32SXin Li 		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
1271*a376eb32SXin Li 
1272*a376eb32SXin Li 		while (NFA_OK(attr, attrlen)) {
1273*a376eb32SXin Li 			unsigned int flavor = NFA_TYPE(attr);
1274*a376eb32SXin Li 			if (flavor) {
1275*a376eb32SXin Li 				if (flavor > cb->attr_count) {
1276*a376eb32SXin Li 					/* we have received an attribute from
1277*a376eb32SXin Li 					 * the kernel which we don't understand
1278*a376eb32SXin Li 					 * yet. We have to silently ignore this
1279*a376eb32SXin Li 					 * for the sake of future compatibility */
1280*a376eb32SXin Li 					attr = NFA_NEXT(attr, attrlen);
1281*a376eb32SXin Li 					continue;
1282*a376eb32SXin Li 				}
1283*a376eb32SXin Li 				nfa[flavor - 1] = attr;
1284*a376eb32SXin Li 			}
1285*a376eb32SXin Li 			attr = NFA_NEXT(attr, attrlen);
1286*a376eb32SXin Li 		}
1287*a376eb32SXin Li 	}
1288*a376eb32SXin Li 
1289*a376eb32SXin Li 	return 0;
1290*a376eb32SXin Li }
1291*a376eb32SXin Li 
__nfnl_handle_msg(struct nfnl_handle * h,struct nlmsghdr * nlh,int len)1292*a376eb32SXin Li static int __nfnl_handle_msg(struct nfnl_handle *h, struct nlmsghdr *nlh,
1293*a376eb32SXin Li 			     int len)
1294*a376eb32SXin Li {
1295*a376eb32SXin Li 	struct nfnl_subsys_handle *ssh;
1296*a376eb32SXin Li 	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
1297*a376eb32SXin Li 	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
1298*a376eb32SXin Li 	int err = 0;
1299*a376eb32SXin Li 
1300*a376eb32SXin Li 	if (subsys_id > NFNL_MAX_SUBSYS)
1301*a376eb32SXin Li 		return -1;
1302*a376eb32SXin Li 
1303*a376eb32SXin Li 	ssh = &h->subsys[subsys_id];
1304*a376eb32SXin Li 
1305*a376eb32SXin Li 	if (nlh->nlmsg_len < NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg))))
1306*a376eb32SXin Li 		return -1;
1307*a376eb32SXin Li 
1308*a376eb32SXin Li 	if (type >= ssh->cb_count)
1309*a376eb32SXin Li 		return -1;
1310*a376eb32SXin Li 
1311*a376eb32SXin Li 	if (ssh->cb[type].attr_count) {
1312*a376eb32SXin Li 		struct nfattr *nfa[ssh->cb[type].attr_count];
1313*a376eb32SXin Li 
1314*a376eb32SXin Li 		err = nfnl_check_attributes(h, nlh, nfa);
1315*a376eb32SXin Li 		if (err < 0)
1316*a376eb32SXin Li 			return err;
1317*a376eb32SXin Li 		if (ssh->cb[type].call)
1318*a376eb32SXin Li 			return ssh->cb[type].call(nlh, nfa, ssh->cb[type].data);
1319*a376eb32SXin Li 	}
1320*a376eb32SXin Li 	return 0;
1321*a376eb32SXin Li }
1322*a376eb32SXin Li 
nfnl_handle_packet(struct nfnl_handle * h,char * buf,int len)1323*a376eb32SXin Li int nfnl_handle_packet(struct nfnl_handle *h, char *buf, int len)
1324*a376eb32SXin Li {
1325*a376eb32SXin Li 
1326*a376eb32SXin Li 	while (len >= NLMSG_SPACE(0)) {
1327*a376eb32SXin Li 		u_int32_t rlen;
1328*a376eb32SXin Li 		struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
1329*a376eb32SXin Li 
1330*a376eb32SXin Li 		if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
1331*a376eb32SXin Li 		    || len < nlh->nlmsg_len)
1332*a376eb32SXin Li 			return -1;
1333*a376eb32SXin Li 
1334*a376eb32SXin Li 		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
1335*a376eb32SXin Li 		if (rlen > len)
1336*a376eb32SXin Li 			rlen = len;
1337*a376eb32SXin Li 
1338*a376eb32SXin Li 		if (__nfnl_handle_msg(h, nlh, rlen) < 0)
1339*a376eb32SXin Li 			return -1;
1340*a376eb32SXin Li 
1341*a376eb32SXin Li 		len -= rlen;
1342*a376eb32SXin Li 		buf += rlen;
1343*a376eb32SXin Li 	}
1344*a376eb32SXin Li 	return 0;
1345*a376eb32SXin Li }
1346*a376eb32SXin Li 
nfnl_is_error(struct nfnl_handle * h,struct nlmsghdr * nlh)1347*a376eb32SXin Li static int nfnl_is_error(struct nfnl_handle *h, struct nlmsghdr *nlh)
1348*a376eb32SXin Li {
1349*a376eb32SXin Li 	/* This message is an ACK or a DONE */
1350*a376eb32SXin Li 	if (nlh->nlmsg_type == NLMSG_ERROR ||
1351*a376eb32SXin Li 	    (nlh->nlmsg_type == NLMSG_DONE &&
1352*a376eb32SXin Li 	     nlh->nlmsg_flags & NLM_F_MULTI)) {
1353*a376eb32SXin Li 		if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) {
1354*a376eb32SXin Li 			errno = EBADMSG;
1355*a376eb32SXin Li 			return 1;
1356*a376eb32SXin Li 		}
1357*a376eb32SXin Li 		errno = -(*((int *)NLMSG_DATA(nlh)));
1358*a376eb32SXin Li 		return 1;
1359*a376eb32SXin Li 	}
1360*a376eb32SXin Li 	return 0;
1361*a376eb32SXin Li }
1362*a376eb32SXin Li 
1363*a376eb32SXin Li /* On error, -1 is returned and errno is set appropiately. On success,
1364*a376eb32SXin Li  * 0 is returned if there is no more data to process, >0 if there is
1365*a376eb32SXin Li  * more data to process */
nfnl_step(struct nfnl_handle * h,struct nlmsghdr * nlh)1366*a376eb32SXin Li static int nfnl_step(struct nfnl_handle *h, struct nlmsghdr *nlh)
1367*a376eb32SXin Li {
1368*a376eb32SXin Li 	struct nfnl_subsys_handle *ssh;
1369*a376eb32SXin Li 	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
1370*a376eb32SXin Li 	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
1371*a376eb32SXin Li 
1372*a376eb32SXin Li 	/* Is this an error message? */
1373*a376eb32SXin Li 	if (nfnl_is_error(h, nlh)) {
1374*a376eb32SXin Li 		/* This is an ACK */
1375*a376eb32SXin Li 		if (errno == 0)
1376*a376eb32SXin Li 			return 0;
1377*a376eb32SXin Li 		/* This an error message */
1378*a376eb32SXin Li 		return -1;
1379*a376eb32SXin Li 	}
1380*a376eb32SXin Li 
1381*a376eb32SXin Li 	/* nfnetlink sanity checks: check for nfgenmsg size */
1382*a376eb32SXin Li 	if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) {
1383*a376eb32SXin Li 		errno = ENOSPC;
1384*a376eb32SXin Li 		return -1;
1385*a376eb32SXin Li 	}
1386*a376eb32SXin Li 
1387*a376eb32SXin Li 	if (subsys_id > NFNL_MAX_SUBSYS) {
1388*a376eb32SXin Li 		errno = ENOENT;
1389*a376eb32SXin Li 		return -1;
1390*a376eb32SXin Li 	}
1391*a376eb32SXin Li 
1392*a376eb32SXin Li 	ssh = &h->subsys[subsys_id];
1393*a376eb32SXin Li 	if (!ssh) {
1394*a376eb32SXin Li 		errno = ENOENT;
1395*a376eb32SXin Li 		return -1;
1396*a376eb32SXin Li 	}
1397*a376eb32SXin Li 
1398*a376eb32SXin Li 	if (type >= ssh->cb_count) {
1399*a376eb32SXin Li 		errno = ENOENT;
1400*a376eb32SXin Li 		return -1;
1401*a376eb32SXin Li 	}
1402*a376eb32SXin Li 
1403*a376eb32SXin Li 	if (ssh->cb[type].attr_count) {
1404*a376eb32SXin Li 		int err;
1405*a376eb32SXin Li 		struct nfattr *tb[ssh->cb[type].attr_count];
1406*a376eb32SXin Li 		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
1407*a376eb32SXin Li 		int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
1408*a376eb32SXin Li 		int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
1409*a376eb32SXin Li 
1410*a376eb32SXin Li 		err = nfnl_parse_attr(tb, ssh->cb[type].attr_count, attr, len);
1411*a376eb32SXin Li 		if (err == -1)
1412*a376eb32SXin Li 			return -1;
1413*a376eb32SXin Li 
1414*a376eb32SXin Li 		if (ssh->cb[type].call) {
1415*a376eb32SXin Li 			/*
1416*a376eb32SXin Li 			 * On error, the callback returns NFNL_CB_FAILURE and
1417*a376eb32SXin Li 			 * errno must be explicitely set. On success,
1418*a376eb32SXin Li 			 * NFNL_CB_STOP is returned and we're done, otherwise
1419*a376eb32SXin Li 			 * NFNL_CB_CONTINUE means that we want to continue
1420*a376eb32SXin Li 			 * data processing.
1421*a376eb32SXin Li 			 */
1422*a376eb32SXin Li 			return ssh->cb[type].call(nlh,
1423*a376eb32SXin Li 						  tb,
1424*a376eb32SXin Li 						  ssh->cb[type].data);
1425*a376eb32SXin Li 		}
1426*a376eb32SXin Li 	}
1427*a376eb32SXin Li 	/* no callback set, continue data processing */
1428*a376eb32SXin Li 	return 1;
1429*a376eb32SXin Li }
1430*a376eb32SXin Li 
1431*a376eb32SXin Li /**
1432*a376eb32SXin Li  * nfnl_process - process data coming from a nfnetlink system
1433*a376eb32SXin Li  * @h: nfnetlink handler
1434*a376eb32SXin Li  * @buf: buffer that contains the netlink message
1435*a376eb32SXin Li  * @len: size of the data contained in the buffer (not the buffer size)
1436*a376eb32SXin Li  *
1437*a376eb32SXin Li  * This function processes all the nfnetlink messages contained inside a
1438*a376eb32SXin Li  * buffer. It performs the appropiate sanity checks and passes the message
1439*a376eb32SXin Li  * to a certain handler that is registered via register_callback().
1440*a376eb32SXin Li  *
1441*a376eb32SXin Li  * On success, NFNL_CB_STOP is returned if the data processing has finished.
1442*a376eb32SXin Li  * If a value NFNL_CB_CONTINUE is returned, then there is more data to
1443*a376eb32SXin Li  * process. On error, NFNL_CB_CONTINUE is returned and errno is set to the
1444*a376eb32SXin Li  * appropiate value.
1445*a376eb32SXin Li  *
1446*a376eb32SXin Li  * In case that the callback returns NFNL_CB_FAILURE, errno may be set by
1447*a376eb32SXin Li  * the library client. If your callback decides not to process data anymore
1448*a376eb32SXin Li  * for any reason, then it must return NFNL_CB_STOP. Otherwise, if the
1449*a376eb32SXin Li  * callback continues the processing NFNL_CB_CONTINUE is returned.
1450*a376eb32SXin Li  */
nfnl_process(struct nfnl_handle * h,const unsigned char * buf,size_t len)1451*a376eb32SXin Li int nfnl_process(struct nfnl_handle *h, const unsigned char *buf, size_t len)
1452*a376eb32SXin Li {
1453*a376eb32SXin Li 	int ret = 0;
1454*a376eb32SXin Li 	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
1455*a376eb32SXin Li 
1456*a376eb32SXin Li 	assert(h);
1457*a376eb32SXin Li 	assert(buf);
1458*a376eb32SXin Li 	assert(len > 0);
1459*a376eb32SXin Li 
1460*a376eb32SXin Li 	/* check for out of sequence message */
1461*a376eb32SXin Li 	if (nlh->nlmsg_seq && nlh->nlmsg_seq != h->seq) {
1462*a376eb32SXin Li 		errno = EILSEQ;
1463*a376eb32SXin Li 		return -1;
1464*a376eb32SXin Li 	}
1465*a376eb32SXin Li 	while (len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) {
1466*a376eb32SXin Li 
1467*a376eb32SXin Li 		ret = nfnl_step(h, nlh);
1468*a376eb32SXin Li 		if (ret <= NFNL_CB_STOP)
1469*a376eb32SXin Li 			break;
1470*a376eb32SXin Li 
1471*a376eb32SXin Li 		nlh = NLMSG_NEXT(nlh, len);
1472*a376eb32SXin Li 	}
1473*a376eb32SXin Li 	return ret;
1474*a376eb32SXin Li }
1475*a376eb32SXin Li 
1476*a376eb32SXin Li /*
1477*a376eb32SXin Li  * New parsing functions based on iterators
1478*a376eb32SXin Li  */
1479*a376eb32SXin Li 
1480*a376eb32SXin Li struct nfnl_iterator {
1481*a376eb32SXin Li 	struct nlmsghdr *nlh;
1482*a376eb32SXin Li 	unsigned int	len;
1483*a376eb32SXin Li };
1484*a376eb32SXin Li 
1485*a376eb32SXin Li /**
1486*a376eb32SXin Li  * nfnl_iterator_create: create an nfnetlink iterator
1487*a376eb32SXin Li  * @h: nfnetlink handler
1488*a376eb32SXin Li  * @buf: buffer that contains data received from a nfnetlink system
1489*a376eb32SXin Li  * @len: size of the data contained in the buffer (not the buffer size)
1490*a376eb32SXin Li  *
1491*a376eb32SXin Li  * This function creates an iterator that can be used to parse nfnetlink
1492*a376eb32SXin Li  * message one by one. The iterator gives more control to the programmer
1493*a376eb32SXin Li  * in the messages processing.
1494*a376eb32SXin Li  *
1495*a376eb32SXin Li  * On success, a valid address is returned. On error, NULL is returned
1496*a376eb32SXin Li  * and errno is set to the appropiate value.
1497*a376eb32SXin Li  */
1498*a376eb32SXin Li struct nfnl_iterator *
nfnl_iterator_create(const struct nfnl_handle * h,const char * buf,size_t len)1499*a376eb32SXin Li nfnl_iterator_create(const struct nfnl_handle *h,
1500*a376eb32SXin Li 		     const char *buf,
1501*a376eb32SXin Li 		     size_t len)
1502*a376eb32SXin Li {
1503*a376eb32SXin Li 	struct nlmsghdr *nlh;
1504*a376eb32SXin Li 	struct nfnl_iterator *it;
1505*a376eb32SXin Li 
1506*a376eb32SXin Li 	assert(h);
1507*a376eb32SXin Li 	assert(buf);
1508*a376eb32SXin Li 	assert(len > 0);
1509*a376eb32SXin Li 
1510*a376eb32SXin Li 	it = malloc(sizeof(struct nfnl_iterator));
1511*a376eb32SXin Li 	if (!it) {
1512*a376eb32SXin Li 		errno = ENOMEM;
1513*a376eb32SXin Li 		return NULL;
1514*a376eb32SXin Li 	}
1515*a376eb32SXin Li 
1516*a376eb32SXin Li 	/* first message in buffer */
1517*a376eb32SXin Li 	nlh = (struct nlmsghdr *)buf;
1518*a376eb32SXin Li 	if (len < NLMSG_SPACE(0) || !NLMSG_OK(nlh, len)) {
1519*a376eb32SXin Li 		free(it);
1520*a376eb32SXin Li 		errno = EBADMSG;
1521*a376eb32SXin Li 		return NULL;
1522*a376eb32SXin Li 	}
1523*a376eb32SXin Li 	it->nlh = nlh;
1524*a376eb32SXin Li 	it->len = len;
1525*a376eb32SXin Li 
1526*a376eb32SXin Li 	return it;
1527*a376eb32SXin Li }
1528*a376eb32SXin Li 
1529*a376eb32SXin Li /**
1530*a376eb32SXin Li  * nfnl_iterator_destroy - destroy a nfnetlink iterator
1531*a376eb32SXin Li  * @it: nfnetlink iterator
1532*a376eb32SXin Li  *
1533*a376eb32SXin Li  * This function destroys a certain iterator. Nothing is returned.
1534*a376eb32SXin Li  */
nfnl_iterator_destroy(struct nfnl_iterator * it)1535*a376eb32SXin Li void nfnl_iterator_destroy(struct nfnl_iterator *it)
1536*a376eb32SXin Li {
1537*a376eb32SXin Li 	assert(it);
1538*a376eb32SXin Li 	free(it);
1539*a376eb32SXin Li }
1540*a376eb32SXin Li 
1541*a376eb32SXin Li /**
1542*a376eb32SXin Li  * nfnl_iterator_process - process a nfnetlink message
1543*a376eb32SXin Li  * @h: nfnetlink handler
1544*a376eb32SXin Li  * @it: nfnetlink iterator that contains the current message to be proccesed
1545*a376eb32SXin Li  *
1546*a376eb32SXin Li  * This function process just the current message selected by the iterator.
1547*a376eb32SXin Li  * On success, a value greater or equal to zero is returned. On error,
1548*a376eb32SXin Li  * -1 is returned and errno is appropiately set.
1549*a376eb32SXin Li  */
nfnl_iterator_process(struct nfnl_handle * h,struct nfnl_iterator * it)1550*a376eb32SXin Li int nfnl_iterator_process(struct nfnl_handle *h, struct nfnl_iterator *it)
1551*a376eb32SXin Li {
1552*a376eb32SXin Li 	assert(h);
1553*a376eb32SXin Li 	assert(it->nlh);
1554*a376eb32SXin Li 
1555*a376eb32SXin Li         /* check for out of sequence message */
1556*a376eb32SXin Li 	if (it->nlh->nlmsg_seq && it->nlh->nlmsg_seq != h->seq) {
1557*a376eb32SXin Li 		errno = EILSEQ;
1558*a376eb32SXin Li 		return -1;
1559*a376eb32SXin Li 	}
1560*a376eb32SXin Li 	if (it->len < NLMSG_SPACE(0) || !NLMSG_OK(it->nlh, it->len)) {
1561*a376eb32SXin Li 		errno = EBADMSG;
1562*a376eb32SXin Li 		return -1;
1563*a376eb32SXin Li 	}
1564*a376eb32SXin Li 	return nfnl_step(h, it->nlh);
1565*a376eb32SXin Li }
1566*a376eb32SXin Li 
1567*a376eb32SXin Li /**
1568*a376eb32SXin Li  * nfnl_iterator_next - get the next message hold by the iterator
1569*a376eb32SXin Li  * @h: nfnetlink handler
1570*a376eb32SXin Li  * @it: nfnetlink iterator that contains the current message processed
1571*a376eb32SXin Li  *
1572*a376eb32SXin Li  * This function update the current message to be processed pointer.
1573*a376eb32SXin Li  * It returns NFNL_CB_CONTINUE if there is still more messages to be
1574*a376eb32SXin Li  * processed, otherwise NFNL_CB_STOP is returned.
1575*a376eb32SXin Li  */
nfnl_iterator_next(const struct nfnl_handle * h,struct nfnl_iterator * it)1576*a376eb32SXin Li int nfnl_iterator_next(const struct nfnl_handle *h, struct nfnl_iterator *it)
1577*a376eb32SXin Li {
1578*a376eb32SXin Li 	assert(h);
1579*a376eb32SXin Li 	assert(it);
1580*a376eb32SXin Li 
1581*a376eb32SXin Li 	it->nlh = NLMSG_NEXT(it->nlh, it->len);
1582*a376eb32SXin Li 	if (!it->nlh)
1583*a376eb32SXin Li 		return 0;
1584*a376eb32SXin Li 	return 1;
1585*a376eb32SXin Li }
1586*a376eb32SXin Li 
1587*a376eb32SXin Li /**
1588*a376eb32SXin Li  * nfnl_catch - get responses from the nfnetlink system and process them
1589*a376eb32SXin Li  * @h: nfnetlink handler
1590*a376eb32SXin Li *
1591*a376eb32SXin Li  * This function handles the data received from the nfnetlink system.
1592*a376eb32SXin Li  * For example, events generated by one of the subsystems. The message
1593*a376eb32SXin Li  * is passed to the callback registered via callback_register(). Note that
1594*a376eb32SXin Li  * this a replacement of nfnl_listen and its use is recommended.
1595*a376eb32SXin Li  *
1596*a376eb32SXin Li  * On success, 0 is returned. On error, a -1 is returned. If you do not
1597*a376eb32SXin Li  * want to listen to events anymore, then your callback must return
1598*a376eb32SXin Li  * NFNL_CB_STOP.
1599*a376eb32SXin Li  *
1600*a376eb32SXin Li  * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
1601*a376eb32SXin Li  * that case is possible that the information requested is incomplete.
1602*a376eb32SXin Li  */
nfnl_catch(struct nfnl_handle * h)1603*a376eb32SXin Li int nfnl_catch(struct nfnl_handle *h)
1604*a376eb32SXin Li {
1605*a376eb32SXin Li 	int ret;
1606*a376eb32SXin Li 
1607*a376eb32SXin Li 	assert(h);
1608*a376eb32SXin Li 
1609*a376eb32SXin Li 	while (1) {
1610*a376eb32SXin Li 		unsigned char buf[h->rcv_buffer_size]
1611*a376eb32SXin Li 			__attribute__ ((aligned));
1612*a376eb32SXin Li 
1613*a376eb32SXin Li 		ret = nfnl_recv(h, buf, sizeof(buf));
1614*a376eb32SXin Li 		if (ret == -1) {
1615*a376eb32SXin Li 			/* interrupted syscall must retry */
1616*a376eb32SXin Li 			if (errno == EINTR)
1617*a376eb32SXin Li 				continue;
1618*a376eb32SXin Li 			break;
1619*a376eb32SXin Li 		}
1620*a376eb32SXin Li 
1621*a376eb32SXin Li 		ret = nfnl_process(h, buf, ret);
1622*a376eb32SXin Li 		if (ret <= NFNL_CB_STOP)
1623*a376eb32SXin Li 			break;
1624*a376eb32SXin Li 	}
1625*a376eb32SXin Li 
1626*a376eb32SXin Li 	return ret;
1627*a376eb32SXin Li }
1628*a376eb32SXin Li 
1629*a376eb32SXin Li /**
1630*a376eb32SXin Li  * nfnl_query - request/response communication challenge
1631*a376eb32SXin Li  * @h: nfnetlink handler
1632*a376eb32SXin Li  * @nlh: nfnetlink message to be sent
1633*a376eb32SXin Li  *
1634*a376eb32SXin Li  * This function sends a nfnetlink message to a certain subsystem and
1635*a376eb32SXin Li  * receives the response messages associated, such messages are passed to
1636*a376eb32SXin Li  * the callback registered via register_callback(). Note that this function
1637*a376eb32SXin Li  * is a replacement for nfnl_talk, its use is recommended.
1638*a376eb32SXin Li  *
1639*a376eb32SXin Li  * On success, 0 is returned. On error, a negative is returned. If your
1640*a376eb32SXin Li  * does not want to listen to events anymore, then your callback must
1641*a376eb32SXin Li  * return NFNL_CB_STOP.
1642*a376eb32SXin Li  *
1643*a376eb32SXin Li  * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
1644*a376eb32SXin Li  * that case is possible that the information requested is incomplete.
1645*a376eb32SXin Li  */
nfnl_query(struct nfnl_handle * h,struct nlmsghdr * nlh)1646*a376eb32SXin Li int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh)
1647*a376eb32SXin Li {
1648*a376eb32SXin Li 	assert(h);
1649*a376eb32SXin Li 	assert(nlh);
1650*a376eb32SXin Li 
1651*a376eb32SXin Li 	if (nfnl_send(h, nlh) == -1)
1652*a376eb32SXin Li 		return -1;
1653*a376eb32SXin Li 
1654*a376eb32SXin Li 	return nfnl_catch(h);
1655*a376eb32SXin Li }
1656