Blame src/libnfnetlink.c

Packit Service f5259b
/* libnfnetlink.c: generic library for communication with netfilter
Packit Service f5259b
 *
Packit Service f5259b
 * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
Packit Service f5259b
 * (C) 2006-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
Packit Service f5259b
 *
Packit Service f5259b
 * Based on some original ideas from Jay Schulist <jschlst@samba.org>
Packit Service f5259b
 *
Packit Service f5259b
 * Development of this code funded by Astaro AG (http://www.astaro.com)
Packit Service f5259b
 *
Packit Service f5259b
 * This program is free software; you can redistribute it and/or modify it
Packit Service f5259b
 * under the terms of the GNU General Public License version 2 as published
Packit Service f5259b
 * by the Free Software Foundation.
Packit Service f5259b
 *
Packit Service f5259b
 * 2005-09-14 Pablo Neira Ayuso <pablo@netfilter.org>: 
Packit Service f5259b
 * 	Define structure nfnlhdr
Packit Service f5259b
 * 	Added __be64_to_cpu function
Packit Service f5259b
 *	Use NFA_TYPE macro to get the attribute type
Packit Service f5259b
 *
Packit Service f5259b
 * 2006-01-14 Harald Welte <laforge@netfilter.org>:
Packit Service f5259b
 * 	introduce nfnl_subsys_handle
Packit Service f5259b
 *
Packit Service f5259b
 * 2006-01-15 Pablo Neira Ayuso <pablo@netfilter.org>:
Packit Service f5259b
 * 	set missing subsys_id in nfnl_subsys_open
Packit Service f5259b
 * 	set missing nfnlh->local.nl_pid in nfnl_open
Packit Service f5259b
 *
Packit Service f5259b
 * 2006-01-26 Harald Welte <laforge@netfilter.org>:
Packit Service f5259b
 * 	remove bogus nfnlh->local.nl_pid from nfnl_open ;)
Packit Service f5259b
 * 	add 16bit attribute functions
Packit Service f5259b
 *
Packit Service f5259b
 * 2006-07-03 Pablo Neira Ayuso <pablo@netfilter.org>:
Packit Service f5259b
 * 	add iterator API
Packit Service f5259b
 * 	add replacements for nfnl_listen and nfnl_talk
Packit Service f5259b
 * 	fix error handling
Packit Service f5259b
 * 	add assertions
Packit Service f5259b
 * 	add documentation
Packit Service f5259b
 * 	minor cleanups
Packit Service f5259b
 */
Packit Service f5259b
Packit Service f5259b
#include <stdlib.h>
Packit Service f5259b
#include <stdio.h>
Packit Service f5259b
#include <unistd.h>
Packit Service f5259b
#include <errno.h>
Packit Service f5259b
#include <string.h>
Packit Service f5259b
#include <time.h>
Packit Service f5259b
#include <netinet/in.h>
Packit Service f5259b
#include <assert.h>
Packit Service f5259b
#include <linux/types.h>
Packit Service f5259b
#include <sys/socket.h>
Packit Service f5259b
#include <sys/uio.h>
Packit Service f5259b
Packit Service f5259b
#include <linux/netlink.h>
Packit Service f5259b
Packit Service f5259b
#include <libnfnetlink/libnfnetlink.h>
Packit Service f5259b
Packit Service f5259b
#ifndef NETLINK_ADD_MEMBERSHIP
Packit Service f5259b
#define NETLINK_ADD_MEMBERSHIP 1
Packit Service f5259b
#endif
Packit Service f5259b
Packit Service f5259b
#ifndef SOL_NETLINK
Packit Service f5259b
#define SOL_NETLINK 270
Packit Service f5259b
#endif
Packit Service f5259b
Packit Service f5259b
Packit Service f5259b
#define nfnl_error(format, args...) \
Packit Service f5259b
	fprintf(stderr, "%s: " format "\n", __FUNCTION__, ## args)
Packit Service f5259b
Packit Service f5259b
#ifdef _NFNL_DEBUG
Packit Service f5259b
#define nfnl_debug_dump_packet nfnl_dump_packet
Packit Service f5259b
#else
Packit Service f5259b
#define nfnl_debug_dump_packet(a, b, ...)
Packit Service f5259b
#endif
Packit Service f5259b
Packit Service f5259b
struct nfnl_subsys_handle {
Packit Service f5259b
	struct nfnl_handle 	*nfnlh;
Packit Service f5259b
	u_int32_t		subscriptions;
Packit Service f5259b
	u_int8_t		subsys_id;
Packit Service f5259b
	u_int8_t		cb_count;
Packit Service f5259b
	struct nfnl_callback 	*cb;	/* array of callbacks */
Packit Service f5259b
};
Packit Service f5259b
Packit Service f5259b
#define		NFNL_MAX_SUBSYS			16 /* enough for now */
Packit Service f5259b
Packit Service f5259b
#define NFNL_F_SEQTRACK_ENABLED		(1 << 0)
Packit Service f5259b
Packit Service f5259b
struct nfnl_handle {
Packit Service f5259b
	int			fd;
Packit Service f5259b
	struct sockaddr_nl	local;
Packit Service f5259b
	struct sockaddr_nl	peer;
Packit Service f5259b
	u_int32_t		subscriptions;
Packit Service f5259b
	u_int32_t		seq;
Packit Service f5259b
	u_int32_t		dump;
Packit Service f5259b
	u_int32_t		rcv_buffer_size;	/* for nfnl_catch */
Packit Service f5259b
	u_int32_t		flags;
Packit Service f5259b
	struct nlmsghdr 	*last_nlhdr;
Packit Service f5259b
	struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1];
Packit Service f5259b
};
Packit Service f5259b
Packit Service f5259b
void nfnl_dump_packet(struct nlmsghdr *nlh, int received_len, char *desc)
Packit Service f5259b
{
Packit Service f5259b
	void *nlmsg_data = NLMSG_DATA(nlh);
Packit Service f5259b
	struct nfattr *nfa = NFM_NFA(NLMSG_DATA(nlh));
Packit Service f5259b
	int len = NFM_PAYLOAD(nlh);
Packit Service f5259b
Packit Service f5259b
	printf("%s called from %s\n", __FUNCTION__, desc);
Packit Service f5259b
	printf("  nlmsghdr = %p, received_len = %u\n", nlh, received_len);
Packit Service f5259b
	printf("  NLMSG_DATA(nlh) = %p (+%td bytes)\n", nlmsg_data,
Packit Service f5259b
	       (nlmsg_data - (void *)nlh));
Packit Service f5259b
	printf("  NFM_NFA(NLMSG_DATA(nlh)) = %p (+%td bytes)\n",
Packit Service f5259b
		nfa, ((void *)nfa - (void *)nlh));
Packit Service f5259b
	printf("  NFM_PAYLOAD(nlh) = %u\n", len);
Packit Service f5259b
	printf("  nlmsg_type = %u, nlmsg_len = %u, nlmsg_seq = %u "
Packit Service f5259b
		"nlmsg_flags = 0x%x\n", nlh->nlmsg_type, nlh->nlmsg_len,
Packit Service f5259b
		nlh->nlmsg_seq, nlh->nlmsg_flags);
Packit Service f5259b
Packit Service f5259b
	while (NFA_OK(nfa, len)) {
Packit Service f5259b
		printf("    nfa@%p: nfa_type=%u, nfa_len=%u\n",
Packit Service f5259b
			nfa, NFA_TYPE(nfa), nfa->nfa_len);
Packit Service f5259b
		nfa = NFA_NEXT(nfa,len);
Packit Service f5259b
	}
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_fd - returns the descriptor that identifies the socket
Packit Service f5259b
 * @nfnlh: nfnetlink handler
Packit Service f5259b
 *
Packit Service f5259b
 * Use this function if you need to interact with the socket. Common
Packit Service f5259b
 * scenarios are the use of poll()/select() to achieve multiplexation.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_fd(struct nfnl_handle *h)
Packit Service f5259b
{
Packit Service f5259b
	assert(h);
Packit Service f5259b
	return h->fd;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_portid - returns the Netlink port ID of this socket
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 */
Packit Service f5259b
unsigned int nfnl_portid(const struct nfnl_handle *h)
Packit Service f5259b
{
Packit Service f5259b
	assert(h);
Packit Service f5259b
	return h->local.nl_pid;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
static int recalc_rebind_subscriptions(struct nfnl_handle *nfnlh)
Packit Service f5259b
{
Packit Service f5259b
	int i, err;
Packit Service f5259b
	u_int32_t new_subscriptions = nfnlh->subscriptions;
Packit Service f5259b
Packit Service f5259b
	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
Packit Service f5259b
		new_subscriptions |= nfnlh->subsys[i].subscriptions;
Packit Service f5259b
Packit Service f5259b
	nfnlh->local.nl_groups = new_subscriptions;
Packit Service f5259b
	err = bind(nfnlh->fd, (struct sockaddr *)&nfnlh->local,
Packit Service f5259b
		   sizeof(nfnlh->local));
Packit Service f5259b
	if (err == -1)
Packit Service f5259b
		return -1;
Packit Service f5259b
Packit Service f5259b
	nfnlh->subscriptions = new_subscriptions;
Packit Service f5259b
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_open - open a nfnetlink handler
Packit Service f5259b
 *
Packit Service f5259b
 * This function creates a nfnetlink handler, this is required to establish
Packit Service f5259b
 * a communication between the userspace and the nfnetlink system.
Packit Service f5259b
 *
Packit Service f5259b
 * On success, a valid address that points to a nfnl_handle structure
Packit Service f5259b
 * is returned. On error, NULL is returned and errno is set approapiately.
Packit Service f5259b
 */
Packit Service f5259b
struct nfnl_handle *nfnl_open(void)
Packit Service f5259b
{
Packit Service f5259b
	struct nfnl_handle *nfnlh;
Packit Service f5259b
	unsigned int addr_len;
Packit Service f5259b
Packit Service f5259b
	nfnlh = malloc(sizeof(*nfnlh));
Packit Service f5259b
	if (!nfnlh)
Packit Service f5259b
		return NULL;
Packit Service f5259b
Packit Service f5259b
	memset(nfnlh, 0, sizeof(*nfnlh));
Packit Service f5259b
	nfnlh->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
Packit Service f5259b
	if (nfnlh->fd == -1)
Packit Service f5259b
		goto err_free;
Packit Service f5259b
Packit Service f5259b
	nfnlh->local.nl_family = AF_NETLINK;
Packit Service f5259b
	nfnlh->peer.nl_family = AF_NETLINK;
Packit Service f5259b
Packit Service f5259b
	addr_len = sizeof(nfnlh->local);
Packit Service f5259b
	getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
Packit Service f5259b
	if (addr_len != sizeof(nfnlh->local)) {
Packit Service f5259b
		errno = EINVAL;
Packit Service f5259b
		goto err_close;
Packit Service f5259b
	}
Packit Service f5259b
	if (nfnlh->local.nl_family != AF_NETLINK) {
Packit Service f5259b
		errno = EINVAL;
Packit Service f5259b
		goto err_close;
Packit Service f5259b
	}
Packit Service f5259b
	nfnlh->seq = time(NULL);
Packit Service f5259b
	nfnlh->rcv_buffer_size = NFNL_BUFFSIZE;
Packit Service f5259b
Packit Service f5259b
	/* don't set pid here, only first socket of process has real pid !!! 
Packit Service f5259b
	 * binding to pid '0' will default */
Packit Service f5259b
Packit Service f5259b
	/* let us do the initial bind */
Packit Service f5259b
	if (recalc_rebind_subscriptions(nfnlh) < 0)
Packit Service f5259b
		goto err_close;
Packit Service f5259b
Packit Service f5259b
	/* use getsockname to get the netlink pid that the kernel assigned us */
Packit Service f5259b
	addr_len = sizeof(nfnlh->local);
Packit Service f5259b
	getsockname(nfnlh->fd, (struct sockaddr *)&nfnlh->local, &addr_len);
Packit Service f5259b
	if (addr_len != sizeof(nfnlh->local)) {
Packit Service f5259b
		errno = EINVAL;
Packit Service f5259b
		goto err_close;
Packit Service f5259b
	}
Packit Service f5259b
	/* sequence tracking enabled by default */
Packit Service f5259b
	nfnlh->flags |= NFNL_F_SEQTRACK_ENABLED;
Packit Service f5259b
Packit Service f5259b
	return nfnlh;
Packit Service f5259b
Packit Service f5259b
err_close:
Packit Service f5259b
	close(nfnlh->fd);
Packit Service f5259b
err_free:
Packit Service f5259b
	free(nfnlh);
Packit Service f5259b
	return NULL;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_set_sequence_tracking - set netlink sequence tracking
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 */
Packit Service f5259b
void nfnl_set_sequence_tracking(struct nfnl_handle *h)
Packit Service f5259b
{
Packit Service f5259b
	h->flags |= NFNL_F_SEQTRACK_ENABLED;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_unset_sequence_tracking - set netlink sequence tracking
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 */
Packit Service f5259b
void nfnl_unset_sequence_tracking(struct nfnl_handle *h)
Packit Service f5259b
{
Packit Service f5259b
	h->flags &= ~NFNL_F_SEQTRACK_ENABLED;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_set_rcv_buffer_size - set the size of the receive buffer
Packit Service f5259b
 * @h: libnfnetlink handler
Packit Service f5259b
 * @size: buffer size
Packit Service f5259b
 *
Packit Service f5259b
 * This function sets the size of the receive buffer size, i.e. the size
Packit Service f5259b
 * of the buffer used by nfnl_recv. Default value is 4096 bytes.
Packit Service f5259b
 */
Packit Service f5259b
void nfnl_set_rcv_buffer_size(struct nfnl_handle *h, unsigned int size)
Packit Service f5259b
{
Packit Service f5259b
	h->rcv_buffer_size = size;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_subsys_open - open a netlink subsystem
Packit Service f5259b
 * @nfnlh: libnfnetlink handle
Packit Service f5259b
 * @subsys_id: which nfnetlink subsystem we are interested in
Packit Service f5259b
 * @cb_count: number of callbacks that are used maximum.
Packit Service f5259b
 * @subscriptions: netlink groups we want to be subscribed to
Packit Service f5259b
 *
Packit Service f5259b
 * This function creates a subsystem handler that contains the set of 
Packit Service f5259b
 * callbacks that handle certain types of messages coming from a netfilter
Packit Service f5259b
 * subsystem. Initially the callback set is empty, you can register callbacks
Packit Service f5259b
 * via nfnl_callback_register().
Packit Service f5259b
 *
Packit Service f5259b
 * On error, NULL is returned and errno is set appropiately. On success,
Packit Service f5259b
 * a valid address that points to a nfnl_subsys_handle structure is returned.
Packit Service f5259b
 */
Packit Service f5259b
struct nfnl_subsys_handle *
Packit Service f5259b
nfnl_subsys_open(struct nfnl_handle *nfnlh, u_int8_t subsys_id,
Packit Service f5259b
		 u_int8_t cb_count, u_int32_t subscriptions)
Packit Service f5259b
{
Packit Service f5259b
	struct nfnl_subsys_handle *ssh;
Packit Service f5259b
Packit Service f5259b
	assert(nfnlh);
Packit Service f5259b
Packit Service f5259b
	if (subsys_id > NFNL_MAX_SUBSYS) { 
Packit Service f5259b
		errno = ENOENT;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	ssh = &nfnlh->subsys[subsys_id];
Packit Service f5259b
	if (ssh->cb) {
Packit Service f5259b
		errno = EBUSY;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	ssh->cb = calloc(cb_count, sizeof(*(ssh->cb)));
Packit Service f5259b
	if (!ssh->cb)
Packit Service f5259b
		return NULL;
Packit Service f5259b
Packit Service f5259b
	ssh->nfnlh = nfnlh;
Packit Service f5259b
	ssh->cb_count = cb_count;
Packit Service f5259b
	ssh->subscriptions = subscriptions;
Packit Service f5259b
	ssh->subsys_id = subsys_id;
Packit Service f5259b
Packit Service f5259b
	/* although now we have nfnl_join to subscribe to certain
Packit Service f5259b
	 * groups, just keep this to ensure compatibility */
Packit Service f5259b
	if (recalc_rebind_subscriptions(nfnlh) < 0) {
Packit Service f5259b
		free(ssh->cb);
Packit Service f5259b
		ssh->cb = NULL;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
	
Packit Service f5259b
	return ssh;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_subsys_close - close a nfnetlink subsys handler 
Packit Service f5259b
 * @ssh: nfnetlink subsystem handler
Packit Service f5259b
 *
Packit Service f5259b
 * Release all the callbacks registered in a subsystem handler.
Packit Service f5259b
 */
Packit Service f5259b
void nfnl_subsys_close(struct nfnl_subsys_handle *ssh)
Packit Service f5259b
{
Packit Service f5259b
	assert(ssh);
Packit Service f5259b
Packit Service f5259b
	ssh->subscriptions = 0;
Packit Service f5259b
	ssh->cb_count = 0;
Packit Service f5259b
	if (ssh->cb) {
Packit Service f5259b
		free(ssh->cb);
Packit Service f5259b
		ssh->cb = NULL;
Packit Service f5259b
	}
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_close - close a nfnetlink handler
Packit Service f5259b
 * @nfnlh: nfnetlink handler
Packit Service f5259b
 *
Packit Service f5259b
 * This function closes the nfnetlink handler. On success, 0 is returned.
Packit Service f5259b
 * On error, -1 is returned and errno is set appropiately.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_close(struct nfnl_handle *nfnlh)
Packit Service f5259b
{
Packit Service f5259b
	int i, ret;
Packit Service f5259b
Packit Service f5259b
	assert(nfnlh);
Packit Service f5259b
Packit Service f5259b
	for (i = 0; i < NFNL_MAX_SUBSYS; i++)
Packit Service f5259b
		nfnl_subsys_close(&nfnlh->subsys[i]);
Packit Service f5259b
Packit Service f5259b
	ret = close(nfnlh->fd);
Packit Service f5259b
	if (ret < 0)
Packit Service f5259b
		return ret;
Packit Service f5259b
Packit Service f5259b
	free(nfnlh);
Packit Service f5259b
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_join - join a nfnetlink multicast group
Packit Service f5259b
 * @nfnlh: nfnetlink handler
Packit Service f5259b
 * @group: group we want to join
Packit Service f5259b
 *
Packit Service f5259b
 * This function is used to join a certain multicast group. It must be
Packit Service f5259b
 * called once the nfnetlink handler has been created. If any doubt, 
Packit Service f5259b
 * just use it if you have to listen to nfnetlink events.
Packit Service f5259b
 *
Packit Service f5259b
 * On success, 0 is returned. On error, -1 is returned and errno is set
Packit Service f5259b
 * approapiately.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_join(const struct nfnl_handle *nfnlh, unsigned int group)
Packit Service f5259b
{
Packit Service f5259b
	assert(nfnlh);
Packit Service f5259b
	return setsockopt(nfnlh->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
Packit Service f5259b
			  &group, sizeof(group));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_send - send a nfnetlink message through netlink socket
Packit Service f5259b
 * @nfnlh: nfnetlink handler
Packit Service f5259b
 * @n: netlink message
Packit Service f5259b
 *
Packit Service f5259b
 * On success, the number of bytes is returned. On error, -1 is returned 
Packit Service f5259b
 * and errno is set appropiately.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_send(struct nfnl_handle *nfnlh, struct nlmsghdr *n)
Packit Service f5259b
{
Packit Service f5259b
	assert(nfnlh);
Packit Service f5259b
	assert(n);
Packit Service f5259b
Packit Service f5259b
	nfnl_debug_dump_packet(n, n->nlmsg_len+sizeof(*n), "nfnl_send");
Packit Service f5259b
Packit Service f5259b
	return sendto(nfnlh->fd, n, n->nlmsg_len, 0, 
Packit Service f5259b
		      (struct sockaddr *)&nfnlh->peer, sizeof(nfnlh->peer));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
int nfnl_sendmsg(const struct nfnl_handle *nfnlh, const struct msghdr *msg,
Packit Service f5259b
		 unsigned int flags)
Packit Service f5259b
{
Packit Service f5259b
	assert(nfnlh);
Packit Service f5259b
	assert(msg);
Packit Service f5259b
Packit Service f5259b
	return sendmsg(nfnlh->fd, msg, flags);
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
int nfnl_sendiov(const struct nfnl_handle *nfnlh, const struct iovec *iov,
Packit Service f5259b
		 unsigned int num, unsigned int flags)
Packit Service f5259b
{
Packit Service f5259b
	struct msghdr msg;
Packit Service f5259b
Packit Service f5259b
	assert(nfnlh);
Packit Service f5259b
Packit Service f5259b
	msg.msg_name = (struct sockaddr *) &nfnlh->peer;
Packit Service f5259b
	msg.msg_namelen = sizeof(nfnlh->peer);
Packit Service f5259b
	msg.msg_iov = (struct iovec *) iov;
Packit Service f5259b
	msg.msg_iovlen = num;
Packit Service f5259b
	msg.msg_control = NULL;
Packit Service f5259b
	msg.msg_controllen = 0;
Packit Service f5259b
	msg.msg_flags = 0;
Packit Service f5259b
Packit Service f5259b
	return nfnl_sendmsg(nfnlh, &msg, flags);
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_fill_hdr - fill in netlink and nfnetlink header
Packit Service f5259b
 * @nfnlh: nfnetlink handle
Packit Service f5259b
 * @nlh: netlink message to be filled in
Packit Service f5259b
 * @len: length of _payload_ bytes (not including nfgenmsg)
Packit Service f5259b
 * @family: AF_INET / ...
Packit Service f5259b
 * @res_id: resource id
Packit Service f5259b
 * @msg_type: nfnetlink message type (without subsystem)
Packit Service f5259b
 * @msg_flags: netlink message flags
Packit Service f5259b
 *
Packit Service f5259b
 * This function sets up appropiately the nfnetlink header. See that the
Packit Service f5259b
 * pointer to the netlink message passed must point to a memory region of
Packit Service f5259b
 * at least the size of struct nlmsghdr + struct nfgenmsg.
Packit Service f5259b
 */
Packit Service f5259b
void nfnl_fill_hdr(struct nfnl_subsys_handle *ssh,
Packit Service f5259b
		    struct nlmsghdr *nlh, unsigned int len, 
Packit Service f5259b
		    u_int8_t family,
Packit Service f5259b
		    u_int16_t res_id,
Packit Service f5259b
		    u_int16_t msg_type,
Packit Service f5259b
		    u_int16_t msg_flags)
Packit Service f5259b
{
Packit Service f5259b
	assert(ssh);
Packit Service f5259b
	assert(nlh);
Packit Service f5259b
Packit Service f5259b
	struct nfgenmsg *nfg = (void *)nlh + sizeof(*nlh);
Packit Service f5259b
Packit Service f5259b
	nlh->nlmsg_len = NLMSG_LENGTH(len+sizeof(*nfg));
Packit Service f5259b
	nlh->nlmsg_type = (ssh->subsys_id<<8)|msg_type;
Packit Service f5259b
	nlh->nlmsg_flags = msg_flags;
Packit Service f5259b
	nlh->nlmsg_pid = 0;
Packit Service f5259b
Packit Service f5259b
	if (ssh->nfnlh->flags & NFNL_F_SEQTRACK_ENABLED) {
Packit Service f5259b
		nlh->nlmsg_seq = ++ssh->nfnlh->seq;
Packit Service f5259b
		/* kernel uses sequence number zero for events */
Packit Service f5259b
		if (!ssh->nfnlh->seq)
Packit Service f5259b
			nlh->nlmsg_seq = ssh->nfnlh->seq = time(NULL);
Packit Service f5259b
	} else {
Packit Service f5259b
		/* unset sequence number, ignore it */
Packit Service f5259b
		nlh->nlmsg_seq = 0;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	nfg->nfgen_family = family;
Packit Service f5259b
	nfg->version = NFNETLINK_V0;
Packit Service f5259b
	nfg->res_id = htons(res_id);
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
struct nfattr *
Packit Service f5259b
nfnl_parse_hdr(const struct nfnl_handle *nfnlh,
Packit Service f5259b
		const struct nlmsghdr *nlh,
Packit Service f5259b
		struct nfgenmsg **genmsg)
Packit Service f5259b
{
Packit Service f5259b
	if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg)))
Packit Service f5259b
		return NULL;
Packit Service f5259b
Packit Service f5259b
	if (nlh->nlmsg_len == NLMSG_LENGTH(sizeof(struct nfgenmsg))) {
Packit Service f5259b
		if (genmsg)
Packit Service f5259b
			*genmsg = (void *)nlh + sizeof(*nlh);
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	if (genmsg)
Packit Service f5259b
		*genmsg = (void *)nlh + sizeof(*nlh);
Packit Service f5259b
Packit Service f5259b
	return (void *)nlh + NLMSG_LENGTH(sizeof(struct nfgenmsg));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_recv - receive data from a nfnetlink subsystem
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 * @buf: buffer where the data will be stored
Packit Service f5259b
 * @len: size of the buffer
Packit Service f5259b
 *
Packit Service f5259b
 * This function doesn't perform any sanity checking. So do no expect
Packit Service f5259b
 * that the data is well-formed. Such checkings are done by the parsing
Packit Service f5259b
 * functions.
Packit Service f5259b
 *
Packit Service f5259b
 * On success, 0 is returned. On error, -1 is returned and errno is set
Packit Service f5259b
 * appropiately.
Packit Service f5259b
 *
Packit Service f5259b
 * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
Packit Service f5259b
 * that case is possible that the information requested is incomplete.
Packit Service f5259b
 */
Packit Service f5259b
ssize_t 
Packit Service f5259b
nfnl_recv(const struct nfnl_handle *h, unsigned char *buf, size_t len)
Packit Service f5259b
{
Packit Service f5259b
	socklen_t addrlen;
Packit Service f5259b
	int status;
Packit Service f5259b
	struct sockaddr_nl peer;
Packit Service f5259b
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(buf);
Packit Service f5259b
	assert(len > 0);
Packit Service f5259b
	
Packit Service f5259b
	if (len < sizeof(struct nlmsgerr)
Packit Service f5259b
	    || len < sizeof(struct nlmsghdr)) {
Packit Service f5259b
	    	errno = EBADMSG;
Packit Service f5259b
		return -1; 
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	addrlen = sizeof(h->peer);
Packit Service f5259b
	status = recvfrom(h->fd, buf, len, 0, (struct sockaddr *)&peer,	
Packit Service f5259b
			&addrlen);
Packit Service f5259b
	if (status <= 0)
Packit Service f5259b
		return status;
Packit Service f5259b
Packit Service f5259b
	if (addrlen != sizeof(peer)) {
Packit Service f5259b
		errno = EINVAL;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	if (peer.nl_pid != 0) {
Packit Service f5259b
		errno = ENOMSG;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	return status;
Packit Service f5259b
}
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_listen: listen for one or more netlink messages
Packit Service f5259b
 * @nfnhl: libnfnetlink handle
Packit Service f5259b
 * @handler: callback function to be called for every netlink message
Packit Service f5259b
 *          - the callback handler should normally return 0
Packit Service f5259b
 *          - but may return a negative error code which will cause
Packit Service f5259b
 *            nfnl_listen to return immediately with the same error code
Packit Service f5259b
 *          - or return a postivie error code which will cause 
Packit Service f5259b
 *            nfnl_listen to return after it has finished processing all
Packit Service f5259b
 *            the netlink messages in the current packet
Packit Service f5259b
 *          Thus a positive error code will terminate nfnl_listen "soon"
Packit Service f5259b
 *          without any loss of data, a negative error code will terminate
Packit Service f5259b
 *          nfnl_listen "very soon" and throw away data already read from
Packit Service f5259b
 *          the netlink socket.
Packit Service f5259b
 * @jarg: opaque argument passed on to callback
Packit Service f5259b
 *
Packit Service f5259b
 * This function is used to receive and process messages coming from an open
Packit Service f5259b
 * nfnetlink handler like events or information request via nfnl_send().
Packit Service f5259b
 *
Packit Service f5259b
 * On error, -1 is returned, unfortunately errno is not always set
Packit Service f5259b
 * appropiately. For that reason, the use of this function is DEPRECATED. 
Packit Service f5259b
 * Please, use nfnl_receive_process() instead.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_listen(struct nfnl_handle *nfnlh,
Packit Service f5259b
		int (*handler)(struct sockaddr_nl *, struct nlmsghdr *n,
Packit Service f5259b
			       void *), void *jarg)
Packit Service f5259b
{
Packit Service f5259b
	struct sockaddr_nl nladdr;
Packit Service f5259b
	char buf[NFNL_BUFFSIZE] __attribute__ ((aligned));
Packit Service f5259b
	struct iovec iov;
Packit Service f5259b
	int remain;
Packit Service f5259b
	struct nlmsghdr *h;
Packit Service f5259b
	struct nlmsgerr *msgerr;
Packit Service f5259b
	int quit=0;
Packit Service f5259b
Packit Service f5259b
	struct msghdr msg = {
Packit Service f5259b
		.msg_name    = &nladdr,
Packit Service f5259b
		.msg_namelen = sizeof(nladdr),
Packit Service f5259b
		.msg_iov     = &iov,
Packit Service f5259b
		.msg_iovlen  = 1,
Packit Service f5259b
	};
Packit Service f5259b
Packit Service f5259b
	memset(&nladdr, 0, sizeof(nladdr));
Packit Service f5259b
	nladdr.nl_family = AF_NETLINK;
Packit Service f5259b
	iov.iov_base = buf;
Packit Service f5259b
	iov.iov_len = sizeof(buf);
Packit Service f5259b
Packit Service f5259b
	while (! quit) {
Packit Service f5259b
		remain = recvmsg(nfnlh->fd, &msg, 0);
Packit Service f5259b
		if (remain < 0) {
Packit Service f5259b
			if (errno == EINTR)
Packit Service f5259b
				continue;
Packit Service f5259b
			/* Bad file descriptor */
Packit Service f5259b
			else if (errno == EBADF)
Packit Service f5259b
				break;
Packit Service f5259b
			else if (errno == EAGAIN)
Packit Service f5259b
				break;
Packit Service f5259b
			nfnl_error("recvmsg overrun: %s", strerror(errno));
Packit Service f5259b
			continue;
Packit Service f5259b
		}
Packit Service f5259b
		if (remain == 0) {
Packit Service f5259b
			nfnl_error("EOF on netlink");
Packit Service f5259b
			return -1;
Packit Service f5259b
		}
Packit Service f5259b
		if (msg.msg_namelen != sizeof(nladdr)) {
Packit Service f5259b
			nfnl_error("Bad sender address len (%d)",
Packit Service f5259b
				   msg.msg_namelen);
Packit Service f5259b
			return -1;
Packit Service f5259b
		}
Packit Service f5259b
Packit Service f5259b
		for (h = (struct nlmsghdr *)buf; remain >= sizeof(*h);) {
Packit Service f5259b
			int err;
Packit Service f5259b
			int len = h->nlmsg_len;
Packit Service f5259b
			int l = len - sizeof(*h);
Packit Service f5259b
Packit Service f5259b
			if (l < 0 || len > remain) {
Packit Service f5259b
				if (msg.msg_flags & MSG_TRUNC) {
Packit Service f5259b
					nfnl_error("MSG_TRUNC");
Packit Service f5259b
					return -1;
Packit Service f5259b
				}
Packit Service f5259b
				nfnl_error("Malformed msg (len=%d)", len);
Packit Service f5259b
				return -1;
Packit Service f5259b
			}
Packit Service f5259b
Packit Service f5259b
			/* end of messages reached, let's return */
Packit Service f5259b
			if (h->nlmsg_type == NLMSG_DONE)
Packit Service f5259b
				return 0;
Packit Service f5259b
Packit Service f5259b
			/* Break the loop if success is explicitely
Packit Service f5259b
			 * reported via NLM_F_ACK flag set */
Packit Service f5259b
			if (h->nlmsg_type == NLMSG_ERROR) {
Packit Service f5259b
				msgerr = NLMSG_DATA(h);
Packit Service f5259b
				return msgerr->error;
Packit Service f5259b
			}
Packit Service f5259b
Packit Service f5259b
			err = handler(&nladdr, h, jarg);
Packit Service f5259b
			if (err < 0)
Packit Service f5259b
				return err;
Packit Service f5259b
			quit |= err;
Packit Service f5259b
		
Packit Service f5259b
			/* FIXME: why not _NEXT macros, etc.? */
Packit Service f5259b
			//h = NLMSG_NEXT(h, remain);
Packit Service f5259b
			remain -= NLMSG_ALIGN(len);
Packit Service f5259b
			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
Packit Service f5259b
		}
Packit Service f5259b
		if (msg.msg_flags & MSG_TRUNC) {
Packit Service f5259b
			nfnl_error("MSG_TRUNC");
Packit Service f5259b
			continue;
Packit Service f5259b
		}
Packit Service f5259b
		if (remain) {
Packit Service f5259b
			nfnl_error("remnant size %d", remain);
Packit Service f5259b
			return -1;
Packit Service f5259b
		}
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	return quit;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_talk - send a request and then receive and process messages returned
Packit Service f5259b
 * @nfnlh: nfnetelink handler
Packit Service f5259b
 * @n: netlink message that contains the request
Packit Service f5259b
 * @peer: peer PID
Packit Service f5259b
 * @groups: netlink groups
Packit Service f5259b
 * @junk: callback called if out-of-sequence messages were received
Packit Service f5259b
 * @jarg: data for the junk callback
Packit Service f5259b
 *
Packit Service f5259b
 * This function is used to request an action that does not returns any
Packit Service f5259b
 * information. On error, a negative value is returned, errno could be
Packit Service f5259b
 * set appropiately. For that reason, the use of this function is DEPRECATED.
Packit Service f5259b
 * Please, use nfnl_query() instead.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_talk(struct nfnl_handle *nfnlh, struct nlmsghdr *n, pid_t peer,
Packit Service f5259b
	      unsigned groups, struct nlmsghdr *answer,
Packit Service f5259b
	      int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
Packit Service f5259b
	      void *jarg)
Packit Service f5259b
{
Packit Service f5259b
	char buf[NFNL_BUFFSIZE] __attribute__ ((aligned));
Packit Service f5259b
	struct sockaddr_nl nladdr;
Packit Service f5259b
	struct nlmsghdr *h;
Packit Service f5259b
	unsigned int seq;
Packit Service f5259b
	int status;
Packit Service f5259b
	struct iovec iov = {
Packit Service f5259b
		n, n->nlmsg_len
Packit Service f5259b
	};
Packit Service f5259b
	struct msghdr msg = {
Packit Service f5259b
		.msg_name    = &nladdr,
Packit Service f5259b
		.msg_namelen = sizeof(nladdr),
Packit Service f5259b
		.msg_iov     = &iov,
Packit Service f5259b
		.msg_iovlen  = 1,
Packit Service f5259b
	};
Packit Service f5259b
Packit Service f5259b
	memset(&nladdr, 0, sizeof(nladdr));
Packit Service f5259b
	nladdr.nl_family = AF_NETLINK;
Packit Service f5259b
	nladdr.nl_pid = peer;
Packit Service f5259b
	nladdr.nl_groups = groups;
Packit Service f5259b
Packit Service f5259b
	n->nlmsg_seq = seq = ++nfnlh->seq;
Packit Service f5259b
	/* FIXME: why ? */
Packit Service f5259b
	if (!answer)
Packit Service f5259b
		n->nlmsg_flags |= NLM_F_ACK;
Packit Service f5259b
Packit Service f5259b
	status = sendmsg(nfnlh->fd, &msg, 0);
Packit Service f5259b
	if (status < 0) {
Packit Service f5259b
		nfnl_error("sendmsg(netlink) %s", strerror(errno));
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
	iov.iov_base = buf;
Packit Service f5259b
	iov.iov_len = sizeof(buf);
Packit Service f5259b
Packit Service f5259b
	while (1) {
Packit Service f5259b
		status = recvmsg(nfnlh->fd, &msg, 0);
Packit Service f5259b
		if (status < 0) {
Packit Service f5259b
			if (errno == EINTR)
Packit Service f5259b
				continue;
Packit Service f5259b
			nfnl_error("recvmsg over-run");
Packit Service f5259b
			continue;
Packit Service f5259b
		}
Packit Service f5259b
		if (status == 0) {
Packit Service f5259b
			nfnl_error("EOF on netlink");
Packit Service f5259b
			return -1;
Packit Service f5259b
		}
Packit Service f5259b
		if (msg.msg_namelen != sizeof(nladdr)) {
Packit Service f5259b
			nfnl_error("Bad sender address len %d",
Packit Service f5259b
				   msg.msg_namelen);
Packit Service f5259b
			return -1;
Packit Service f5259b
		}
Packit Service f5259b
Packit Service f5259b
		for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
Packit Service f5259b
			int len = h->nlmsg_len;
Packit Service f5259b
			int l = len - sizeof(*h);
Packit Service f5259b
			int err;
Packit Service f5259b
Packit Service f5259b
			if (l < 0 || len > status) {
Packit Service f5259b
				if (msg.msg_flags & MSG_TRUNC) {
Packit Service f5259b
					nfnl_error("Truncated message\n");
Packit Service f5259b
					return -1;
Packit Service f5259b
				}
Packit Service f5259b
				nfnl_error("Malformed message: len=%d\n", len);
Packit Service f5259b
				return -1; /* FIXME: libnetlink exits here */
Packit Service f5259b
			}
Packit Service f5259b
Packit Service f5259b
			if (h->nlmsg_pid != nfnlh->local.nl_pid ||
Packit Service f5259b
			    h->nlmsg_seq != seq) {
Packit Service f5259b
				if (junk) {
Packit Service f5259b
					err = junk(&nladdr, h, jarg);
Packit Service f5259b
					if (err < 0)
Packit Service f5259b
						return err;
Packit Service f5259b
				}
Packit Service f5259b
				goto cont;
Packit Service f5259b
			}
Packit Service f5259b
Packit Service f5259b
			if (h->nlmsg_type == NLMSG_ERROR) {
Packit Service f5259b
				struct nlmsgerr *err = NLMSG_DATA(h);
Packit Service f5259b
				if (l < sizeof(struct nlmsgerr))
Packit Service f5259b
					nfnl_error("ERROR truncated\n");
Packit Service f5259b
				else {
Packit Service f5259b
					errno = -err->error;
Packit Service f5259b
					if (errno == 0) {
Packit Service f5259b
						if (answer)
Packit Service f5259b
							memcpy(answer, h, h->nlmsg_len);
Packit Service f5259b
						return 0;
Packit Service f5259b
					}
Packit Service f5259b
					perror("NFNETLINK answers");
Packit Service f5259b
				}
Packit Service f5259b
				return err->error;
Packit Service f5259b
			}
Packit Service f5259b
			if (answer) {
Packit Service f5259b
				memcpy(answer, h, h->nlmsg_len);
Packit Service f5259b
				return 0;
Packit Service f5259b
			}
Packit Service f5259b
Packit Service f5259b
			nfnl_error("Unexpected reply!\n");
Packit Service f5259b
cont:
Packit Service f5259b
			status -= NLMSG_ALIGN(len);
Packit Service f5259b
			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
Packit Service f5259b
		}
Packit Service f5259b
		if (msg.msg_flags & MSG_TRUNC) {
Packit Service f5259b
			nfnl_error("Messages truncated\n");
Packit Service f5259b
			continue;
Packit Service f5259b
		}
Packit Service f5259b
		if (status)
Packit Service f5259b
			nfnl_error("Remnant of size %d\n", status);
Packit Service f5259b
	}
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_addattr_l - Add variable length attribute to nlmsghdr
Packit Service f5259b
 * @n: netlink message header to which attribute is to be added
Packit Service f5259b
 * @maxlen: maximum length of netlink message header
Packit Service f5259b
 * @type: type of new attribute
Packit Service f5259b
 * @data: content of new attribute
Packit Service f5259b
 * @len: attribute length
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
Packit Service f5259b
		   int alen)
Packit Service f5259b
{
Packit Service f5259b
	int len = NFA_LENGTH(alen);
Packit Service f5259b
	struct nfattr *nfa;
Packit Service f5259b
Packit Service f5259b
	assert(n);
Packit Service f5259b
	assert(maxlen > 0);
Packit Service f5259b
	assert(type >= 0);
Packit Service f5259b
Packit Service f5259b
	if ((NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) {
Packit Service f5259b
		errno = ENOSPC;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	nfa = NLMSG_TAIL(n);
Packit Service f5259b
	nfa->nfa_type = type;
Packit Service f5259b
	nfa->nfa_len = len;
Packit Service f5259b
	memcpy(NFA_DATA(nfa), data, alen);
Packit Service f5259b
	n->nlmsg_len = (NLMSG_ALIGN(n->nlmsg_len) + NFA_ALIGN(len));
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_nfa_addattr_l - Add variable length attribute to struct nfattr 
Packit Service f5259b
 *
Packit Service f5259b
 * @nfa: struct nfattr
Packit Service f5259b
 * @maxlen: maximal length of nfattr buffer
Packit Service f5259b
 * @type: type for new attribute
Packit Service f5259b
 * @data: content of new attribute
Packit Service f5259b
 * @alen: length of new attribute
Packit Service f5259b
 *
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_nfa_addattr_l(struct nfattr *nfa, int maxlen, int type, 
Packit Service f5259b
		       const void *data, int alen)
Packit Service f5259b
{
Packit Service f5259b
	struct nfattr *subnfa;
Packit Service f5259b
	int len = NFA_LENGTH(alen);
Packit Service f5259b
Packit Service f5259b
	assert(nfa);
Packit Service f5259b
	assert(maxlen > 0);
Packit Service f5259b
	assert(type >= 0);
Packit Service f5259b
Packit Service f5259b
	if (NFA_ALIGN(nfa->nfa_len) + len > maxlen) {
Packit Service f5259b
		errno = ENOSPC;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	subnfa = (struct nfattr *)(((char *)nfa) + NFA_ALIGN(nfa->nfa_len));
Packit Service f5259b
	subnfa->nfa_type = type;
Packit Service f5259b
	subnfa->nfa_len = len;
Packit Service f5259b
	memcpy(NFA_DATA(subnfa), data, alen);
Packit Service f5259b
	nfa->nfa_len = NFA_ALIGN(nfa->nfa_len) + len;
Packit Service f5259b
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_addattr8 - Add u_int8_t attribute to nlmsghdr
Packit Service f5259b
 *
Packit Service f5259b
 * @n: netlink message header to which attribute is to be added
Packit Service f5259b
 * @maxlen: maximum length of netlink message header
Packit Service f5259b
 * @type: type of new attribute
Packit Service f5259b
 * @data: content of new attribute
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_addattr8(struct nlmsghdr *n, int maxlen, int type, u_int8_t data)
Packit Service f5259b
{
Packit Service f5259b
	assert(n);
Packit Service f5259b
	assert(maxlen > 0);
Packit Service f5259b
	assert(type >= 0);
Packit Service f5259b
Packit Service f5259b
	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_nfa_addattr16 - Add u_int16_t attribute to struct nfattr 
Packit Service f5259b
 *
Packit Service f5259b
 * @nfa: struct nfattr
Packit Service f5259b
 * @maxlen: maximal length of nfattr buffer
Packit Service f5259b
 * @type: type for new attribute
Packit Service f5259b
 * @data: content of new attribute
Packit Service f5259b
 *
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_nfa_addattr16(struct nfattr *nfa, int maxlen, int type, 
Packit Service f5259b
		       u_int16_t data)
Packit Service f5259b
{
Packit Service f5259b
	assert(nfa);
Packit Service f5259b
	assert(maxlen > 0);
Packit Service f5259b
	assert(type >= 0);
Packit Service f5259b
Packit Service f5259b
	return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_addattr16 - Add u_int16_t attribute to nlmsghdr
Packit Service f5259b
 *
Packit Service f5259b
 * @n: netlink message header to which attribute is to be added
Packit Service f5259b
 * @maxlen: maximum length of netlink message header
Packit Service f5259b
 * @type: type of new attribute
Packit Service f5259b
 * @data: content of new attribute
Packit Service f5259b
 *
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_addattr16(struct nlmsghdr *n, int maxlen, int type,
Packit Service f5259b
		   u_int16_t data)
Packit Service f5259b
{
Packit Service f5259b
	assert(n);
Packit Service f5259b
	assert(maxlen > 0);
Packit Service f5259b
	assert(type >= 0);
Packit Service f5259b
Packit Service f5259b
	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_nfa_addattr32 - Add u_int32_t attribute to struct nfattr 
Packit Service f5259b
 *
Packit Service f5259b
 * @nfa: struct nfattr
Packit Service f5259b
 * @maxlen: maximal length of nfattr buffer
Packit Service f5259b
 * @type: type for new attribute
Packit Service f5259b
 * @data: content of new attribute
Packit Service f5259b
 *
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_nfa_addattr32(struct nfattr *nfa, int maxlen, int type, 
Packit Service f5259b
		       u_int32_t data)
Packit Service f5259b
{
Packit Service f5259b
	assert(nfa);
Packit Service f5259b
	assert(maxlen > 0);
Packit Service f5259b
	assert(type >= 0);
Packit Service f5259b
Packit Service f5259b
	return nfnl_nfa_addattr_l(nfa, maxlen, type, &data, sizeof(data));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_addattr32 - Add u_int32_t attribute to nlmsghdr
Packit Service f5259b
 *
Packit Service f5259b
 * @n: netlink message header to which attribute is to be added
Packit Service f5259b
 * @maxlen: maximum length of netlink message header
Packit Service f5259b
 * @type: type of new attribute
Packit Service f5259b
 * @data: content of new attribute
Packit Service f5259b
 *
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_addattr32(struct nlmsghdr *n, int maxlen, int type,
Packit Service f5259b
		   u_int32_t data)
Packit Service f5259b
{
Packit Service f5259b
	assert(n);
Packit Service f5259b
	assert(maxlen > 0);
Packit Service f5259b
	assert(type >= 0);
Packit Service f5259b
Packit Service f5259b
	return nfnl_addattr_l(n, maxlen, type, &data, sizeof(data));
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_parse_attr - Parse a list of nfattrs into a pointer array
Packit Service f5259b
 *
Packit Service f5259b
 * @tb: pointer array, will be filled in (output)
Packit Service f5259b
 * @max: size of pointer array
Packit Service f5259b
 * @nfa: pointer to list of nfattrs
Packit Service f5259b
 * @len: length of 'nfa'
Packit Service f5259b
 *
Packit Service f5259b
 * The returned value is equal to the number of remaining bytes of the netlink
Packit Service f5259b
 * message that cannot be parsed.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_parse_attr(struct nfattr *tb[], int max, struct nfattr *nfa, int len)
Packit Service f5259b
{
Packit Service f5259b
	assert(tb);
Packit Service f5259b
	assert(max > 0);
Packit Service f5259b
	assert(nfa);
Packit Service f5259b
Packit Service f5259b
	memset(tb, 0, sizeof(struct nfattr *) * max);
Packit Service f5259b
Packit Service f5259b
	while (NFA_OK(nfa, len)) {
Packit Service f5259b
		if (NFA_TYPE(nfa) <= max)
Packit Service f5259b
			tb[NFA_TYPE(nfa)-1] = nfa;
Packit Service f5259b
                nfa = NFA_NEXT(nfa,len);
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	return len;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_build_nfa_iovec - Build two iovec's from tag, length and value
Packit Service f5259b
 *
Packit Service f5259b
 * @iov: pointer to array of two 'struct iovec' (caller-allocated)
Packit Service f5259b
 * @nfa: pointer to 'struct nfattr' (caller-allocated)
Packit Service f5259b
 * @type: type (tag) of attribute
Packit Service f5259b
 * @len: length of value
Packit Service f5259b
 * @val: pointer to buffer containing 'value'
Packit Service f5259b
 *
Packit Service f5259b
 */ 
Packit Service f5259b
void nfnl_build_nfa_iovec(struct iovec *iov, struct nfattr *nfa, 
Packit Service f5259b
			  u_int16_t type, u_int32_t len, unsigned char *val)
Packit Service f5259b
{
Packit Service f5259b
	assert(iov);
Packit Service f5259b
	assert(nfa);
Packit Service f5259b
Packit Service f5259b
        /* Set the attribut values */ 
Packit Service f5259b
        nfa->nfa_len = sizeof(struct nfattr) + len;
Packit Service f5259b
        nfa->nfa_type = type;
Packit Service f5259b
Packit Service f5259b
	iov[0].iov_base = nfa;
Packit Service f5259b
	iov[0].iov_len = sizeof(*nfa);
Packit Service f5259b
	iov[1].iov_base = val;
Packit Service f5259b
	iov[1].iov_len = NFA_ALIGN(len);
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
#ifndef SO_RCVBUFFORCE
Packit Service f5259b
#define SO_RCVBUFFORCE	(33)
Packit Service f5259b
#endif
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_rcvbufsiz - set the socket buffer size
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 * @size: size of the buffer we want to set
Packit Service f5259b
 *
Packit Service f5259b
 * This function sets the new size of the socket buffer. Use this setting
Packit Service f5259b
 * to increase the socket buffer size if your system is reporting ENOBUFS
Packit Service f5259b
 * errors.
Packit Service f5259b
 *
Packit Service f5259b
 * This function returns the new size of the socket buffer.
Packit Service f5259b
 */
Packit Service f5259b
unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, unsigned int size)
Packit Service f5259b
{
Packit Service f5259b
	int status;
Packit Service f5259b
	socklen_t socklen = sizeof(size);
Packit Service f5259b
	unsigned int read_size = 0;
Packit Service f5259b
Packit Service f5259b
	assert(h);
Packit Service f5259b
Packit Service f5259b
	/* first we try the FORCE option, which is introduced in kernel
Packit Service f5259b
	 * 2.6.14 to give "root" the ability to override the system wide
Packit Service f5259b
	 * maximum */
Packit Service f5259b
	status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, socklen);
Packit Service f5259b
	if (status < 0) {
Packit Service f5259b
		/* if this didn't work, we try at least to get the system
Packit Service f5259b
		 * wide maximum (or whatever the user requested) */
Packit Service f5259b
		setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &size, socklen);
Packit Service f5259b
	}
Packit Service f5259b
	getsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &read_size, &socklen);
Packit Service f5259b
Packit Service f5259b
	return read_size;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_get_msg_first - get the first message of a multipart netlink message
Packit Service f5259b
 * @h: nfnetlink handle
Packit Service f5259b
 * @buf: data received that we want to process
Packit Service f5259b
 * @len: size of the data received
Packit Service f5259b
 *
Packit Service f5259b
 * This function returns a pointer to the first netlink message contained
Packit Service f5259b
 * in the chunk of data received from certain nfnetlink subsystem.
Packit Service f5259b
 *
Packit Service f5259b
 * On success, a valid address that points to the netlink message is returned.
Packit Service f5259b
 * On error, NULL is returned.
Packit Service f5259b
 */
Packit Service f5259b
struct nlmsghdr *nfnl_get_msg_first(struct nfnl_handle *h,
Packit Service f5259b
				    const unsigned char *buf,
Packit Service f5259b
				    size_t len)
Packit Service f5259b
{
Packit Service f5259b
	struct nlmsghdr *nlh;
Packit Service f5259b
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(buf);
Packit Service f5259b
	assert(len > 0);
Packit Service f5259b
Packit Service f5259b
	/* first message in buffer */
Packit Service f5259b
	nlh = (struct nlmsghdr *)buf;
Packit Service f5259b
	if (!NLMSG_OK(nlh, len))
Packit Service f5259b
		return NULL;
Packit Service f5259b
	h->last_nlhdr = nlh;
Packit Service f5259b
Packit Service f5259b
	return nlh;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
struct nlmsghdr *nfnl_get_msg_next(struct nfnl_handle *h,
Packit Service f5259b
				   const unsigned char *buf,
Packit Service f5259b
				   size_t len)
Packit Service f5259b
{
Packit Service f5259b
	struct nlmsghdr *nlh;
Packit Service f5259b
	size_t remain_len;
Packit Service f5259b
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(buf);
Packit Service f5259b
	assert(len > 0);
Packit Service f5259b
Packit Service f5259b
	/* if last header in handle not inside this buffer, 
Packit Service f5259b
	 * drop reference to last header */
Packit Service f5259b
	if (!h->last_nlhdr ||
Packit Service f5259b
	    (unsigned char *)h->last_nlhdr >= (buf + len)  ||
Packit Service f5259b
	    (unsigned char *)h->last_nlhdr < buf) {
Packit Service f5259b
		h->last_nlhdr = NULL;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	/* n-th part of multipart message */
Packit Service f5259b
	if (h->last_nlhdr->nlmsg_type == NLMSG_DONE ||
Packit Service f5259b
	    h->last_nlhdr->nlmsg_flags & NLM_F_MULTI) {
Packit Service f5259b
		/* if last part in multipart message or no
Packit Service f5259b
		 * multipart message at all, return */
Packit Service f5259b
		h->last_nlhdr = NULL;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	remain_len = (len - ((unsigned char *)h->last_nlhdr - buf));
Packit Service f5259b
	nlh = NLMSG_NEXT(h->last_nlhdr, remain_len);
Packit Service f5259b
Packit Service f5259b
	if (!NLMSG_OK(nlh, remain_len)) {
Packit Service f5259b
		h->last_nlhdr = NULL;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	h->last_nlhdr = nlh;
Packit Service f5259b
Packit Service f5259b
	return nlh;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_callback_register - register a callback for a certain message type
Packit Service f5259b
 * @ssh: nfnetlink subsys handler
Packit Service f5259b
 * @type: subsys call
Packit Service f5259b
 * @cb: nfnetlink callback to be registered
Packit Service f5259b
 *
Packit Service f5259b
 * On success, 0 is returned. On error, -1 is returned and errno is set
Packit Service f5259b
 * appropiately.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_callback_register(struct nfnl_subsys_handle *ssh,
Packit Service f5259b
			   u_int8_t type, struct nfnl_callback *cb)
Packit Service f5259b
{
Packit Service f5259b
	assert(ssh);
Packit Service f5259b
	assert(cb);
Packit Service f5259b
Packit Service f5259b
	if (type >= ssh->cb_count) {
Packit Service f5259b
		errno = EINVAL;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	memcpy(&ssh->cb[type], cb, sizeof(*cb));
Packit Service f5259b
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_callback_unregister - unregister a certain callback
Packit Service f5259b
 * @ssh: nfnetlink subsys handler
Packit Service f5259b
 * @type: subsys call
Packit Service f5259b
 *
Packit Service f5259b
 * On sucess, 0 is returned. On error, -1 is returned and errno is
Packit Service f5259b
 * set appropiately.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_callback_unregister(struct nfnl_subsys_handle *ssh, u_int8_t type)
Packit Service f5259b
{
Packit Service f5259b
	assert(ssh);
Packit Service f5259b
Packit Service f5259b
	if (type >= ssh->cb_count) {
Packit Service f5259b
		errno = EINVAL;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	ssh->cb[type].call = NULL;
Packit Service f5259b
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
int nfnl_check_attributes(const struct nfnl_handle *h,
Packit Service f5259b
			 const struct nlmsghdr *nlh,
Packit Service f5259b
			 struct nfattr *nfa[])
Packit Service f5259b
{
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(nlh);
Packit Service f5259b
	assert(nfa);
Packit Service f5259b
Packit Service f5259b
	int min_len;
Packit Service f5259b
	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
Packit Service f5259b
	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
Packit Service f5259b
	const struct nfnl_subsys_handle *ssh;
Packit Service f5259b
	struct nfnl_callback *cb;
Packit Service f5259b
Packit Service f5259b
	if (subsys_id > NFNL_MAX_SUBSYS)
Packit Service f5259b
		return -EINVAL;
Packit Service f5259b
Packit Service f5259b
	ssh = &h->subsys[subsys_id];
Packit Service f5259b
 	cb = &ssh->cb[type];
Packit Service f5259b
Packit Service f5259b
#if 1
Packit Service f5259b
	/* checks need to be enabled as soon as this is called from
Packit Service f5259b
	 * somebody else than __nfnl_handle_msg */
Packit Service f5259b
	if (type >= ssh->cb_count)
Packit Service f5259b
		return -EINVAL;
Packit Service f5259b
Packit Service f5259b
	min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
Packit Service f5259b
	if (nlh->nlmsg_len < min_len)
Packit Service f5259b
		return -EINVAL;
Packit Service f5259b
#endif
Packit Service f5259b
	memset(nfa, 0, sizeof(struct nfattr *) * cb->attr_count);
Packit Service f5259b
Packit Service f5259b
	if (nlh->nlmsg_len > min_len) {
Packit Service f5259b
		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
Packit Service f5259b
		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
Packit Service f5259b
Packit Service f5259b
		while (NFA_OK(attr, attrlen)) {
Packit Service f5259b
			unsigned int flavor = NFA_TYPE(attr);
Packit Service f5259b
			if (flavor) {
Packit Service f5259b
				if (flavor > cb->attr_count) {
Packit Service f5259b
					/* we have received an attribute from
Packit Service f5259b
					 * the kernel which we don't understand
Packit Service f5259b
					 * yet. We have to silently ignore this
Packit Service f5259b
					 * for the sake of future compatibility */
Packit Service f5259b
					attr = NFA_NEXT(attr, attrlen);
Packit Service f5259b
					continue;
Packit Service f5259b
				}
Packit Service f5259b
				nfa[flavor - 1] = attr;
Packit Service f5259b
			}
Packit Service f5259b
			attr = NFA_NEXT(attr, attrlen);
Packit Service f5259b
		}
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
static int __nfnl_handle_msg(struct nfnl_handle *h, struct nlmsghdr *nlh,
Packit Service f5259b
			     int len)
Packit Service f5259b
{
Packit Service f5259b
	struct nfnl_subsys_handle *ssh;
Packit Service f5259b
	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
Packit Service f5259b
	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
Packit Service f5259b
	int err = 0;
Packit Service f5259b
Packit Service f5259b
	if (subsys_id > NFNL_MAX_SUBSYS)
Packit Service f5259b
		return -1;
Packit Service f5259b
Packit Service f5259b
	ssh = &h->subsys[subsys_id];
Packit Service f5259b
Packit Service f5259b
	if (nlh->nlmsg_len < NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg))))
Packit Service f5259b
		return -1;
Packit Service f5259b
Packit Service f5259b
	if (type >= ssh->cb_count)
Packit Service f5259b
		return -1;
Packit Service f5259b
Packit Service f5259b
	if (ssh->cb[type].attr_count) {
Packit Service f5259b
		struct nfattr *nfa[ssh->cb[type].attr_count];
Packit Service f5259b
Packit Service f5259b
		err = nfnl_check_attributes(h, nlh, nfa);
Packit Service f5259b
		if (err < 0)
Packit Service f5259b
			return err;
Packit Service f5259b
		if (ssh->cb[type].call)
Packit Service f5259b
			return ssh->cb[type].call(nlh, nfa, ssh->cb[type].data);
Packit Service f5259b
	}
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
int nfnl_handle_packet(struct nfnl_handle *h, char *buf, int len)
Packit Service f5259b
{
Packit Service f5259b
Packit Service f5259b
	while (len >= NLMSG_SPACE(0)) {
Packit Service f5259b
		u_int32_t rlen;
Packit Service f5259b
		struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
Packit Service f5259b
Packit Service f5259b
		if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
Packit Service f5259b
		    || len < nlh->nlmsg_len)
Packit Service f5259b
			return -1;
Packit Service f5259b
Packit Service f5259b
		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
Packit Service f5259b
		if (rlen > len)
Packit Service f5259b
			rlen = len;
Packit Service f5259b
Packit Service f5259b
		if (__nfnl_handle_msg(h, nlh, rlen) < 0)
Packit Service f5259b
			return -1;
Packit Service f5259b
Packit Service f5259b
		len -= rlen;
Packit Service f5259b
		buf += rlen;
Packit Service f5259b
	}
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
static int nfnl_is_error(struct nfnl_handle *h, struct nlmsghdr *nlh)
Packit Service f5259b
{
Packit Service f5259b
	/* This message is an ACK or a DONE */
Packit Service f5259b
	if (nlh->nlmsg_type == NLMSG_ERROR ||
Packit Service f5259b
	    (nlh->nlmsg_type == NLMSG_DONE &&
Packit Service f5259b
	     nlh->nlmsg_flags & NLM_F_MULTI)) {
Packit Service f5259b
		if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) {
Packit Service f5259b
			errno = EBADMSG;
Packit Service f5259b
			return 1;
Packit Service f5259b
		}
Packit Service f5259b
		errno = -(*((int *)NLMSG_DATA(nlh)));
Packit Service f5259b
		return 1;
Packit Service f5259b
	}
Packit Service f5259b
	return 0;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/* On error, -1 is returned and errno is set appropiately. On success, 
Packit Service f5259b
 * 0 is returned if there is no more data to process, >0 if there is
Packit Service f5259b
 * more data to process */
Packit Service f5259b
static int nfnl_step(struct nfnl_handle *h, struct nlmsghdr *nlh)
Packit Service f5259b
{
Packit Service f5259b
	struct nfnl_subsys_handle *ssh;
Packit Service f5259b
	u_int8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
Packit Service f5259b
	u_int8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
Packit Service f5259b
Packit Service f5259b
	/* Is this an error message? */
Packit Service f5259b
	if (nfnl_is_error(h, nlh)) {
Packit Service f5259b
		/* This is an ACK */
Packit Service f5259b
		if (errno == 0)
Packit Service f5259b
			return 0;
Packit Service f5259b
		/* This an error message */
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
	
Packit Service f5259b
	/* nfnetlink sanity checks: check for nfgenmsg size */
Packit Service f5259b
	if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) {
Packit Service f5259b
		errno = ENOSPC;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	if (subsys_id > NFNL_MAX_SUBSYS) {
Packit Service f5259b
		errno = ENOENT;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	ssh = &h->subsys[subsys_id];
Packit Service f5259b
	if (!ssh) {
Packit Service f5259b
		errno = ENOENT;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	if (type >= ssh->cb_count) {
Packit Service f5259b
		errno = ENOENT;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	if (ssh->cb[type].attr_count) {
Packit Service f5259b
		int err;
Packit Service f5259b
		struct nfattr *tb[ssh->cb[type].attr_count];
Packit Service f5259b
		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
Packit Service f5259b
		int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
Packit Service f5259b
		int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
Packit Service f5259b
Packit Service f5259b
		err = nfnl_parse_attr(tb, ssh->cb[type].attr_count, attr, len);
Packit Service f5259b
		if (err == -1)
Packit Service f5259b
			return -1;
Packit Service f5259b
Packit Service f5259b
		if (ssh->cb[type].call) {
Packit Service f5259b
			/*
Packit Service f5259b
			 * On error, the callback returns NFNL_CB_FAILURE and
Packit Service f5259b
			 * errno must be explicitely set. On success, 
Packit Service f5259b
			 * NFNL_CB_STOP is returned and we're done, otherwise 
Packit Service f5259b
			 * NFNL_CB_CONTINUE means that we want to continue 
Packit Service f5259b
			 * data processing.
Packit Service f5259b
			 */
Packit Service f5259b
			return ssh->cb[type].call(nlh,
Packit Service f5259b
						  tb,
Packit Service f5259b
						  ssh->cb[type].data);
Packit Service f5259b
		}
Packit Service f5259b
	}
Packit Service f5259b
	/* no callback set, continue data processing */
Packit Service f5259b
	return 1;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_process - process data coming from a nfnetlink system
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 * @buf: buffer that contains the netlink message
Packit Service f5259b
 * @len: size of the data contained in the buffer (not the buffer size)
Packit Service f5259b
 *
Packit Service f5259b
 * This function processes all the nfnetlink messages contained inside a
Packit Service f5259b
 * buffer. It performs the appropiate sanity checks and passes the message
Packit Service f5259b
 * to a certain handler that is registered via register_callback().
Packit Service f5259b
 *
Packit Service f5259b
 * On success, NFNL_CB_STOP is returned if the data processing has finished.
Packit Service f5259b
 * If a value NFNL_CB_CONTINUE is returned, then there is more data to
Packit Service f5259b
 * process. On error, NFNL_CB_CONTINUE is returned and errno is set to the 
Packit Service f5259b
 * appropiate value.
Packit Service f5259b
 *
Packit Service f5259b
 * In case that the callback returns NFNL_CB_FAILURE, errno may be set by
Packit Service f5259b
 * the library client. If your callback decides not to process data anymore
Packit Service f5259b
 * for any reason, then it must return NFNL_CB_STOP. Otherwise, if the 
Packit Service f5259b
 * callback continues the processing NFNL_CB_CONTINUE is returned.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_process(struct nfnl_handle *h, const unsigned char *buf, size_t len)
Packit Service f5259b
{
Packit Service f5259b
	int ret = 0;
Packit Service f5259b
	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
Packit Service f5259b
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(buf);
Packit Service f5259b
	assert(len > 0);
Packit Service f5259b
Packit Service f5259b
	/* check for out of sequence message */
Packit Service f5259b
	if (nlh->nlmsg_seq && nlh->nlmsg_seq != h->seq) {
Packit Service f5259b
		errno = EILSEQ;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
	while (len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) {
Packit Service f5259b
Packit Service f5259b
		ret = nfnl_step(h, nlh);
Packit Service f5259b
		if (ret <= NFNL_CB_STOP)
Packit Service f5259b
			break;
Packit Service f5259b
Packit Service f5259b
		nlh = NLMSG_NEXT(nlh, len);
Packit Service f5259b
	}
Packit Service f5259b
	return ret;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/*
Packit Service f5259b
 * New parsing functions based on iterators
Packit Service f5259b
 */
Packit Service f5259b
Packit Service f5259b
struct nfnl_iterator {
Packit Service f5259b
	struct nlmsghdr *nlh;
Packit Service f5259b
	unsigned int	len;
Packit Service f5259b
};
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_iterator_create: create an nfnetlink iterator
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 * @buf: buffer that contains data received from a nfnetlink system
Packit Service f5259b
 * @len: size of the data contained in the buffer (not the buffer size)
Packit Service f5259b
 *
Packit Service f5259b
 * This function creates an iterator that can be used to parse nfnetlink
Packit Service f5259b
 * message one by one. The iterator gives more control to the programmer
Packit Service f5259b
 * in the messages processing.
Packit Service f5259b
 *
Packit Service f5259b
 * On success, a valid address is returned. On error, NULL is returned
Packit Service f5259b
 * and errno is set to the appropiate value.
Packit Service f5259b
 */
Packit Service f5259b
struct nfnl_iterator *
Packit Service f5259b
nfnl_iterator_create(const struct nfnl_handle *h,
Packit Service f5259b
		     const char *buf,
Packit Service f5259b
		     size_t len)
Packit Service f5259b
{
Packit Service f5259b
	struct nlmsghdr *nlh;
Packit Service f5259b
	struct nfnl_iterator *it;
Packit Service f5259b
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(buf);
Packit Service f5259b
	assert(len > 0);
Packit Service f5259b
Packit Service f5259b
	it = malloc(sizeof(struct nfnl_iterator));
Packit Service f5259b
	if (!it) {
Packit Service f5259b
		errno = ENOMEM;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	/* first message in buffer */
Packit Service f5259b
	nlh = (struct nlmsghdr *)buf;
Packit Service f5259b
	if (len < NLMSG_SPACE(0) || !NLMSG_OK(nlh, len)) {
Packit Service f5259b
		free(it);
Packit Service f5259b
		errno = EBADMSG;
Packit Service f5259b
		return NULL;
Packit Service f5259b
	}
Packit Service f5259b
	it->nlh = nlh;
Packit Service f5259b
	it->len = len;
Packit Service f5259b
Packit Service f5259b
	return it;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_iterator_destroy - destroy a nfnetlink iterator
Packit Service f5259b
 * @it: nfnetlink iterator
Packit Service f5259b
 *
Packit Service f5259b
 * This function destroys a certain iterator. Nothing is returned.
Packit Service f5259b
 */
Packit Service f5259b
void nfnl_iterator_destroy(struct nfnl_iterator *it)
Packit Service f5259b
{
Packit Service f5259b
	assert(it);
Packit Service f5259b
	free(it);
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_iterator_process - process a nfnetlink message
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 * @it: nfnetlink iterator that contains the current message to be proccesed
Packit Service f5259b
 *
Packit Service f5259b
 * This function process just the current message selected by the iterator.
Packit Service f5259b
 * On success, a value greater or equal to zero is returned. On error,
Packit Service f5259b
 * -1 is returned and errno is appropiately set.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_iterator_process(struct nfnl_handle *h, struct nfnl_iterator *it)
Packit Service f5259b
{
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(it->nlh);
Packit Service f5259b
Packit Service f5259b
        /* check for out of sequence message */
Packit Service f5259b
	if (it->nlh->nlmsg_seq && it->nlh->nlmsg_seq != h->seq) {
Packit Service f5259b
		errno = EILSEQ;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}	
Packit Service f5259b
	if (it->len < NLMSG_SPACE(0) || !NLMSG_OK(it->nlh, it->len)) {
Packit Service f5259b
		errno = EBADMSG;
Packit Service f5259b
		return -1;
Packit Service f5259b
	}
Packit Service f5259b
	return nfnl_step(h, it->nlh);
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_iterator_next - get the next message hold by the iterator
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 * @it: nfnetlink iterator that contains the current message processed
Packit Service f5259b
 *
Packit Service f5259b
 * This function update the current message to be processed pointer.
Packit Service f5259b
 * It returns NFNL_CB_CONTINUE if there is still more messages to be 
Packit Service f5259b
 * processed, otherwise NFNL_CB_STOP is returned.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_iterator_next(const struct nfnl_handle *h, struct nfnl_iterator *it)
Packit Service f5259b
{
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(it);
Packit Service f5259b
Packit Service f5259b
	it->nlh = NLMSG_NEXT(it->nlh, it->len);
Packit Service f5259b
	if (!it->nlh)
Packit Service f5259b
		return 0;
Packit Service f5259b
	return 1;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_catch - get responses from the nfnetlink system and process them
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
*
Packit Service f5259b
 * This function handles the data received from the nfnetlink system.
Packit Service f5259b
 * For example, events generated by one of the subsystems. The message
Packit Service f5259b
 * is passed to the callback registered via callback_register(). Note that
Packit Service f5259b
 * this a replacement of nfnl_listen and its use is recommended.
Packit Service f5259b
 * 
Packit Service f5259b
 * On success, 0 is returned. On error, a -1 is returned. If you do not
Packit Service f5259b
 * want to listen to events anymore, then your callback must return 
Packit Service f5259b
 * NFNL_CB_STOP.
Packit Service f5259b
 *
Packit Service f5259b
 * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
Packit Service f5259b
 * that case is possible that the information requested is incomplete.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_catch(struct nfnl_handle *h)
Packit Service f5259b
{
Packit Service f5259b
	int ret;
Packit Service f5259b
Packit Service f5259b
	assert(h);
Packit Service f5259b
Packit Service f5259b
	while (1) {
Packit Service f5259b
		unsigned char buf[h->rcv_buffer_size]
Packit Service f5259b
			__attribute__ ((aligned));
Packit Service f5259b
Packit Service f5259b
		ret = nfnl_recv(h, buf, sizeof(buf));
Packit Service f5259b
		if (ret == -1) {
Packit Service f5259b
			/* interrupted syscall must retry */
Packit Service f5259b
			if (errno == EINTR)
Packit Service f5259b
				continue;
Packit Service f5259b
			break;
Packit Service f5259b
		}
Packit Service f5259b
Packit Service f5259b
		ret = nfnl_process(h, buf, ret);
Packit Service f5259b
		if (ret <= NFNL_CB_STOP)
Packit Service f5259b
			break; 
Packit Service f5259b
	}
Packit Service f5259b
Packit Service f5259b
	return ret;
Packit Service f5259b
}
Packit Service f5259b
Packit Service f5259b
/**
Packit Service f5259b
 * nfnl_query - request/response communication challenge
Packit Service f5259b
 * @h: nfnetlink handler
Packit Service f5259b
 * @nlh: nfnetlink message to be sent
Packit Service f5259b
 *
Packit Service f5259b
 * This function sends a nfnetlink message to a certain subsystem and
Packit Service f5259b
 * receives the response messages associated, such messages are passed to
Packit Service f5259b
 * the callback registered via register_callback(). Note that this function
Packit Service f5259b
 * is a replacement for nfnl_talk, its use is recommended.
Packit Service f5259b
 *
Packit Service f5259b
 * On success, 0 is returned. On error, a negative is returned. If your
Packit Service f5259b
 * does not want to listen to events anymore, then your callback must 
Packit Service f5259b
 * return NFNL_CB_STOP.
Packit Service f5259b
 *
Packit Service f5259b
 * Note that ENOBUFS is returned in case that nfnetlink is exhausted. In
Packit Service f5259b
 * that case is possible that the information requested is incomplete.
Packit Service f5259b
 */
Packit Service f5259b
int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh)
Packit Service f5259b
{
Packit Service f5259b
	assert(h);
Packit Service f5259b
	assert(nlh);
Packit Service f5259b
Packit Service f5259b
	if (nfnl_send(h, nlh) == -1)
Packit Service f5259b
		return -1;
Packit Service f5259b
Packit Service f5259b
	return nfnl_catch(h);
Packit Service f5259b
}