[netfilter-cvslog] r6782 - in tags/libnfnetlink: . libnfnetlink-0.0.30 libnfnetlink-0.0.30/include/libnfnetlink libnfnetlink-0.0.30/src

pablo at netfilter.org pablo at netfilter.org
Thu Mar 22 01:57:58 CET 2007


Author: pablo at netfilter.org
Date: 2007-03-22 01:57:58 +0100 (Thu, 22 Mar 2007)
New Revision: 6782

Added:
   tags/libnfnetlink/libnfnetlink-0.0.30/
   tags/libnfnetlink/libnfnetlink-0.0.30/configure.in
   tags/libnfnetlink/libnfnetlink-0.0.30/include/libnfnetlink/libnfnetlink.h
   tags/libnfnetlink/libnfnetlink-0.0.30/src/Makefile.am
   tags/libnfnetlink/libnfnetlink-0.0.30/src/libnfnetlink.c
Removed:
   tags/libnfnetlink/libnfnetlink-0.0.30/configure.in
   tags/libnfnetlink/libnfnetlink-0.0.30/include/libnfnetlink/libnfnetlink.h
   tags/libnfnetlink/libnfnetlink-0.0.30/src/Makefile.am
   tags/libnfnetlink/libnfnetlink-0.0.30/src/libnfnetlink.c
Log:
libnfnetlink 0.0.30



Copied: tags/libnfnetlink/libnfnetlink-0.0.30 (from rev 6750, trunk/libnfnetlink)

Deleted: tags/libnfnetlink/libnfnetlink-0.0.30/configure.in
===================================================================
--- trunk/libnfnetlink/configure.in	2007-02-12 01:43:31 UTC (rev 6750)
+++ tags/libnfnetlink/libnfnetlink-0.0.30/configure.in	2007-03-22 00:57:58 UTC (rev 6782)
@@ -1,25 +0,0 @@
-dnl Process this file with autoconf to create configure.
-
-AC_INIT
-
-AC_CANONICAL_SYSTEM
-
-AM_INIT_AUTOMAKE(libnfnetlink, 0.0.25)
-
-AC_PROG_CC
-AC_EXEEXT
-AM_PROG_LIBTOOL
-AC_SUBST(LIBTOOL_DEPS)
-
-case $target in 
-*-*-linux*) ;;
-*) AC_MSG_ERROR([Linux only, dude!]);;
-esac
-
-
-dnl--------------------------------
-dnl--------------------------------
-
-
-dnl Output the makefile
-AC_OUTPUT(Makefile src/Makefile include/Makefile include/libnfnetlink/Makefile utils/Makefile libnfnetlink.pc)

Copied: tags/libnfnetlink/libnfnetlink-0.0.30/configure.in (from rev 6780, trunk/libnfnetlink/configure.in)
===================================================================
--- tags/libnfnetlink/libnfnetlink-0.0.30/configure.in	                        (rev 0)
+++ tags/libnfnetlink/libnfnetlink-0.0.30/configure.in	2007-03-22 00:57:58 UTC (rev 6782)
@@ -0,0 +1,25 @@
+dnl Process this file with autoconf to create configure.
+
+AC_INIT
+
+AC_CANONICAL_SYSTEM
+
+AM_INIT_AUTOMAKE(libnfnetlink, 0.0.30)
+
+AC_PROG_CC
+AC_EXEEXT
+AM_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+
+case $target in 
+*-*-linux*) ;;
+*) AC_MSG_ERROR([Linux only, dude!]);;
+esac
+
+
+dnl--------------------------------
+dnl--------------------------------
+
+
+dnl Output the makefile
+AC_OUTPUT(Makefile src/Makefile include/Makefile include/libnfnetlink/Makefile utils/Makefile libnfnetlink.pc)

Deleted: tags/libnfnetlink/libnfnetlink-0.0.30/include/libnfnetlink/libnfnetlink.h
===================================================================
--- trunk/libnfnetlink/include/libnfnetlink/libnfnetlink.h	2007-02-12 01:43:31 UTC (rev 6750)
+++ tags/libnfnetlink/libnfnetlink-0.0.30/include/libnfnetlink/libnfnetlink.h	2007-03-22 00:57:58 UTC (rev 6782)
@@ -1,221 +0,0 @@
-/* libnfnetlink.h: Header file for generic netfilter netlink interface
- *
- * (C) 2002 Harald Welte <laforge at gnumonks.org>
- *
- * 2005-10-29 Pablo Neira Ayuso <pablo at netfilter.org>:
- * 	Fix NFNL_HEADER_LEN
- * 2005-11-13 Pablo Neira Ayuso <pablo at netfilter.org>:
- * 	Define NETLINK_NETFILTER if it's undefined
- */
-
-#ifndef __LIBNFNETLINK_H
-#define __LIBNFNETLINK_H
-
-#ifndef aligned_u64
-#define aligned_u64 unsigned long long __attribute__((aligned(8)))
-#endif
-
-#include <sys/socket.h>	/* for sa_family_t */
-#include <linux/netlink.h>
-#include <libnfnetlink/linux_nfnetlink.h>
-
-#ifndef NETLINK_NETFILTER
-#define NETLINK_NETFILTER 12
-#endif
-
-#define NLMSG_TAIL(nlh) \
-	(((void *) (nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))
-
-#define NFNL_HEADER_LEN	(NLMSG_ALIGN(sizeof(struct nlmsghdr))	\
-			 +NLMSG_ALIGN(sizeof(struct nfgenmsg)))
-
-#define NFNL_BUFFSIZE		8192
-
-struct nfnlhdr {
-	struct nlmsghdr nlh;
-	struct nfgenmsg nfmsg;
-};
-
-struct nfnl_callback {
-	int (*call)(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data);
-	void *data;
-	u_int16_t attr_count;
-};
-
-struct nfnl_handle;
-struct nfnl_subsys_handle;
-
-extern int nfnl_fd(struct nfnl_handle *h);
-
-/* get a new library handle */
-extern struct nfnl_handle *nfnl_open(void);
-extern int nfnl_close(struct nfnl_handle *);
-
-extern struct nfnl_subsys_handle *nfnl_subsys_open(struct nfnl_handle *, 
-						   u_int8_t, u_int8_t, 
-						   unsigned int);
-extern void nfnl_subsys_close(struct nfnl_subsys_handle *);
-
-/* sending of data */
-extern int nfnl_send(struct nfnl_handle *, struct nlmsghdr *);
-extern int nfnl_sendmsg(const struct nfnl_handle *, const struct msghdr *msg,
-			unsigned int flags);
-extern int nfnl_sendiov(const struct nfnl_handle *nfnlh,
-			const struct iovec *iov, unsigned int num,
-			unsigned int flags);
-extern void nfnl_fill_hdr(struct nfnl_subsys_handle *, struct nlmsghdr *,
-			  unsigned int, u_int8_t, u_int16_t, u_int16_t,
-			  u_int16_t);
-extern int nfnl_talk(struct nfnl_handle *, struct nlmsghdr *, pid_t,
-                     unsigned, struct nlmsghdr *,
-                     int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *),
-                     void *);
-
-/* simple challenge/response */
-extern int nfnl_listen(struct nfnl_handle *,
-                      int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *),
-                      void *);
-
-/* receiving */
-extern ssize_t nfnl_recv(const struct nfnl_handle *h, unsigned char *buf, size_t len);
-extern int nfnl_callback_register(struct nfnl_subsys_handle *,
-				  u_int8_t type, struct nfnl_callback *cb);
-extern int nfnl_callback_unregister(struct nfnl_subsys_handle *, u_int8_t type);
-extern int nfnl_handle_packet(struct nfnl_handle *, char *buf, int len);
-
-/* parsing */
-extern struct nfattr *nfnl_parse_hdr(const struct nfnl_handle *nfnlh, 
-				     const struct nlmsghdr *nlh,
-				     struct nfgenmsg **genmsg);
-extern int nfnl_check_attributes(const struct nfnl_handle *nfnlh,
-				 const struct nlmsghdr *nlh,
-				 struct nfattr *tb[]);
-extern struct nlmsghdr *nfnl_get_msg_first(struct nfnl_handle *h,
-					   const unsigned char *buf,
-					   size_t len);
-extern struct nlmsghdr *nfnl_get_msg_next(struct nfnl_handle *h,
-					  const unsigned char *buf,
-					  size_t len);
-
-/* callback verdict */
-enum {
-	NFNL_CB_FAILURE = -1,   /* failure */
-	NFNL_CB_STOP = 0,       /* stop the query */
-	NFNL_CB_CONTINUE = 1,   /* keep iterating */
-};
-
-/* join a certain netlink multicast group */
-extern int nfnl_join(const struct nfnl_handle *nfnlh, unsigned int group);
-
-/* process a netlink message */
-extern int nfnl_process(struct nfnl_handle *h,
-			const unsigned char *buf,
-			size_t len);
-
-/* iterator API */
-
-extern struct nfnl_iterator *
-nfnl_iterator_create(const struct nfnl_handle *h,
-		     const char *buf,
-		     size_t len);
-
-extern void nfnl_iterator_destroy(struct nfnl_iterator *it);
-
-extern int nfnl_iterator_process(struct nfnl_handle *h,
-				 struct nfnl_iterator *it);
-
-extern int nfnl_iterator_next(const struct nfnl_handle *h,
-			      struct nfnl_iterator *it);
-
-/* replacement for nfnl_listen */
-extern int nfnl_catch(struct nfnl_handle *h);
-
-/* replacement for nfnl_talk */
-extern int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh);
-
-#define nfnl_attr_present(tb, attr)			\
-	(tb[attr-1])
-
-#define nfnl_get_data(tb, attr, type)			\
-	({	type __ret = 0;				\
-	 if (tb[attr-1])				\
-	 __ret = *(type *)NFA_DATA(tb[attr-1]);		\
-	 __ret;						\
-	 })
-
-#define nfnl_get_pointer_to_data(tb, attr, type)	\
-	({	type *__ret = NULL;			\
-	 if (tb[attr-1])				\
-	 __ret = NFA_DATA(tb[attr-1]);			\
-	 __ret;						\
-	 })
-
-/* nfnl attribute handling functions */
-extern int nfnl_addattr_l(struct nlmsghdr *, int, int, const void *, int);
-extern int nfnl_addattr16(struct nlmsghdr *, int, int, u_int16_t);
-extern int nfnl_addattr32(struct nlmsghdr *, int, int, u_int32_t);
-extern int nfnl_nfa_addattr_l(struct nfattr *, int, int, const void *, int);
-extern int nfnl_nfa_addattr16(struct nfattr *, int, int, u_int16_t);
-extern int nfnl_nfa_addattr32(struct nfattr *, int, int, u_int32_t);
-extern int nfnl_parse_attr(struct nfattr **, int, struct nfattr *, int);
-#define nfnl_parse_nested(tb, max, nfa) \
-	nfnl_parse_attr((tb), (max), NFA_DATA((nfa)), NFA_PAYLOAD((nfa)))
-#define nfnl_nest(nlh, bufsize, type) 				\
-({	struct nfattr *__start = NLMSG_TAIL(nlh);		\
-	nfnl_addattr_l(nlh, bufsize, (NFNL_NFA_NEST | type), NULL, 0); 	\
-	__start; })
-#define nfnl_nest_end(nlh, tail) 				\
-({	(tail)->nfa_len = (void *) NLMSG_TAIL(nlh) - (void *) tail; })
-
-extern void nfnl_build_nfa_iovec(struct iovec *iov, struct nfattr *nfa, 
-				 u_int16_t type, u_int32_t len,
-				 unsigned char *val);
-extern unsigned int nfnl_rcvbufsiz(struct nfnl_handle *h, unsigned int size);
-
-
-extern void nfnl_dump_packet(struct nlmsghdr *, int, char *);
-
-/*
- * index to interface name API
- */
-
-#ifndef IFNAMSIZ
-#define IFNAMSIZ 16
-#endif
-
-struct nlif_handle;
-
-struct nlif_handle *nlif_open(void);
-void nlif_close(struct nlif_handle *orig);
-int nlif_fd(struct nlif_handle *nlif_handle);
-int nlif_query(struct nlif_handle *nlif_handle);
-int nlif_catch(struct nlif_handle *nlif_handle);
-int nlif_index2name(struct nlif_handle *nlif_handle, 
-		    unsigned int index, 
-		    char *name);
-
-/* Pablo: What is the equivalence of be64_to_cpu in userspace?
- * 
- * Harald: Good question.  I don't think there's a standard way [yet?], 
- * so I'd suggest manually implementing it by "#if little endian" bitshift
- * operations in C (at least for now).
- *
- * All the payload of any nfattr will always be in network byte order.
- * This would allow easy transport over a real network in the future 
- * (e.g. jamal's netlink2).
- *
- * Pablo: I've called it __be64_to_cpu instead of be64_to_cpu, since maybe 
- * there will one in the userspace headers someday. We don't want to
- * pollute POSIX space naming,
- */
-
-#include <byteswap.h>
-#if __BYTE_ORDER == __BIG_ENDIAN
-#  define __be64_to_cpu(x)	(x)
-# else
-# if __BYTE_ORDER == __LITTLE_ENDIAN
-#  define __be64_to_cpu(x)	__bswap_64(x)
-# endif
-#endif
-
-#endif /* __LIBNFNETLINK_H */

Copied: tags/libnfnetlink/libnfnetlink-0.0.30/include/libnfnetlink/libnfnetlink.h (from rev 6763, trunk/libnfnetlink/include/libnfnetlink/libnfnetlink.h)
===================================================================
--- tags/libnfnetlink/libnfnetlink-0.0.30/include/libnfnetlink/libnfnetlink.h	                        (rev 0)
+++ tags/libnfnetlink/libnfnetlink-0.0.30/include/libnfnetlink/libnfnetlink.h	2007-03-22 00:57:58 UTC (rev 6782)
@@ -0,0 +1,222 @@
+/* libnfnetlink.h: Header file for generic netfilter netlink interface
+ *
+ * (C) 2002 Harald Welte <laforge at gnumonks.org>
+ *
+ * 2005-10-29 Pablo Neira Ayuso <pablo at netfilter.org>:
+ * 	Fix NFNL_HEADER_LEN
+ * 2005-11-13 Pablo Neira Ayuso <pablo at netfilter.org>:
+ * 	Define NETLINK_NETFILTER if it's undefined
+ */
+
+#ifndef __LIBNFNETLINK_H
+#define __LIBNFNETLINK_H
+
+#ifndef aligned_u64
+#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+#endif
+
+#include <sys/socket.h>	/* for sa_family_t */
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <libnfnetlink/linux_nfnetlink.h>
+
+#ifndef NETLINK_NETFILTER
+#define NETLINK_NETFILTER 12
+#endif
+
+#define NLMSG_TAIL(nlh) \
+	(((void *) (nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))
+
+#define NFNL_HEADER_LEN	(NLMSG_ALIGN(sizeof(struct nlmsghdr))	\
+			 +NLMSG_ALIGN(sizeof(struct nfgenmsg)))
+
+#define NFNL_BUFFSIZE		8192
+
+struct nfnlhdr {
+	struct nlmsghdr nlh;
+	struct nfgenmsg nfmsg;
+};
+
+struct nfnl_callback {
+	int (*call)(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data);
+	void *data;
+	u_int16_t attr_count;
+};
+
+struct nfnl_handle;
+struct nfnl_subsys_handle;
+
+extern int nfnl_fd(struct nfnl_handle *h);
+
+/* get a new library handle */
+extern struct nfnl_handle *nfnl_open(void);
+extern int nfnl_close(struct nfnl_handle *);
+
+extern struct nfnl_subsys_handle *nfnl_subsys_open(struct nfnl_handle *, 
+						   u_int8_t, u_int8_t, 
+						   unsigned int);
+extern void nfnl_subsys_close(struct nfnl_subsys_handle *);
+
+/* sending of data */
+extern int nfnl_send(struct nfnl_handle *, struct nlmsghdr *);
+extern int nfnl_sendmsg(const struct nfnl_handle *, const struct msghdr *msg,
+			unsigned int flags);
+extern int nfnl_sendiov(const struct nfnl_handle *nfnlh,
+			const struct iovec *iov, unsigned int num,
+			unsigned int flags);
+extern void nfnl_fill_hdr(struct nfnl_subsys_handle *, struct nlmsghdr *,
+			  unsigned int, u_int8_t, u_int16_t, u_int16_t,
+			  u_int16_t);
+extern int nfnl_talk(struct nfnl_handle *, struct nlmsghdr *, pid_t,
+                     unsigned, struct nlmsghdr *,
+                     int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *),
+                     void *);
+
+/* simple challenge/response */
+extern int nfnl_listen(struct nfnl_handle *,
+                      int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *),
+                      void *);
+
+/* receiving */
+extern ssize_t nfnl_recv(const struct nfnl_handle *h, unsigned char *buf, size_t len);
+extern int nfnl_callback_register(struct nfnl_subsys_handle *,
+				  u_int8_t type, struct nfnl_callback *cb);
+extern int nfnl_callback_unregister(struct nfnl_subsys_handle *, u_int8_t type);
+extern int nfnl_handle_packet(struct nfnl_handle *, char *buf, int len);
+
+/* parsing */
+extern struct nfattr *nfnl_parse_hdr(const struct nfnl_handle *nfnlh, 
+				     const struct nlmsghdr *nlh,
+				     struct nfgenmsg **genmsg);
+extern int nfnl_check_attributes(const struct nfnl_handle *nfnlh,
+				 const struct nlmsghdr *nlh,
+				 struct nfattr *tb[]);
+extern struct nlmsghdr *nfnl_get_msg_first(struct nfnl_handle *h,
+					   const unsigned char *buf,
+					   size_t len);
+extern struct nlmsghdr *nfnl_get_msg_next(struct nfnl_handle *h,
+					  const unsigned char *buf,
+					  size_t len);
+
+/* callback verdict */
+enum {
+	NFNL_CB_FAILURE = -1,   /* failure */
+	NFNL_CB_STOP = 0,       /* stop the query */
+	NFNL_CB_CONTINUE = 1,   /* keep iterating */
+};
+
+/* join a certain netlink multicast group */
+extern int nfnl_join(const struct nfnl_handle *nfnlh, unsigned int group);
+
+/* process a netlink message */
+extern int nfnl_process(struct nfnl_handle *h,
+			const unsigned char *buf,
+			size_t len);
+
+/* iterator API */
+
+extern struct nfnl_iterator *
+nfnl_iterator_create(const struct nfnl_handle *h,
+		     const char *buf,
+		     size_t len);
+
+extern void nfnl_iterator_destroy(struct nfnl_iterator *it);
+
+extern int nfnl_iterator_process(struct nfnl_handle *h,
+				 struct nfnl_iterator *it);
+
+extern int nfnl_iterator_next(const struct nfnl_handle *h,
+			      struct nfnl_iterator *it);
+
+/* replacement for nfnl_listen */
+extern int nfnl_catch(struct nfnl_handle *h);
+
+/* replacement for nfnl_talk */
+extern int nfnl_query(struct nfnl_handle *h, struct nlmsghdr *nlh);
+
+#define nfnl_attr_present(tb, attr)			\
+	(tb[attr-1])
+
+#define nfnl_get_data(tb, attr, type)			\
+	({	type __ret = 0;				\
+	 if (tb[attr-1])				\
+	 __ret = *(type *)NFA_DATA(tb[attr-1]);		\
+	 __ret;						\
+	 })
+
+#define nfnl_get_pointer_to_data(tb, attr, type)	\
+	({	type *__ret = NULL;			\
+	 if (tb[attr-1])				\
+	 __ret = NFA_DATA(tb[attr-1]);			\
+	 __ret;						\
+	 })
+
+/* nfnl attribute handling functions */
+extern int nfnl_addattr_l(struct nlmsghdr *, int, int, const void *, int);
+extern int nfnl_addattr16(struct nlmsghdr *, int, int, u_int16_t);
+extern int nfnl_addattr32(struct nlmsghdr *, int, int, u_int32_t);
+extern int nfnl_nfa_addattr_l(struct nfattr *, int, int, const void *, int);
+extern int nfnl_nfa_addattr16(struct nfattr *, int, int, u_int16_t);
+extern int nfnl_nfa_addattr32(struct nfattr *, int, int, u_int32_t);
+extern int nfnl_parse_attr(struct nfattr **, int, struct nfattr *, int);
+#define nfnl_parse_nested(tb, max, nfa) \
+	nfnl_parse_attr((tb), (max), NFA_DATA((nfa)), NFA_PAYLOAD((nfa)))
+#define nfnl_nest(nlh, bufsize, type) 				\
+({	struct nfattr *__start = NLMSG_TAIL(nlh);		\
+	nfnl_addattr_l(nlh, bufsize, (NFNL_NFA_NEST | type), NULL, 0); 	\
+	__start; })
+#define nfnl_nest_end(nlh, tail) 				\
+({	(tail)->nfa_len = (void *) NLMSG_TAIL(nlh) - (void *) tail; })
+
+extern void nfnl_build_nfa_iovec(struct iovec *iov, struct nfattr *nfa, 
+				 u_int16_t type, u_int32_t len,
+				 unsigned char *val);
+extern unsigned int nfnl_rcvbufsiz(struct nfnl_handle *h, unsigned int size);
+
+
+extern void nfnl_dump_packet(struct nlmsghdr *, int, char *);
+
+/*
+ * index to interface name API
+ */
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+struct nlif_handle;
+
+struct nlif_handle *nlif_open(void);
+void nlif_close(struct nlif_handle *orig);
+int nlif_fd(struct nlif_handle *nlif_handle);
+int nlif_query(struct nlif_handle *nlif_handle);
+int nlif_catch(struct nlif_handle *nlif_handle);
+int nlif_index2name(struct nlif_handle *nlif_handle, 
+		    unsigned int index, 
+		    char *name);
+
+/* Pablo: What is the equivalence of be64_to_cpu in userspace?
+ * 
+ * Harald: Good question.  I don't think there's a standard way [yet?], 
+ * so I'd suggest manually implementing it by "#if little endian" bitshift
+ * operations in C (at least for now).
+ *
+ * All the payload of any nfattr will always be in network byte order.
+ * This would allow easy transport over a real network in the future 
+ * (e.g. jamal's netlink2).
+ *
+ * Pablo: I've called it __be64_to_cpu instead of be64_to_cpu, since maybe 
+ * there will one in the userspace headers someday. We don't want to
+ * pollute POSIX space naming,
+ */
+
+#include <byteswap.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+#  define __be64_to_cpu(x)	(x)
+# else
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define __be64_to_cpu(x)	__bswap_64(x)
+# endif
+#endif
+
+#endif /* __LIBNFNETLINK_H */

Deleted: tags/libnfnetlink/libnfnetlink-0.0.30/src/Makefile.am
===================================================================
--- trunk/libnfnetlink/src/Makefile.am	2007-02-12 01:43:31 UTC (rev 6750)
+++ tags/libnfnetlink/libnfnetlink-0.0.30/src/Makefile.am	2007-03-22 00:57:58 UTC (rev 6782)
@@ -1,12 +0,0 @@
-include $(top_srcdir)/Make_global.am
-
-AM_CFLAGS=-fPIC -Wall
-LIBS=
-
-lib_LTLIBRARIES = libnfnetlink.la
-
-libnfnetlink_la_LDFLAGS = -Wc,-nostartfiles	\
-			  -version-info $(LIBVERSION)
-libnfnetlink_la_SOURCES = libnfnetlink.c iftable.c rtnl.c
-
-noinst_HEADERS = iftable.h rtnl.c

Copied: tags/libnfnetlink/libnfnetlink-0.0.30/src/Makefile.am (from rev 6753, trunk/libnfnetlink/src/Makefile.am)
===================================================================
--- tags/libnfnetlink/libnfnetlink-0.0.30/src/Makefile.am	                        (rev 0)
+++ tags/libnfnetlink/libnfnetlink-0.0.30/src/Makefile.am	2007-03-22 00:57:58 UTC (rev 6782)
@@ -0,0 +1,12 @@
+include $(top_srcdir)/Make_global.am
+
+AM_CFLAGS=-fPIC -Wall
+LIBS=
+
+lib_LTLIBRARIES = libnfnetlink.la
+
+libnfnetlink_la_LDFLAGS = -Wc,-nostartfiles	\
+			  -version-info $(LIBVERSION)
+libnfnetlink_la_SOURCES = libnfnetlink.c iftable.c rtnl.c
+
+noinst_HEADERS = iftable.h rtnl.h

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

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




More information about the netfilter-cvslog mailing list