Thread-safe error handling

In order for the interface to become more thread safe, the error
handling was revised to no longer depend on a static errno and
error string buffer.

This patch converts all error paths to return a libnl specific
error code which can be translated to a error message using
nl_geterror(int error). The functions nl_error() and
nl_get_errno() are therefore obsolete.

This change required various sets of function prototypes to be
changed in order to return an error code, the most prominent
are:

    struct nl_cache *foo_alloc_cache(...);
changed to:
    int foo_alloc_cache(..., struct nl_cache **);

    struct nl_msg *foo_build_request(...);
changed to:
    int foo_build_request(..., struct nl_msg **);

    struct foo *foo_parse(...);
changed to:
    int foo_parse(..., struct foo **);

This pretty much only leaves trivial allocation functions to
still return a pointer object which can still return NULL to
signal out of memory.

This change is a serious API and ABI breaker, sorry!
diff --git a/include/netlink-local.h b/include/netlink-local.h
index 10619ac..1592138 100644
--- a/include/netlink-local.h
+++ b/include/netlink-local.h
@@ -81,43 +81,9 @@
 		assert(0);	\
 	} while (0)
 
-#define RET_ERR(R, E)                    \
-    do {                                 \
-		errno = E;                       \
-		return -R;                       \
-	} while (0)
-
-extern int __nl_error(int, const char *, unsigned int,
-	const char *, const char *, ...);
-
 extern int __nl_read_num_str_file(const char *path,
 				  int (*cb)(long, const char *));
 
-#ifdef NL_ERROR_ASSERT
-#include <assert.h>
-static inline int __assert_error(const char *file, int line, char *func,
-	const char *fmt, ...)
-{
-	va_list args;
-	fprintf(stderr, "%s:%d:%s: ", file, line, func);
-	va_start(args, fmt);
-	vfprintf(stderr, fmt, args);
-	va_end(args);
-	fprintf(stderr, "\n");
-	assert(0);
-	return 0;
-}
-#define nl_error(E, FMT,ARG...) \
-	__assert_error(__FILE__, __LINE__, __FUNCTION__, FMT, ##ARG)
-
-#else
-#define nl_error(E, FMT,ARG...) \
-	__nl_error(E, __FILE__, __LINE__, __FUNCTION__, FMT, ##ARG)
-
-#endif
-
-#define nl_errno(E)	nl_error(E, NULL)
-
 /* backwards compat */
 #define dp_new_line(params, line)	nl_new_line(params)
 #define dp_dump(params, fmt, arg...)	nl_dump(params, fmt, ##arg)
@@ -129,7 +95,7 @@
 
 	tl = calloc(1, sizeof(*tl));
 	if (!tl)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	tl->i = i;
 	tl->a = strdup(a);
diff --git a/include/netlink-tc.h b/include/netlink-tc.h
index 65be588..691969d 100644
--- a/include/netlink-tc.h
+++ b/include/netlink-tc.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_TC_PRIV_H_
@@ -51,7 +51,7 @@
 extern char *tca_get_kind(struct rtnl_tca *);
 extern uint64_t tca_get_stat(struct rtnl_tca *, int );
 
-extern struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags);
+extern int tca_build_msg(struct rtnl_tca *, int, int, struct nl_msg **);
 
 static inline void *tca_priv(struct rtnl_tca *tca)
 {
diff --git a/include/netlink/addr.h b/include/netlink/addr.h
index 8464a0c..00868d2 100644
--- a/include/netlink/addr.h
+++ b/include/netlink/addr.h
@@ -24,7 +24,7 @@
 extern struct nl_addr *	nl_addr_alloc(size_t);
 extern struct nl_addr *	nl_addr_alloc_from_attr(struct nlattr *, int);
 extern struct nl_addr *	nl_addr_build(int, void *, size_t);
-extern struct nl_addr *	nl_addr_parse(const char *, int);
+extern int		nl_addr_parse(const char *, int, struct nl_addr **);
 extern struct nl_addr *	nl_addr_clone(struct nl_addr *);
 
 /* Destroyage */
@@ -42,7 +42,7 @@
 extern int      	nl_addr_guess_family(struct nl_addr *);
 extern int		nl_addr_fill_sockaddr(struct nl_addr *,
 					      struct sockaddr *, socklen_t *);
-extern struct addrinfo *nl_addr_info(struct nl_addr *addr);
+extern int		nl_addr_info(struct nl_addr *, struct addrinfo **);
 extern int		nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen);
 
 /* Access Functions */
diff --git a/include/netlink/cache.h b/include/netlink/cache.h
index cb7741b..b437d76 100644
--- a/include/netlink/cache.h
+++ b/include/netlink/cache.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_CACHE_H_
@@ -39,7 +39,11 @@
 /* Cache creation/deletion */
 #define nl_cache_alloc_from_ops(ptr)	nl_cache_alloc(ptr)
 extern struct nl_cache *	nl_cache_alloc(struct nl_cache_ops *);
-extern struct nl_cache *	nl_cache_alloc_name(const char *);
+extern int			nl_cache_alloc_and_fill(struct nl_cache_ops *,
+							struct nl_handle *,
+							struct nl_cache **);
+extern int			nl_cache_alloc_name(const char *,
+						    struct nl_cache **);
 extern struct nl_cache *	nl_cache_subset(struct nl_cache *,
 						struct nl_object *);
 extern void			nl_cache_clear(struct nl_cache *);
@@ -106,11 +110,13 @@
 
 #define NL_AUTO_PROVIDE		1
 
-extern struct nl_cache_mngr *	nl_cache_mngr_alloc(struct nl_handle *,
-						    int, int);
-extern struct nl_cache *	nl_cache_mngr_add(struct nl_cache_mngr *,
+extern int			nl_cache_mngr_alloc(struct nl_handle *,
+						    int, int,
+						    struct nl_cache_mngr **);
+extern int			nl_cache_mngr_add(struct nl_cache_mngr *,
 						  const char *,
-						  change_func_t);
+						  change_func_t,
+						  struct nl_cache **);
 extern int			nl_cache_mngr_get_fd(struct nl_cache_mngr *);
 extern int			nl_cache_mngr_poll(struct nl_cache_mngr *,
 						   int);
diff --git a/include/netlink/errno.h b/include/netlink/errno.h
new file mode 100644
index 0000000..0b43da0
--- /dev/null
+++ b/include/netlink/errno.h
@@ -0,0 +1,59 @@
+/*
+ * netlink/errno.h		Error Numbers
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ERRNO_H_
+#define NETLINK_ERRNO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NLE_SUCCESS		0
+#define NLE_FAILURE		1
+#define NLE_INTR		2
+#define NLE_BAD_SOCK		3
+#define NLE_AGAIN		4
+#define NLE_NOMEM		5
+#define NLE_EXIST		6
+#define NLE_INVAL		7
+#define NLE_RANGE		8
+#define NLE_MSGSIZE		9
+#define NLE_OPNOTSUPP		10
+#define NLE_AF_NOSUPPORT	11
+#define NLE_OBJ_NOTFOUND	12
+#define NLE_NOATTR		13
+#define NLE_MISSING_ATTR	14
+#define NLE_AF_MISMATCH		15
+#define NLE_SEQ_MISMATCH	16
+#define NLE_MSG_OVERFLOW	17
+#define NLE_MSG_TRUNC		18
+#define NLE_NOADDR		19
+#define NLE_SRCRT_NOSUPPORT	20
+#define NLE_MSG_TOOSHORT	21
+#define NLE_MSGTYPE_NOSUPPORT	22
+#define NLE_OBJ_MISMATCH	23
+#define NLE_NOCACHE		24
+#define NLE_BUSY		25
+#define NLE_PROTO_MISMATCH	26
+#define NLE_NOACCESS		27
+#define NLE_PERM		28
+
+#define NLE_MAX			NLE_PERM
+
+extern const char *	nl_geterror(int);
+extern void		nl_perror(int, const char *);
+extern int		nl_syserr2nlerr(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/fib_lookup/lookup.h b/include/netlink/fib_lookup/lookup.h
index 29c7ee8..201a7a0 100644
--- a/include/netlink/fib_lookup/lookup.h
+++ b/include/netlink/fib_lookup/lookup.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_FIB_LOOKUP_H_
@@ -28,8 +28,9 @@
 
 extern struct nl_cache *	flnl_result_alloc_cache(void);
 
-extern struct nl_msg *		flnl_lookup_build_request(struct flnl_request *,
-							  int);
+extern int			flnl_lookup_build_request(struct flnl_request *,
+							  int,
+							  struct nl_msg **);
 extern int			flnl_lookup(struct nl_handle *,
 					    struct flnl_request *,
 					    struct nl_cache *);
diff --git a/include/netlink/genl/ctrl.h b/include/netlink/genl/ctrl.h
index 5d65c68..f66338e 100644
--- a/include/netlink/genl/ctrl.h
+++ b/include/netlink/genl/ctrl.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_GENL_CTRL_H_
@@ -22,7 +22,8 @@
 
 struct genl_family;
 
-extern struct nl_cache *	genl_ctrl_alloc_cache(struct nl_handle *);
+extern int			genl_ctrl_alloc_cache(struct nl_handle *,
+						      struct nl_cache **);
 extern struct genl_family *	genl_ctrl_search(struct nl_cache *, int);
 extern struct genl_family *	genl_ctrl_search_by_name(struct nl_cache *,
 							 const char *);
diff --git a/include/netlink/netfilter/ct.h b/include/netlink/netfilter/ct.h
index f554017..2e08228 100644
--- a/include/netlink/netfilter/ct.h
+++ b/include/netlink/netfilter/ct.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  */
@@ -27,95 +27,95 @@
 
 extern struct nl_object_ops ct_obj_ops;
 
-/* General */
 extern struct nfnl_ct *	nfnl_ct_alloc(void);
-extern struct nl_cache *nfnl_ct_alloc_cache(struct nl_handle *);
+extern int	nfnl_ct_alloc_cache(struct nl_handle *, struct nl_cache **);
 
-extern int		nfnlmsg_ct_group(struct nlmsghdr *);
-extern struct nfnl_ct *	nfnlmsg_ct_parse(struct nlmsghdr *);
+extern int	nfnlmsg_ct_group(struct nlmsghdr *);
+extern int	nfnlmsg_ct_parse(struct nlmsghdr *, struct nfnl_ct **);
 
-extern void		nfnl_ct_get(struct nfnl_ct *);
-extern void		nfnl_ct_put(struct nfnl_ct *);
+extern void	nfnl_ct_get(struct nfnl_ct *);
+extern void	nfnl_ct_put(struct nfnl_ct *);
 
-extern int		nfnl_ct_dump_request(struct nl_handle *);
+extern int	nfnl_ct_dump_request(struct nl_handle *);
 
-extern struct nl_msg *	nfnl_ct_build_add_request(const struct nfnl_ct *, int);
-extern int		nfnl_ct_add(struct nl_handle *, const struct nfnl_ct *, int);
+extern int	nfnl_ct_build_add_request(const struct nfnl_ct *, int,
+					  struct nl_msg **);
+extern int	nfnl_ct_add(struct nl_handle *, const struct nfnl_ct *, int);
 
-extern struct nl_msg *	nfnl_ct_build_delete_request(const struct nfnl_ct *, int);
-extern int		nfnl_ct_delete(struct nl_handle *, const struct nfnl_ct *, int);
+extern int	nfnl_ct_build_delete_request(const struct nfnl_ct *, int,
+					     struct nl_msg **);
+extern int	nfnl_ct_delete(struct nl_handle *, const struct nfnl_ct *, int);
 
-extern struct nl_msg *	nfnl_ct_build_query_request(const struct nfnl_ct *, int);
-extern int		nfnl_ct_query(struct nl_handle *, const struct nfnl_ct *, int);
+extern int	nfnl_ct_build_query_request(const struct nfnl_ct *, int,
+					    struct nl_msg **);
+extern int	nfnl_ct_query(struct nl_handle *, const struct nfnl_ct *, int);
 
-extern void		nfnl_ct_set_family(struct nfnl_ct *, uint8_t);
-extern uint8_t		nfnl_ct_get_family(const struct nfnl_ct *);
+extern void	nfnl_ct_set_family(struct nfnl_ct *, uint8_t);
+extern uint8_t	nfnl_ct_get_family(const struct nfnl_ct *);
 
-extern void		nfnl_ct_set_proto(struct nfnl_ct *, uint8_t);
-extern int		nfnl_ct_test_proto(const struct nfnl_ct *);
-extern uint8_t		nfnl_ct_get_proto(const struct nfnl_ct *);
+extern void	nfnl_ct_set_proto(struct nfnl_ct *, uint8_t);
+extern int	nfnl_ct_test_proto(const struct nfnl_ct *);
+extern uint8_t	nfnl_ct_get_proto(const struct nfnl_ct *);
 
-extern void		nfnl_ct_set_tcp_state(struct nfnl_ct *, uint8_t);
-extern int		nfnl_ct_test_tcp_state(const struct nfnl_ct *);
-extern uint8_t		nfnl_ct_get_tcp_state(const struct nfnl_ct *);
-extern char *		nfnl_ct_tcp_state2str(uint8_t, char *, size_t);
-extern int		nfnl_ct_str2tcp_state(const char *name);
+extern void	nfnl_ct_set_tcp_state(struct nfnl_ct *, uint8_t);
+extern int	nfnl_ct_test_tcp_state(const struct nfnl_ct *);
+extern uint8_t	nfnl_ct_get_tcp_state(const struct nfnl_ct *);
+extern char *	nfnl_ct_tcp_state2str(uint8_t, char *, size_t);
+extern int	nfnl_ct_str2tcp_state(const char *name);
 
-extern void		nfnl_ct_set_status(struct nfnl_ct *, uint32_t);
-extern void		nfnl_ct_unset_status(struct nfnl_ct *, uint32_t);
-extern uint32_t		nfnl_ct_get_status(const struct nfnl_ct *);
+extern void	nfnl_ct_set_status(struct nfnl_ct *, uint32_t);
+extern void	nfnl_ct_unset_status(struct nfnl_ct *, uint32_t);
+extern uint32_t	nfnl_ct_get_status(const struct nfnl_ct *);
 
-extern void		nfnl_ct_set_timeout(struct nfnl_ct *, uint32_t);
-extern int		nfnl_ct_test_timeout(const struct nfnl_ct *);
-extern uint32_t		nfnl_ct_get_timeout(const struct nfnl_ct *);
+extern void	nfnl_ct_set_timeout(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_timeout(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_timeout(const struct nfnl_ct *);
 
-extern void		nfnl_ct_set_mark(struct nfnl_ct *, uint32_t);
-extern int		nfnl_ct_test_mark(const struct nfnl_ct *);
-extern uint32_t		nfnl_ct_get_mark(const struct nfnl_ct *);
+extern void	nfnl_ct_set_mark(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_mark(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_mark(const struct nfnl_ct *);
 
-extern void		nfnl_ct_set_use(struct nfnl_ct *, uint32_t);
-extern int		nfnl_ct_test_use(const struct nfnl_ct *);
-extern uint32_t		nfnl_ct_get_use(const struct nfnl_ct *);
+extern void	nfnl_ct_set_use(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_use(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_use(const struct nfnl_ct *);
 
-extern void		nfnl_ct_set_id(struct nfnl_ct *, uint32_t);
-extern int		nfnl_ct_test_id(const struct nfnl_ct *);
-extern uint32_t		nfnl_ct_get_id(const struct nfnl_ct *);
+extern void	nfnl_ct_set_id(struct nfnl_ct *, uint32_t);
+extern int	nfnl_ct_test_id(const struct nfnl_ct *);
+extern uint32_t	nfnl_ct_get_id(const struct nfnl_ct *);
 
-extern int		nfnl_ct_set_src(struct nfnl_ct *, int,
-					struct nl_addr *);
+extern int	nfnl_ct_set_src(struct nfnl_ct *, int, struct nl_addr *);
 extern struct nl_addr *	nfnl_ct_get_src(const struct nfnl_ct *, int);
 
-extern int		nfnl_ct_set_dst(struct nfnl_ct *, int,
-					struct nl_addr *);
+extern int	nfnl_ct_set_dst(struct nfnl_ct *, int, struct nl_addr *);
 extern struct nl_addr *	nfnl_ct_get_dst(const struct nfnl_ct *, int);
 
-extern void		nfnl_ct_set_src_port(struct nfnl_ct *, int, uint16_t);
-extern int		nfnl_ct_test_src_port(const struct nfnl_ct *, int);
-extern uint16_t		nfnl_ct_get_src_port(const struct nfnl_ct *, int);
+extern void	nfnl_ct_set_src_port(struct nfnl_ct *, int, uint16_t);
+extern int	nfnl_ct_test_src_port(const struct nfnl_ct *, int);
+extern uint16_t	nfnl_ct_get_src_port(const struct nfnl_ct *, int);
 
-extern void		nfnl_ct_set_dst_port(struct nfnl_ct *, int, uint16_t);
-extern int		nfnl_ct_test_dst_port(const struct nfnl_ct *, int);
-extern uint16_t		nfnl_ct_get_dst_port(const struct nfnl_ct *, int);
+extern void	nfnl_ct_set_dst_port(struct nfnl_ct *, int, uint16_t);
+extern int	nfnl_ct_test_dst_port(const struct nfnl_ct *, int);
+extern uint16_t	nfnl_ct_get_dst_port(const struct nfnl_ct *, int);
 
-extern void		nfnl_ct_set_icmp_id(struct nfnl_ct *, int, uint16_t);
-extern int		nfnl_ct_test_icmp_id(const struct nfnl_ct *, int);
-extern uint16_t		nfnl_ct_get_icmp_id(const struct nfnl_ct *, int);
+extern void	nfnl_ct_set_icmp_id(struct nfnl_ct *, int, uint16_t);
+extern int	nfnl_ct_test_icmp_id(const struct nfnl_ct *, int);
+extern uint16_t	nfnl_ct_get_icmp_id(const struct nfnl_ct *, int);
 
-extern void		nfnl_ct_set_icmp_type(struct nfnl_ct *, int, uint8_t);
-extern int		nfnl_ct_test_icmp_type(const struct nfnl_ct *, int);
-extern uint8_t		nfnl_ct_get_icmp_type(const struct nfnl_ct *, int);
+extern void	nfnl_ct_set_icmp_type(struct nfnl_ct *, int, uint8_t);
+extern int	nfnl_ct_test_icmp_type(const struct nfnl_ct *, int);
+extern uint8_t	nfnl_ct_get_icmp_type(const struct nfnl_ct *, int);
 
-extern void		nfnl_ct_set_icmp_code(struct nfnl_ct *, int, uint8_t);
-extern int		nfnl_ct_test_icmp_code(const struct nfnl_ct *, int);
-extern uint8_t		nfnl_ct_get_icmp_code(const struct nfnl_ct *, int);
+extern void	nfnl_ct_set_icmp_code(struct nfnl_ct *, int, uint8_t);
+extern int	nfnl_ct_test_icmp_code(const struct nfnl_ct *, int);
+extern uint8_t	nfnl_ct_get_icmp_code(const struct nfnl_ct *, int);
 
-extern void		nfnl_ct_set_packets(struct nfnl_ct *, int, uint64_t);
-extern int		nfnl_ct_test_packets(const struct nfnl_ct *, int);
-extern uint64_t		nfnl_ct_get_packets(const struct nfnl_ct *,int);
+extern void	nfnl_ct_set_packets(struct nfnl_ct *, int, uint64_t);
+extern int	nfnl_ct_test_packets(const struct nfnl_ct *, int);
+extern uint64_t	nfnl_ct_get_packets(const struct nfnl_ct *,int);
 
-extern void		nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t);
-extern int		nfnl_ct_test_bytes(const struct nfnl_ct *, int);
-extern uint64_t		nfnl_ct_get_bytes(const struct nfnl_ct *, int);
+extern void	nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t);
+extern int	nfnl_ct_test_bytes(const struct nfnl_ct *, int);
+extern uint64_t	nfnl_ct_get_bytes(const struct nfnl_ct *, int);
 
 #ifdef __cplusplus
 }
diff --git a/include/netlink/netfilter/log.h b/include/netlink/netfilter/log.h
index 51f4a90..be8dd32 100644
--- a/include/netlink/netfilter/log.h
+++ b/include/netlink/netfilter/log.h
@@ -40,7 +40,8 @@
 
 /* General */
 extern struct nfnl_log *	nfnl_log_alloc(void);
-extern struct nfnl_log *	nfnlmsg_log_parse(struct nlmsghdr *);
+extern int			nfnlmsg_log_parse(struct nlmsghdr *,
+						  struct nfnl_log **);
 
 extern void			nfnl_log_get(struct nfnl_log *);
 extern void			nfnl_log_put(struct nfnl_log *);
@@ -82,24 +83,23 @@
 extern char *			nfnl_log_flags2str(unsigned int, char *, size_t);
 extern unsigned int		nfnl_log_str2flags(const char *);
 
-/* Message construction / sending */
-extern struct nl_msg *		nfnl_log_build_pf_bind(uint8_t);
-extern int			nfnl_log_pf_bind(struct nl_handle *, uint8_t);
+extern int	nfnl_log_build_pf_bind(uint8_t, struct nl_msg **);
+extern int	nfnl_log_pf_bind(struct nl_handle *, uint8_t);
 
-extern struct nl_msg *		nfnl_log_build_pf_unbind(uint8_t);
-extern int			nfnl_log_pf_unbind(struct nl_handle *, uint8_t);
+extern int	nfnl_log_build_pf_unbind(uint8_t, struct nl_msg **);
+extern int	nfnl_log_pf_unbind(struct nl_handle *, uint8_t);
 
-extern struct nl_msg *		nfnl_log_build_create_request(const struct nfnl_log *);
-extern int			nfnl_log_create(struct nl_handle *,
-						const struct nfnl_log *);
+extern int	nfnl_log_build_create_request(const struct nfnl_log *,
+					      struct nl_msg **);
+extern int	nfnl_log_create(struct nl_handle *, const struct nfnl_log *);
 
-extern struct nl_msg *		nfnl_log_build_change_request(const struct nfnl_log *);
-extern int			nfnl_log_change(struct nl_handle *,
-						const struct nfnl_log *);
+extern int	nfnl_log_build_change_request(const struct nfnl_log *,
+					      struct nl_msg **);
+extern int	nfnl_log_change(struct nl_handle *, const struct nfnl_log *);
 
-extern struct nl_msg *		nfnl_log_build_delete_request(const struct nfnl_log *);
-extern int			nfnl_log_delete(struct nl_handle *,
-						const struct nfnl_log *);
+extern int	nfnl_log_build_delete_request(const struct nfnl_log *,
+					      struct nl_msg **);
+extern int	nfnl_log_delete(struct nl_handle *, const struct nfnl_log *);
 
 #ifdef __cplusplus
 }
diff --git a/include/netlink/netfilter/log_msg.h b/include/netlink/netfilter/log_msg.h
index 0cdb6c6..42e1f70 100644
--- a/include/netlink/netfilter/log_msg.h
+++ b/include/netlink/netfilter/log_msg.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
@@ -29,7 +29,8 @@
 
 /* General */
 extern struct nfnl_log_msg *nfnl_log_msg_alloc(void);
-extern struct nfnl_log_msg *nfnlmsg_log_msg_parse(struct nlmsghdr *);
+extern int		nfnlmsg_log_msg_parse(struct nlmsghdr *,
+					      struct nfnl_log_msg **);
 
 extern void		nfnl_log_msg_get(struct nfnl_log_msg *);
 extern void		nfnl_log_msg_put(struct nfnl_log_msg *);
diff --git a/include/netlink/netfilter/queue.h b/include/netlink/netfilter/queue.h
index c88abe2..d480135 100644
--- a/include/netlink/netfilter/queue.h
+++ b/include/netlink/netfilter/queue.h
@@ -59,24 +59,26 @@
 extern int			nfnl_queue_test_copy_range(const struct nfnl_queue *);
 extern uint32_t			nfnl_queue_get_copy_range(const struct nfnl_queue *);
 
-/* Message construction / sending */
-extern struct nl_msg *		nfnl_queue_build_pf_bind(uint8_t);
-extern int			nfnl_queue_pf_bind(struct nl_handle *, uint8_t);
+extern int	nfnl_queue_build_pf_bind(uint8_t, struct nl_msg **);
+extern int	nfnl_queue_pf_bind(struct nl_handle *, uint8_t);
 
-extern struct nl_msg *		nfnl_queue_build_pf_unbind(uint8_t);
-extern int			nfnl_queue_pf_unbind(struct nl_handle *, uint8_t);
+extern int	nfnl_queue_build_pf_unbind(uint8_t, struct nl_msg **);
+extern int	nfnl_queue_pf_unbind(struct nl_handle *, uint8_t);
 
-extern struct nl_msg *		nfnl_queue_build_create_request(const struct nfnl_queue *);
-extern int			nfnl_queue_create(struct nl_handle *,
-						  const struct nfnl_queue *);
+extern int	nfnl_queue_build_create_request(const struct nfnl_queue *,
+						struct nl_msg **);
+extern int	nfnl_queue_create(struct nl_handle *,
+				  const struct nfnl_queue *);
 
-extern struct nl_msg *		nfnl_queue_build_change_request(const struct nfnl_queue *);
-extern int			nfnl_queue_change(struct nl_handle *,
-						  const struct nfnl_queue *);
+extern int	nfnl_queue_build_change_request(const struct nfnl_queue *,
+						struct nl_msg **);
+extern int	nfnl_queue_change(struct nl_handle *,
+				  const struct nfnl_queue *);
 
-extern struct nl_msg *		nfnl_queue_build_delete_request(const struct nfnl_queue *);
-extern int			nfnl_queue_delete(struct nl_handle *,
-						  const struct nfnl_queue *);
+extern int	nfnl_queue_build_delete_request(const struct nfnl_queue *,
+						struct nl_msg **);
+extern int	nfnl_queue_delete(struct nl_handle *,
+				  const struct nfnl_queue *);
 
 #ifdef __cplusplus
 }
diff --git a/include/netlink/netfilter/queue_msg.h b/include/netlink/netfilter/queue_msg.h
index bb63236..f8f034c 100644
--- a/include/netlink/netfilter/queue_msg.h
+++ b/include/netlink/netfilter/queue_msg.h
@@ -26,7 +26,8 @@
 
 /* General */
 extern struct nfnl_queue_msg *	nfnl_queue_msg_alloc(void);
-extern struct nfnl_queue_msg *	nfnlmsg_queue_msg_parse(struct nlmsghdr *);
+extern int			nfnlmsg_queue_msg_parse(struct nlmsghdr *,
+						struct nfnl_queue_msg **);
 
 extern void			nfnl_queue_msg_get(struct nfnl_queue_msg *);
 extern void			nfnl_queue_msg_put(struct nfnl_queue_msg *);
diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h
index bfae909..eff4b16 100644
--- a/include/netlink/netlink.h
+++ b/include/netlink/netlink.h
@@ -26,6 +26,7 @@
 #include <linux/genetlink.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <netlink/version.h>
+#include <netlink/errno.h>
 #include <netlink/types.h>
 #include <netlink/handlers.h>
 #include <netlink/socket.h>
diff --git a/include/netlink/object.h b/include/netlink/object.h
index 751a1b3..bae2bf4 100644
--- a/include/netlink/object.h
+++ b/include/netlink/object.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_OBJECT_H_
@@ -27,7 +27,8 @@
 
 /* General */
 extern struct nl_object *	nl_object_alloc(struct nl_object_ops *);
-extern struct nl_object *	nl_object_alloc_name(const char *);
+extern int			nl_object_alloc_name(const char *,
+						     struct nl_object **);
 extern void			nl_object_free(struct nl_object *);
 extern struct nl_object *	nl_object_clone(struct nl_object *obj);
 extern void			nl_object_get(struct nl_object *);
diff --git a/include/netlink/route/addr.h b/include/netlink/route/addr.h
index 71a90e0..9004ca0 100644
--- a/include/netlink/route/addr.h
+++ b/include/netlink/route/addr.h
@@ -6,8 +6,8 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- *                         Baruch Even <baruch@ev-en.org>,
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
  *                         Mediatrix Telecom, inc. <ericb@mediatrix.com>
  */
 
@@ -26,63 +26,56 @@
 
 /* General */
 extern struct rtnl_addr *rtnl_addr_alloc(void);
-extern void		rtnl_addr_put(struct rtnl_addr *);
+extern void	rtnl_addr_put(struct rtnl_addr *);
 
-extern struct nl_cache *rtnl_addr_alloc_cache(struct nl_handle *);
+extern int	rtnl_addr_alloc_cache(struct nl_handle *, struct nl_cache **);
 
-/* Address Addition */
-extern struct nl_msg *	rtnl_addr_build_add_request(struct rtnl_addr *, int);
-extern int		rtnl_addr_add(struct nl_handle *, struct rtnl_addr *,
-				      int);
+extern int	rtnl_addr_build_add_request(struct rtnl_addr *, int,
+					    struct nl_msg **);
+extern int	rtnl_addr_add(struct nl_handle *, struct rtnl_addr *, int);
 
-/* Address Deletion */
-extern struct nl_msg *	rtnl_addr_build_delete_request(struct rtnl_addr *, int);
-extern int		rtnl_addr_delete(struct nl_handle *,
-					 struct rtnl_addr *, int);
+extern int	rtnl_addr_build_delete_request(struct rtnl_addr *, int,
+					       struct nl_msg **);
+extern int	rtnl_addr_delete(struct nl_handle *,
+				 struct rtnl_addr *, int);
 
-/* Address Flags Translations */
-extern char *		rtnl_addr_flags2str(int, char *, size_t);
-extern int		rtnl_addr_str2flags(const char *);
+extern char *	rtnl_addr_flags2str(int, char *, size_t);
+extern int	rtnl_addr_str2flags(const char *);
 
-/* Attribute Access */
-extern void		rtnl_addr_set_label(struct rtnl_addr *, const char *);
-extern char *		rtnl_addr_get_label(struct rtnl_addr *);
+extern void	rtnl_addr_set_label(struct rtnl_addr *, const char *);
+extern char *	rtnl_addr_get_label(struct rtnl_addr *);
 
-extern void		rtnl_addr_set_ifindex(struct rtnl_addr *, int);
-extern int		rtnl_addr_get_ifindex(struct rtnl_addr *);
+extern void	rtnl_addr_set_ifindex(struct rtnl_addr *, int);
+extern int	rtnl_addr_get_ifindex(struct rtnl_addr *);
 
-extern void		rtnl_addr_set_family(struct rtnl_addr *, int);
-extern int		rtnl_addr_get_family(struct rtnl_addr *);
+extern void	rtnl_addr_set_family(struct rtnl_addr *, int);
+extern int	rtnl_addr_get_family(struct rtnl_addr *);
 
-extern void		rtnl_addr_set_prefixlen(struct rtnl_addr *, int);
-extern int		rtnl_addr_get_prefixlen(struct rtnl_addr *);
+extern void	rtnl_addr_set_prefixlen(struct rtnl_addr *, int);
+extern int	rtnl_addr_get_prefixlen(struct rtnl_addr *);
 
-extern void		rtnl_addr_set_scope(struct rtnl_addr *, int);
-extern int		rtnl_addr_get_scope(struct rtnl_addr *);
+extern void	rtnl_addr_set_scope(struct rtnl_addr *, int);
+extern int	rtnl_addr_get_scope(struct rtnl_addr *);
 
-extern void		rtnl_addr_set_flags(struct rtnl_addr *, unsigned int);
-extern void		rtnl_addr_unset_flags(struct rtnl_addr *, unsigned int);
-extern unsigned int	rtnl_addr_get_flags(struct rtnl_addr *);
+extern void	rtnl_addr_set_flags(struct rtnl_addr *, unsigned int);
+extern void	rtnl_addr_unset_flags(struct rtnl_addr *, unsigned int);
+extern unsigned int rtnl_addr_get_flags(struct rtnl_addr *);
 
-extern int		rtnl_addr_set_local(struct rtnl_addr *,
+extern int	rtnl_addr_set_local(struct rtnl_addr *,
 					    struct nl_addr *);
-extern struct nl_addr *	rtnl_addr_get_local(struct rtnl_addr *);
+extern struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *);
 
-extern int		rtnl_addr_set_peer(struct rtnl_addr *,
-					   struct nl_addr *);
-extern struct nl_addr *	rtnl_addr_get_peer(struct rtnl_addr *);
+extern int	rtnl_addr_set_peer(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *);
 
-extern int		rtnl_addr_set_broadcast(struct rtnl_addr *,
-						struct nl_addr *);
-extern struct nl_addr *	rtnl_addr_get_broadcast(struct rtnl_addr *);
+extern int	rtnl_addr_set_broadcast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *);
 
-extern int		rtnl_addr_set_anycast(struct rtnl_addr *,
-					      struct nl_addr *);
-extern struct nl_addr *	rtnl_addr_get_anycast(struct rtnl_addr *);
+extern int	rtnl_addr_set_anycast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *);
 
-extern int		rtnl_addr_set_multicast(struct rtnl_addr *,
-						struct nl_addr *);
-extern struct nl_addr *	rtnl_addr_get_multicast(struct rtnl_addr *);
+extern int	rtnl_addr_set_multicast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *);
 
 #ifdef __cplusplus
 }
diff --git a/include/netlink/route/class.h b/include/netlink/route/class.h
index a624ef6..a704ed1 100644
--- a/include/netlink/route/class.h
+++ b/include/netlink/route/class.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_CLASS_H_
@@ -24,20 +24,20 @@
 
 extern struct nl_object_ops class_obj_ops;
 
-/* General */
 extern struct rtnl_class *	rtnl_class_alloc(void);
-extern void			rtnl_class_put(struct rtnl_class *);
-extern struct nl_cache *	rtnl_class_alloc_cache(struct nl_handle *, int);
+extern void		rtnl_class_put(struct rtnl_class *);
+extern int		rtnl_class_alloc_cache(struct nl_handle *, int,
+					       struct nl_cache **);
 
 /* leaf qdisc access */
 extern struct rtnl_qdisc *	rtnl_class_leaf_qdisc(struct rtnl_class *,
 						      struct nl_cache *);
 
-/* class addition */
-extern struct nl_msg * rtnl_class_build_add_request(struct rtnl_class *, int);
-extern int rtnl_class_add(struct nl_handle *, struct rtnl_class *, int);
+extern int		rtnl_class_build_add_request(struct rtnl_class *, int,
+						     struct nl_msg **);
+extern int		rtnl_class_add(struct nl_handle *, struct rtnl_class *,
+				       int);
 
-/* attribute modification */
 extern void		rtnl_class_set_ifindex(struct rtnl_class *, int);
 extern int		rtnl_class_get_ifindex(struct rtnl_class *);
 extern void		rtnl_class_set_handle(struct rtnl_class *, uint32_t);
diff --git a/include/netlink/route/classifier.h b/include/netlink/route/classifier.h
index 7ef0da4..0ee563e 100644
--- a/include/netlink/route/classifier.h
+++ b/include/netlink/route/classifier.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_CLASSIFIER_H_
@@ -23,21 +23,22 @@
 
 extern struct nl_object_ops cls_obj_ops;
 
-extern struct		rtnl_cls *rtnl_cls_alloc(void);
-extern void		rtnl_cls_put(struct rtnl_cls *);
+extern struct rtnl_cls *rtnl_cls_alloc(void);
+extern void	rtnl_cls_put(struct rtnl_cls *);
 
-extern struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *, int, uint32_t);
+extern int	rtnl_cls_alloc_cache(struct nl_handle *, int, uint32_t,
+				     struct nl_cache **);
 
-/* classifier addition */
-extern int		rtnl_cls_add(struct nl_handle *, struct rtnl_cls *,
-				     int);
-extern struct nl_msg *	rtnl_cls_build_add_request(struct rtnl_cls *, int);
+extern int	rtnl_cls_build_add_request(struct rtnl_cls *, int,
+					   struct nl_msg **);
+extern int	rtnl_cls_add(struct nl_handle *, struct rtnl_cls *, int);
 
-extern struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *, int);
-extern struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *, int);
-extern int  rtnl_cls_delete(struct nl_handle *, struct rtnl_cls *, int);
+extern int	rtnl_cls_build_change_request(struct rtnl_cls *, int,
+					      struct nl_msg **);
+extern int	rtnl_cls_build_delete_request(struct rtnl_cls *, int,
+					      struct nl_msg **);
+extern int	rtnl_cls_delete(struct nl_handle *, struct rtnl_cls *, int);
 
-/* attribute modification */
 extern void rtnl_cls_set_ifindex(struct rtnl_cls *, int);
 extern void rtnl_cls_set_handle(struct rtnl_cls *, uint32_t);
 extern void rtnl_cls_set_parent(struct rtnl_cls *, uint32_t);
diff --git a/include/netlink/route/link.h b/include/netlink/route/link.h
index caaa792..87e5ada 100644
--- a/include/netlink/route/link.h
+++ b/include/netlink/route/link.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_LINK_H_
@@ -58,109 +58,91 @@
 #define RTNL_LINK_NOT_FOUND -1
 
 /* link object allocation/freeage */
-extern struct rtnl_link *	rtnl_link_alloc(void);
-extern void			rtnl_link_put(struct rtnl_link *);
-extern void			rtnl_link_free(struct rtnl_link *);
+extern struct rtnl_link *rtnl_link_alloc(void);
+extern void	rtnl_link_put(struct rtnl_link *);
+extern void	rtnl_link_free(struct rtnl_link *);
 
 /* link cache management */
-extern struct nl_cache *	rtnl_link_alloc_cache(struct nl_handle *);
-extern struct rtnl_link *	rtnl_link_get(struct nl_cache *, int);
-extern struct rtnl_link *	rtnl_link_get_by_name(struct nl_cache *,
-						      const char *);
+extern int	rtnl_link_alloc_cache(struct nl_handle *, struct nl_cache **);
+extern struct rtnl_link *rtnl_link_get(struct nl_cache *, int);
+extern struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *, const char *);
 
 
-/* Link Modifications */
-extern struct nl_msg *		rtnl_link_build_change_request(struct rtnl_link *,
-							       struct rtnl_link *,
-							       int);
-extern int			rtnl_link_change(struct nl_handle *,
-						 struct rtnl_link *,
-						 struct rtnl_link *, int);
+extern int	rtnl_link_build_change_request(struct rtnl_link *,
+					       struct rtnl_link *, int,
+					       struct nl_msg **);
+extern int	rtnl_link_change(struct nl_handle *, struct rtnl_link *,
+				 struct rtnl_link *, int);
 
 /* Name <-> Index Translations */
-extern char * 			rtnl_link_i2name(struct nl_cache *, int,
-						 char *, size_t);
-extern int			rtnl_link_name2i(struct nl_cache *,
-						 const char *);
+extern char * 	rtnl_link_i2name(struct nl_cache *, int, char *, size_t);
+extern int	rtnl_link_name2i(struct nl_cache *, const char *);
 
 /* Name <-> Statistic Translations */
-extern char *			rtnl_link_stat2str(int, char *, size_t);
-extern int			rtnl_link_str2stat(const char *);
+extern char *	rtnl_link_stat2str(int, char *, size_t);
+extern int	rtnl_link_str2stat(const char *);
 
 /* Link Flags Translations */
-extern char *			rtnl_link_flags2str(int, char *, size_t);
-extern int			rtnl_link_str2flags(const char *);
+extern char *	rtnl_link_flags2str(int, char *, size_t);
+extern int	rtnl_link_str2flags(const char *);
 
-extern char *			rtnl_link_operstate2str(int, char *, size_t);
-extern int			rtnl_link_str2operstate(const char *);
+extern char *	rtnl_link_operstate2str(int, char *, size_t);
+extern int	rtnl_link_str2operstate(const char *);
 
-extern char *			rtnl_link_mode2str(int, char *, size_t);
-extern int			rtnl_link_str2mode(const char *);
+extern char *	rtnl_link_mode2str(int, char *, size_t);
+extern int	rtnl_link_str2mode(const char *);
 
 /* Access Functions */
-extern void			rtnl_link_set_qdisc(struct rtnl_link *,
-						    const char *);
-extern char *			rtnl_link_get_qdisc(struct rtnl_link *);
+extern void	rtnl_link_set_qdisc(struct rtnl_link *, const char *);
+extern char *	rtnl_link_get_qdisc(struct rtnl_link *);
 
-extern void			rtnl_link_set_name(struct rtnl_link *,
-						   const char *);
-extern char *			rtnl_link_get_name(struct rtnl_link *);
+extern void	rtnl_link_set_name(struct rtnl_link *, const char *);
+extern char *	rtnl_link_get_name(struct rtnl_link *);
 
-extern void			rtnl_link_set_flags(struct rtnl_link *,
-						    unsigned int);
-extern void			rtnl_link_unset_flags(struct rtnl_link *,
-						      unsigned int);
-extern unsigned int		rtnl_link_get_flags(struct rtnl_link *);
+extern void	rtnl_link_set_flags(struct rtnl_link *, unsigned int);
+extern void	rtnl_link_unset_flags(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_flags(struct rtnl_link *);
 
-extern void			rtnl_link_set_mtu(struct rtnl_link *,
-						  unsigned int);
-extern unsigned int		rtnl_link_get_mtu(struct rtnl_link *);
+extern void	rtnl_link_set_mtu(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_mtu(struct rtnl_link *);
 
-extern void			rtnl_link_set_txqlen(struct rtnl_link *,
-						     unsigned int);
-extern unsigned int		rtnl_link_get_txqlen(struct rtnl_link *);
+extern void	rtnl_link_set_txqlen(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_txqlen(struct rtnl_link *);
 
-extern void			rtnl_link_set_weight(struct rtnl_link *,
-						     unsigned int);
-extern unsigned int		rtnl_link_get_weight(struct rtnl_link *);
+extern void	rtnl_link_set_weight(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_weight(struct rtnl_link *);
 
-extern void			rtnl_link_set_ifindex(struct rtnl_link *, int);
-extern int			rtnl_link_get_ifindex(struct rtnl_link *);
+extern void	rtnl_link_set_ifindex(struct rtnl_link *, int);
+extern int	rtnl_link_get_ifindex(struct rtnl_link *);
 
-extern void			rtnl_link_set_family(struct rtnl_link *, int);
-extern int			rtnl_link_get_family(struct rtnl_link *);
+extern void	rtnl_link_set_family(struct rtnl_link *, int);
+extern int	rtnl_link_get_family(struct rtnl_link *);
 
-extern void			rtnl_link_set_arptype(struct rtnl_link *,
-						      unsigned int);
-extern unsigned int		rtnl_link_get_arptype(struct rtnl_link *);
+extern void	rtnl_link_set_arptype(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_arptype(struct rtnl_link *);
 
-extern void			rtnl_link_set_addr(struct rtnl_link *,
-						   struct nl_addr *);
-extern struct nl_addr *		rtnl_link_get_addr(struct rtnl_link *);
+extern void	rtnl_link_set_addr(struct rtnl_link *, struct nl_addr *);
+extern struct nl_addr *rtnl_link_get_addr(struct rtnl_link *);
 
-extern void			rtnl_link_set_broadcast(struct rtnl_link *,
-							struct nl_addr *);
-extern struct nl_addr *		rtnl_link_get_broadcast(struct rtnl_link *);
+extern void	rtnl_link_set_broadcast(struct rtnl_link *, struct nl_addr *);
+extern struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *);
 
-extern void			rtnl_link_set_link(struct rtnl_link *, int);
-extern int			rtnl_link_get_link(struct rtnl_link *);
+extern void	rtnl_link_set_link(struct rtnl_link *, int);
+extern int	rtnl_link_get_link(struct rtnl_link *);
 
-extern void			rtnl_link_set_master(struct rtnl_link *, int);
-extern int			rtnl_link_get_master(struct rtnl_link *);
+extern void	rtnl_link_set_master(struct rtnl_link *, int);
+extern int	rtnl_link_get_master(struct rtnl_link *);
 
-extern void			rtnl_link_set_operstate(struct rtnl_link *,
-							uint8_t);
-extern uint8_t			rtnl_link_get_operstate(struct rtnl_link *);
+extern void	rtnl_link_set_operstate(struct rtnl_link *, uint8_t);
+extern uint8_t	rtnl_link_get_operstate(struct rtnl_link *);
 
-extern void			rtnl_link_set_linkmode(struct rtnl_link *,
-						       uint8_t);
-extern uint8_t			rtnl_link_get_linkmode(struct rtnl_link *);
+extern void	rtnl_link_set_linkmode(struct rtnl_link *, uint8_t);
+extern uint8_t	rtnl_link_get_linkmode(struct rtnl_link *);
 
-extern uint64_t 		rtnl_link_get_stat(struct rtnl_link *, int);
+extern uint64_t rtnl_link_get_stat(struct rtnl_link *, int);
 
-extern int			rtnl_link_set_info_type(struct rtnl_link *,
-							const char *);
-extern char *			rtnl_link_get_info_type(struct rtnl_link *);
+extern int	rtnl_link_set_info_type(struct rtnl_link *, const char *);
+extern char *	rtnl_link_get_info_type(struct rtnl_link *);
 
 #ifdef __cplusplus
 }
diff --git a/include/netlink/route/neighbour.h b/include/netlink/route/neighbour.h
index 078c3f4..7b5ed24 100644
--- a/include/netlink/route/neighbour.h
+++ b/include/netlink/route/neighbour.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_NEIGHBOUR_H_
@@ -22,39 +22,31 @@
 
 struct rtnl_neigh;
 
-/* neighbour object allocation/freeage */
-extern struct rtnl_neigh *	rtnl_neigh_alloc(void);
-extern void			rtnl_neigh_put(struct rtnl_neigh *);
+extern struct rtnl_neigh *rtnl_neigh_alloc(void);
+extern void	rtnl_neigh_put(struct rtnl_neigh *);
 
-/* neighbour cache management */
-extern struct nl_cache *	rtnl_neigh_alloc_cache(struct nl_handle *);
-extern struct rtnl_neigh *	rtnl_neigh_get(struct nl_cache *, int,
+extern int	rtnl_neigh_alloc_cache(struct nl_handle *, struct nl_cache **);
+extern struct rtnl_neigh *rtnl_neigh_get(struct nl_cache *, int,
 					       struct nl_addr *);
 
-/* Neigbour state translations */
-extern char *			rtnl_neigh_state2str(int, char *, size_t);
-extern int			rtnl_neigh_str2state(const char *);
+extern char *	rtnl_neigh_state2str(int, char *, size_t);
+extern int	rtnl_neigh_str2state(const char *);
 
-/* Neighbour flags translations */
-extern char *			rtnl_neigh_flags2str(int, char *, size_t);
-extern int			rtnl_neigh_str2flag(const char *);
+extern char *	rtnl_neigh_flags2str(int, char *, size_t);
+extern int	rtnl_neigh_str2flag(const char *);
 
-/* Neighbour Addition */
-extern int			rtnl_neigh_add(struct nl_handle *,
-					       struct rtnl_neigh *, int);
-extern struct nl_msg *		rtnl_neigh_build_add_request(struct rtnl_neigh *, int);
+extern int	rtnl_neigh_add(struct nl_handle *, struct rtnl_neigh *, int);
+extern int	rtnl_neigh_build_add_request(struct rtnl_neigh *, int,
+					     struct nl_msg **);
 
-/* Neighbour Modification */
-extern int			rtnl_neigh_change(struct nl_handle *,
-						  struct rtnl_neigh *, int);
-extern struct nl_msg *		rtnl_neigh_build_change_request(struct rtnl_neigh *, int);
+extern int	rtnl_neigh_change(struct nl_handle *, struct rtnl_neigh *, int);
+extern int	rtnl_neigh_build_change_request(struct rtnl_neigh *, int,
+						struct nl_msg **);
 
-/* Neighbour Deletion */
-extern int			rtnl_neigh_delete(struct nl_handle *,
-						  struct rtnl_neigh *, int);
-extern struct nl_msg *		rtnl_neigh_build_delete_request(struct rtnl_neigh *, int);
+extern int	rtnl_neigh_delete(struct nl_handle *, struct rtnl_neigh *, int);
+extern int	rtnl_neigh_build_delete_request(struct rtnl_neigh *, int,
+						struct nl_msg **);
 
-/* Access functions */
 extern void			rtnl_neigh_set_state(struct rtnl_neigh *, int);
 extern int			rtnl_neigh_get_state(struct rtnl_neigh *);
 extern void			rtnl_neigh_unset_state(struct rtnl_neigh *,
diff --git a/include/netlink/route/neightbl.h b/include/netlink/route/neightbl.h
index 20285ee..7120053 100644
--- a/include/netlink/route/neightbl.h
+++ b/include/netlink/route/neightbl.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_NEIGHTBL_H_
@@ -25,14 +25,15 @@
 extern struct rtnl_neightbl *rtnl_neightbl_alloc(void);
 extern void rtnl_neightbl_put(struct rtnl_neightbl *);
 extern void rtnl_neightbl_free(struct rtnl_neightbl *);
-extern struct nl_cache *rtnl_neightbl_alloc_cache(struct nl_handle *);
+extern int rtnl_neightbl_alloc_cache(struct nl_handle *, struct nl_cache **);
 extern struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *,
 					       const char *, int);
 extern void rtnl_neightbl_dump(struct rtnl_neightbl *, FILE *,
 			       struct nl_dump_params *);
 
-extern struct nl_msg *rtnl_neightbl_build_change_request(struct rtnl_neightbl *,
-						 struct rtnl_neightbl *);
+extern int rtnl_neightbl_build_change_request(struct rtnl_neightbl *,
+					      struct rtnl_neightbl *,
+					      struct nl_msg **);
 extern int rtnl_neightbl_change(struct nl_handle *, struct rtnl_neightbl *,
 				struct rtnl_neightbl *);
 
diff --git a/include/netlink/route/qdisc.h b/include/netlink/route/qdisc.h
index ee71304..d3bc99b 100644
--- a/include/netlink/route/qdisc.h
+++ b/include/netlink/route/qdisc.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_QDISC_H_
@@ -24,60 +24,46 @@
 
 extern struct nl_object_ops qdisc_obj_ops;
 
-/* General */
-extern struct rtnl_qdisc *	rtnl_qdisc_alloc(void);
-extern void			rtnl_qdisc_put(struct rtnl_qdisc *);
+extern struct rtnl_qdisc *rtnl_qdisc_alloc(void);
+extern void	rtnl_qdisc_put(struct rtnl_qdisc *);
 
-/* Cache Management */
-extern struct nl_cache *	rtnl_qdisc_alloc_cache(struct nl_handle *);
-extern struct rtnl_qdisc *	rtnl_qdisc_get(struct nl_cache *,
-					       int, uint32_t);
-extern struct rtnl_qdisc *	rtnl_qdisc_get_by_parent(struct nl_cache *,
-							 int, uint32_t);
+extern int	rtnl_qdisc_alloc_cache(struct nl_handle *, struct nl_cache **);
+extern struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *, int, uint32_t);
+extern struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *,
+						   int, uint32_t);
 
-/* qdisc addition */
-extern struct nl_msg *	rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int);
-extern int		rtnl_qdisc_add(struct nl_handle *, struct rtnl_qdisc *,
-				       int);
+extern int	rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int,
+					     struct nl_msg **);
+extern int	rtnl_qdisc_add(struct nl_handle *, struct rtnl_qdisc *, int);
 
-/* qdisc modification */
-extern struct nl_msg *	rtnl_qdisc_build_change_request(struct rtnl_qdisc *,
-							struct rtnl_qdisc *);
-extern int		rtnl_qdisc_change(struct nl_handle *,
-					  struct rtnl_qdisc *,
-					  struct rtnl_qdisc *);
+extern int	rtnl_qdisc_build_change_request(struct rtnl_qdisc *,
+						struct rtnl_qdisc *,
+						struct nl_msg **);
+extern int	rtnl_qdisc_change(struct nl_handle *, struct rtnl_qdisc *,
+				  struct rtnl_qdisc *);
 
-/* qdisc deletion */
-extern struct nl_msg *	rtnl_qdisc_build_delete_request(struct rtnl_qdisc *);
-extern int		rtnl_qdisc_delete(struct nl_handle *,
-					  struct rtnl_qdisc *);
+extern int	rtnl_qdisc_build_delete_request(struct rtnl_qdisc *,
+						struct nl_msg **);
+extern int	rtnl_qdisc_delete(struct nl_handle *, struct rtnl_qdisc *);
 
-/* attribute modifications */
-extern void		rtnl_qdisc_set_ifindex(struct rtnl_qdisc *, int);
-extern int		rtnl_qdisc_get_ifindex(struct rtnl_qdisc *);
-extern void		rtnl_qdisc_set_handle(struct rtnl_qdisc *, uint32_t);
-extern uint32_t		rtnl_qdisc_get_handle(struct rtnl_qdisc *);
-extern void		rtnl_qdisc_set_parent(struct rtnl_qdisc *, uint32_t);
-extern uint32_t		rtnl_qdisc_get_parent(struct rtnl_qdisc *);
-extern void		rtnl_qdisc_set_kind(struct rtnl_qdisc *, const char *);
-extern char *		rtnl_qdisc_get_kind(struct rtnl_qdisc *);
-extern uint64_t		rtnl_qdisc_get_stat(struct rtnl_qdisc *,
-					    enum rtnl_tc_stats_id);
+extern void	rtnl_qdisc_set_ifindex(struct rtnl_qdisc *, int);
+extern int	rtnl_qdisc_get_ifindex(struct rtnl_qdisc *);
+extern void	rtnl_qdisc_set_handle(struct rtnl_qdisc *, uint32_t);
+extern uint32_t	rtnl_qdisc_get_handle(struct rtnl_qdisc *);
+extern void	rtnl_qdisc_set_parent(struct rtnl_qdisc *, uint32_t);
+extern uint32_t	rtnl_qdisc_get_parent(struct rtnl_qdisc *);
+extern void	rtnl_qdisc_set_kind(struct rtnl_qdisc *, const char *);
+extern char *	rtnl_qdisc_get_kind(struct rtnl_qdisc *);
+extern uint64_t	rtnl_qdisc_get_stat(struct rtnl_qdisc *, enum rtnl_tc_stats_id);
 
-/* iterators */
-extern void		rtnl_qdisc_foreach_child(struct rtnl_qdisc *,
-						 struct nl_cache *,
-						 void (*cb)(struct nl_object *,
-							    void *),
-						 void *);
+extern void	rtnl_qdisc_foreach_child(struct rtnl_qdisc *, struct nl_cache *,
+					 void (*cb)(struct nl_object *, void *),
+					 void *);
 
-extern void		rtnl_qdisc_foreach_cls(struct rtnl_qdisc *,
-					       struct nl_cache *,
-					       void (*cb)(struct nl_object *,
-							  void *),
-					       void *);
+extern void	rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, struct nl_cache *,
+				       void (*cb)(struct nl_object *, void *),
+				       void *);
 
-/* qdisc specific options */
 extern struct nl_msg *	rtnl_qdisc_get_opts(struct rtnl_qdisc *);
 
 #ifdef __cplusplus
diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h
index 071f2c5..b3a9b9e 100644
--- a/include/netlink/route/route.h
+++ b/include/netlink/route/route.h
@@ -42,84 +42,79 @@
 
 extern struct nl_object_ops route_obj_ops;
 
-/* General */
 extern struct rtnl_route *	rtnl_route_alloc(void);
-extern void			rtnl_route_put(struct rtnl_route *);
-extern struct nl_cache *	rtnl_route_alloc_cache(struct nl_handle *,
-						       int, int);
+extern void	rtnl_route_put(struct rtnl_route *);
+extern int	rtnl_route_alloc_cache(struct nl_handle *, int, int,
+				       struct nl_cache **);
 
-extern void		rtnl_route_get(struct rtnl_route *);
-extern void		rtnl_route_put(struct rtnl_route *);
+extern void	rtnl_route_get(struct rtnl_route *);
+extern void	rtnl_route_put(struct rtnl_route *);
 
-extern struct rtnl_route *rtnl_route_parse(struct nlmsghdr *);
-extern int		rtnl_route_build_msg(struct nl_msg *,
-					     struct rtnl_route *);
+extern int	rtnl_route_parse(struct nlmsghdr *, struct rtnl_route **);
+extern int	rtnl_route_build_msg(struct nl_msg *, struct rtnl_route *);
 
-extern struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *, int);
-extern int rtnl_route_add(struct nl_handle *, struct rtnl_route *, int);
-extern struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *, int);
-extern int rtnl_route_delete(struct nl_handle *, struct rtnl_route *, int);
+extern int	rtnl_route_build_add_request(struct rtnl_route *, int,
+					     struct nl_msg **);
+extern int	rtnl_route_add(struct nl_handle *, struct rtnl_route *, int);
+extern int	rtnl_route_build_del_request(struct rtnl_route *, int,
+					     struct nl_msg **);
+extern int	rtnl_route_delete(struct nl_handle *, struct rtnl_route *, int);
 
-extern void		rtnl_route_set_table(struct rtnl_route *, uint32_t);
-extern uint32_t		rtnl_route_get_table(struct rtnl_route *);
-extern void		rtnl_route_set_scope(struct rtnl_route *, uint8_t);
-extern uint8_t		rtnl_route_get_scope(struct rtnl_route *);
-extern void		rtnl_route_set_tos(struct rtnl_route *, uint8_t);
-extern uint8_t		rtnl_route_get_tos(struct rtnl_route *);
-extern void		rtnl_route_set_protocol(struct rtnl_route *, uint8_t);
-extern uint8_t		rtnl_route_get_protocol(struct rtnl_route *);
-extern void		rtnl_route_set_priority(struct rtnl_route *, uint32_t);
-extern uint32_t		rtnl_route_get_priority(struct rtnl_route *);
-extern int		rtnl_route_set_family(struct rtnl_route *, uint8_t);
-extern uint8_t		rtnl_route_get_family(struct rtnl_route *);
-extern int		rtnl_route_set_type(struct rtnl_route *, uint8_t);
-extern uint8_t		rtnl_route_get_type(struct rtnl_route *);
-extern void		rtnl_route_set_flags(struct rtnl_route *, uint32_t);
-extern void		rtnl_route_unset_flags(struct rtnl_route *, uint32_t);
-extern uint32_t		rtnl_route_get_flags(struct rtnl_route *);
-extern int		rtnl_route_set_metric(struct rtnl_route *, int,
-					      unsigned int);
-extern int		rtnl_route_unset_metric(struct rtnl_route *, int);
-extern int		rtnl_route_get_metric(struct rtnl_route *, int,
-					      uint32_t *);
-extern int		rtnl_route_set_dst(struct rtnl_route *,
-					   struct nl_addr *);
-extern struct nl_addr *	rtnl_route_get_dst(struct rtnl_route *);
-extern int		rtnl_route_set_src(struct rtnl_route *,
-					   struct nl_addr *);
-extern struct nl_addr *	rtnl_route_get_src(struct rtnl_route *);
-extern int		rtnl_route_set_pref_src(struct rtnl_route *,
-						struct nl_addr *);
-extern struct nl_addr *	rtnl_route_get_pref_src(struct rtnl_route *);
-extern void		rtnl_route_set_iif(struct rtnl_route *, int);
-extern int		rtnl_route_get_iif(struct rtnl_route *);
-extern int		rtnl_route_get_src_len(struct rtnl_route *);
+extern void	rtnl_route_set_table(struct rtnl_route *, uint32_t);
+extern uint32_t	rtnl_route_get_table(struct rtnl_route *);
+extern void	rtnl_route_set_scope(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_scope(struct rtnl_route *);
+extern void	rtnl_route_set_tos(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_tos(struct rtnl_route *);
+extern void	rtnl_route_set_protocol(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_protocol(struct rtnl_route *);
+extern void	rtnl_route_set_priority(struct rtnl_route *, uint32_t);
+extern uint32_t	rtnl_route_get_priority(struct rtnl_route *);
+extern int	rtnl_route_set_family(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_family(struct rtnl_route *);
+extern int	rtnl_route_set_type(struct rtnl_route *, uint8_t);
+extern uint8_t	rtnl_route_get_type(struct rtnl_route *);
+extern void	rtnl_route_set_flags(struct rtnl_route *, uint32_t);
+extern void	rtnl_route_unset_flags(struct rtnl_route *, uint32_t);
+extern uint32_t	rtnl_route_get_flags(struct rtnl_route *);
+extern int	rtnl_route_set_metric(struct rtnl_route *, int, unsigned int);
+extern int	rtnl_route_unset_metric(struct rtnl_route *, int);
+extern int	rtnl_route_get_metric(struct rtnl_route *, int, uint32_t *);
+extern int	rtnl_route_set_dst(struct rtnl_route *, struct nl_addr *);
+extern struct nl_addr *rtnl_route_get_dst(struct rtnl_route *);
+extern int	rtnl_route_set_src(struct rtnl_route *, struct nl_addr *);
+extern struct nl_addr *rtnl_route_get_src(struct rtnl_route *);
+extern int	rtnl_route_set_pref_src(struct rtnl_route *, struct nl_addr *);
+extern struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *);
+extern void	rtnl_route_set_iif(struct rtnl_route *, int);
+extern int	rtnl_route_get_iif(struct rtnl_route *);
+extern int	rtnl_route_get_src_len(struct rtnl_route *);
 
-extern void		rtnl_route_add_nexthop(struct rtnl_route *,
-					       struct rtnl_nexthop *);
-extern void		rtnl_route_remove_nexthop(struct rtnl_route *,
-						  struct rtnl_nexthop *);
-extern struct nl_list_head *	rtnl_route_get_nexthops(struct rtnl_route *);
-extern int		rtnl_route_get_nnexthops(struct rtnl_route *);
+extern void	rtnl_route_add_nexthop(struct rtnl_route *,
+				       struct rtnl_nexthop *);
+extern void	rtnl_route_remove_nexthop(struct rtnl_route *,
+					  struct rtnl_nexthop *);
+extern struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *);
+extern int	rtnl_route_get_nnexthops(struct rtnl_route *);
 
-extern void		rtnl_route_foreach_nexthop(struct rtnl_route *r,
+extern void	rtnl_route_foreach_nexthop(struct rtnl_route *r,
                                  void (*cb)(struct rtnl_nexthop *, void *),
                                  void *arg);
 
 extern struct rtnl_nexthop * rtnl_route_nexthop_n(struct rtnl_route *r, int n);
 
-extern int		rtnl_route_guess_scope(struct rtnl_route *);
+extern int	rtnl_route_guess_scope(struct rtnl_route *);
 
-extern char *		rtnl_route_table2str(int, char *, size_t);
-extern int		rtnl_route_str2table(const char *);
-extern int		rtnl_route_read_table_names(const char *);
+extern char *	rtnl_route_table2str(int, char *, size_t);
+extern int	rtnl_route_str2table(const char *);
+extern int	rtnl_route_read_table_names(const char *);
 
-extern char *		rtnl_route_proto2str(int, char *, size_t);
-extern int		rtnl_route_str2proto(const char *);
-extern int		rtnl_route_read_protocol_names(const char *);
+extern char *	rtnl_route_proto2str(int, char *, size_t);
+extern int	rtnl_route_str2proto(const char *);
+extern int	rtnl_route_read_protocol_names(const char *);
 
-extern char *		rtnl_route_metric2str(int, char *, size_t);
-extern int		rtnl_route_str2metric(const char *);
+extern char *	rtnl_route_metric2str(int, char *, size_t);
+extern int	rtnl_route_str2metric(const char *);
 
 #ifdef __cplusplus
 }
diff --git a/include/netlink/route/rule.h b/include/netlink/route/rule.h
index e57ef53..1555185 100644
--- a/include/netlink/route/rule.h
+++ b/include/netlink/route/rule.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_RULE_H_
@@ -27,14 +27,15 @@
 extern struct rtnl_rule *	rtnl_rule_alloc(void);
 extern void			rtnl_rule_put(struct rtnl_rule *);
 
-extern struct nl_cache * rtnl_rule_alloc_cache(struct nl_handle *);
-extern struct nl_cache * rtnl_rule_alloc_cache_by_family(struct nl_handle *,
-							 int);
+extern int	rtnl_rule_alloc_cache(struct nl_handle *, int,
+				      struct nl_cache **);
 extern void rtnl_rule_dump(struct rtnl_rule *, FILE *, struct nl_dump_params *);
 
-extern struct nl_msg * rtnl_rule_build_add_request(struct rtnl_rule *, int);
+extern int	rtnl_rule_build_add_request(struct rtnl_rule *, int,
+					    struct nl_msg **);
 extern int rtnl_rule_add(struct nl_handle *, struct rtnl_rule *, int);
-extern struct nl_msg * rtnl_rule_build_delete_request(struct rtnl_rule *, int);
+extern int	rtnl_rule_build_delete_request(struct rtnl_rule *, int,
+					       struct nl_msg **);
 extern int rtnl_rule_delete(struct nl_handle *, struct rtnl_rule *, int);
 
 
diff --git a/include/netlink/utils.h b/include/netlink/utils.h
index 207e8ec..2b6bcb7 100644
--- a/include/netlink/utils.h
+++ b/include/netlink/utils.h
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #ifndef NETLINK_UTILS_H_
@@ -38,10 +38,6 @@
 
 /** @} */
 
-extern char *	nl_geterror(void);
-extern int	nl_get_errno(void);
-extern void	nl_perror(const char *);
-
 /* unit pretty-printing */
 extern double	nl_cancel_down_bytes(unsigned long long, char **);
 extern double	nl_cancel_down_bits(unsigned long long, char **);
diff --git a/lib/addr.c b/lib/addr.c
index 70e4b1d..258084e 100644
--- a/lib/addr.c
+++ b/lib/addr.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -140,11 +140,11 @@
 	pos = dnet_num(src, &area);
 	if ((pos == 0) || (area > 63) ||
 	    ((*(src + pos) != '.') && (*(src + pos) != ',')))
-		return -EINVAL;
+		return -NLE_INVAL;
 
 	pos = dnet_num(src + pos + 1, &node);
 	if ((pos == 0) || (node > 1023))
-		return -EINVAL;
+		return -NLE_INVAL;
 
 	*(uint16_t *)addrbuf = dn_ntohs((area << 10) | node);
 
@@ -166,10 +166,8 @@
 	struct nl_addr *addr;
 	
 	addr = calloc(1, sizeof(*addr) + maxsize);
-	if (!addr) {
-		nl_errno(ENOMEM);
+	if (!addr)
 		return NULL;
-	}
 
 	addr->a_refcnt = 1;
 	addr->a_maxsize = maxsize;
@@ -221,6 +219,7 @@
  * Allocate abstract address object based on a character string
  * @arg addrstr		Address represented as character string.
  * @arg hint		Address family hint or AF_UNSPEC.
+ * @arg result		Pointer to store resulting address.
  *
  * Regognizes the following address formats:
  *@code
@@ -241,9 +240,9 @@
  * The prefix length may be appened at the end prefixed with a
  * slash, e.g. 10.0.0.0/8.
  *
- * @return Newly allocated abstract address object or NULL.
+ * @return 0 on success or a negative error code.
  */
-struct nl_addr *nl_addr_parse(const char *addrstr, int hint)
+int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
 {
 	int err, copy = 0, len = 0, family = AF_UNSPEC;
 	char *str, *prefix, buf[32];
@@ -251,7 +250,7 @@
 
 	str = strdup(addrstr);
 	if (!str) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
@@ -289,8 +288,7 @@
 				goto prefix;
 
 			default:
-				err = nl_error(EINVAL, "Unsuported address" \
-				    "family for default address");
+				err = -NLE_AF_NOSUPPORT;
 				goto errout;
 		}
 	}
@@ -304,7 +302,7 @@
 			goto prefix;
 		}
 		if (hint == AF_INET) {
-			err = nl_error(EINVAL, "Invalid IPv4 address");
+			err = -NLE_NOADDR;
 			goto errout;
 		}
 	}
@@ -316,7 +314,7 @@
 			goto prefix;
 		}
 		if (hint == AF_INET6) {
-			err = nl_error(EINVAL, "Invalid IPv6 address");
+			err = -NLE_NOADDR;
 			goto errout;
 		}
 	}
@@ -338,7 +336,7 @@
 		}
 
 		if (hint == AF_LLC) {
-			err = nl_error(EINVAL, "Invalid link layer address");
+			err = -NLE_NOADDR;
 			goto errout;
 		}
 	}
@@ -351,7 +349,7 @@
 			goto prefix;
 		}
 		if (hint == AF_DECnet) {
-			err = nl_error(EINVAL, "Invalid DECnet address");
+			err = -NLE_NOADDR;
 			goto errout;
 		}
 	}
@@ -363,7 +361,7 @@
 			long l = strtol(s, &p, 16);
 
 			if (s == p || l > 0xff || i >= sizeof(buf)) {
-				err = -EINVAL;
+				err = -NLE_INVAL;
 				goto errout;
 			}
 
@@ -378,13 +376,13 @@
 		goto prefix;
 	}
 
-	err = nl_error(EINVAL, "Invalid address");
+	err = -NLE_NOADDR;
 	goto errout;
 
 prefix:
 	addr = nl_addr_alloc(len);
 	if (!addr) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
@@ -398,18 +396,19 @@
 		long pl = strtol(++prefix, &p, 0);
 		if (p == prefix) {
 			nl_addr_destroy(addr);
-			err = -EINVAL;
+			err = -NLE_INVAL;
 			goto errout;
 		}
 		nl_addr_set_prefixlen(addr, pl);
 	} else
 		nl_addr_set_prefixlen(addr, len * 8);
 
+	*result = addr;
 	err = 0;
 errout:
 	free(str);
 
-	return err ? NULL : addr;
+	return err;
 }
 
 /**
@@ -634,7 +633,7 @@
 		struct sockaddr_in *sai = (struct sockaddr_in *) sa;
 
 		if (*salen < sizeof(*sai))
-			return -EINVAL;
+			return -NLE_INVAL;
 
 		sai->sin_family = addr->a_family;
 		memcpy(&sai->sin_addr, addr->a_addr, 4);
@@ -646,7 +645,7 @@
 		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
 
 		if (*salen < sizeof(*sa6))
-			return -EINVAL;
+			return -NLE_INVAL;
 
 		sa6->sin6_family = addr->a_family;
 		memcpy(&sa6->sin6_addr, addr->a_addr, 16);
@@ -655,7 +654,7 @@
 		break;
 
 	default:
-		return -EINVAL;
+		return -NLE_INVAL;
 	}
 
 	return 0;
@@ -672,6 +671,7 @@
 /**
  * Call getaddrinfo() for an abstract address object.
  * @arg addr		Abstract address object.
+ * @arg result		Pointer to store resulting address list.
  * 
  * Calls getaddrinfo() for the specified abstract address in AI_NUMERICHOST
  * mode.
@@ -679,13 +679,11 @@
  * @note The caller is responsible for freeing the linked list using the
  *       interface provided by getaddrinfo(3).
  *
- * @return A linked list of addrinfo handles or  NULL with an error message
- *         associated.
+ * @return 0 on success or a negative error code.
  */
-struct addrinfo *nl_addr_info(struct nl_addr *addr)
+int nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
 {
 	int err;
-	struct addrinfo *res;
 	char buf[INET6_ADDRSTRLEN+5];
 	struct addrinfo hint = {
 		.ai_flags = AI_NUMERICHOST,
@@ -694,13 +692,24 @@
 
 	nl_addr2str(addr, buf, sizeof(buf));
 
-	err = getaddrinfo(buf, NULL, &hint, &res);
+	err = getaddrinfo(buf, NULL, &hint, result);
 	if (err != 0) {
-		nl_error(err, gai_strerror(err));
-		return NULL;
+		switch (err) {
+		case EAI_ADDRFAMILY: return -NLE_AF_NOSUPPORT;
+		case EAI_AGAIN: return -NLE_AGAIN;
+		case EAI_BADFLAGS: return -NLE_INVAL;
+		case EAI_FAIL: return -NLE_NOADDR;
+		case EAI_FAMILY: return -NLE_AF_NOSUPPORT;
+		case EAI_MEMORY: return -NLE_NOMEM;
+		case EAI_NODATA: return -NLE_NOADDR;
+		case EAI_NONAME: return -NLE_OBJ_NOTFOUND;
+		case EAI_SERVICE: return -NLE_OPNOTSUPP;
+		case EAI_SOCKTYPE: return -NLE_BAD_SOCK;
+		default: return -NLE_FAILURE;
+		}
 	}
 
-	return res;
+	return 0;
 }
 
 /**
@@ -756,7 +765,7 @@
 int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
 {
 	if (len > addr->a_maxsize)
-		return -ERANGE;
+		return -NLE_RANGE;
 
 	addr->a_len = len;
 	memcpy(addr->a_addr, buf, len);
diff --git a/lib/attr.c b/lib/attr.c
index 875c881..0143be7 100644
--- a/lib/attr.c
+++ b/lib/attr.c
@@ -267,7 +267,7 @@
  *     return 0;
  *
  * nla_put_failure:
- *     return -ENOMEM;
+ *     return -NLE_NOMEM;
  * }
  * @endcode
  *
@@ -544,18 +544,18 @@
 		minlen = nla_attr_minlen[pt->type];
 
 	if (pt->type == NLA_FLAG && nla_len(nla) > 0)
-		return nl_errno(ERANGE);
+		return -NLE_RANGE;
 
 	if (nla_len(nla) < minlen)
-		return nl_errno(ERANGE);
+		return -NLE_RANGE;
 
 	if (pt->maxlen && nla_len(nla) > pt->maxlen)
-		return nl_errno(ERANGE);
+		return -NLE_RANGE;
 
 	if (pt->type == NLA_STRING) {
 		char *data = nla_data(nla);
 		if (data[nla_len(nla) - 1] != '\0')
-			return nl_errno(EINVAL);
+			return -NLE_INVAL;
 	}
 
 	return 0;
@@ -802,10 +802,8 @@
 	
 	tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
 
-	if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size) {
-		nl_errno(ENOBUFS);
+	if ((tlen + msg->nm_nlh->nlmsg_len) > msg->nm_size)
 		return NULL;
-	}
 
 	nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
 	nla->nla_type = attrtype;
@@ -842,7 +840,7 @@
 
 	nla = nla_reserve(msg, attrtype, datalen);
 	if (!nla)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	memcpy(nla_data(nla), data, datalen);
 	NL_DBG(2, "msg %p: Wrote %d bytes at offset +%td for attr %d\n",
diff --git a/lib/cache.c b/lib/cache.c
index e7ba5b9..bc360f0 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -175,10 +175,8 @@
 	struct nl_cache *cache;
 
 	cache = calloc(1, sizeof(*cache));
-	if (!cache) {
-		nl_errno(ENOMEM);
+	if (!cache)
 		return NULL;
-	}
 
 	nl_init_list_head(&cache->c_items);
 	cache->c_ops = ops;
@@ -188,22 +186,43 @@
 	return cache;
 }
 
+int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_handle *sock,
+			    struct nl_cache **result)
+{
+	struct nl_cache *cache;
+	int err;
+	
+	if (!(cache = nl_cache_alloc(ops)))
+		return -NLE_NOMEM;
+
+	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
+		nl_cache_free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
+}
+
 /**
  * Allocate an empty cache based on type name
  * @arg kind		Name of cache type
  * @return A newly allocated and initialized cache.
  */
-struct nl_cache *nl_cache_alloc_name(const char *kind)
+int nl_cache_alloc_name(const char *kind, struct nl_cache **result)
 {
 	struct nl_cache_ops *ops;
+	struct nl_cache *cache;
 
 	ops = nl_cache_ops_lookup(kind);
-	if (!ops) {
-		nl_error(ENOENT, "Unable to lookup cache \"%s\"", kind);
-		return NULL;
-	}
+	if (!ops)
+		return -NLE_NOCACHE;
 
-	return nl_cache_alloc(ops);
+	if (!(cache = nl_cache_alloc(ops)))
+		return -NLE_NOMEM;
+
+	*result = cache;
+	return 0;
 }
 
 /**
@@ -307,12 +326,12 @@
 	struct nl_object *new;
 
 	if (cache->c_ops->co_obj_ops != obj->ce_ops)
-		return nl_error(EINVAL, "Object mismatches cache type");
+		return -NLE_OBJ_MISMATCH;
 
 	if (!nl_list_empty(&obj->ce_list)) {
 		new = nl_object_clone(obj);
 		if (!new)
-			return nl_errno(ENOMEM);
+			return -NLE_NOMEM;
 	} else {
 		nl_object_get(obj);
 		new = obj;
@@ -334,7 +353,7 @@
 int nl_cache_move(struct nl_cache *cache, struct nl_object *obj)
 {
 	if (cache->c_ops->co_obj_ops != obj->ce_ops)
-		return nl_error(EINVAL, "Object mismatches cache type");
+		return -NLE_OBJ_MISMATCH;
 
 	NL_DBG(3, "Moving object %p to cache %p\n", obj, cache);
 	
@@ -423,7 +442,7 @@
 	          cache, nl_cache_name(cache));
 
 	if (cache->c_ops->co_request_update == NULL)
-		return nl_error(EOPNOTSUPP, "Operation not supported");
+		return -NLE_OPNOTSUPP;
 
 	return cache->c_ops->co_request_update(cache, handle);
 }
@@ -457,7 +476,7 @@
 
 	cb = nl_cb_clone(handle->h_cb);
 	if (cb == NULL)
-		return nl_get_errno();
+		return -NLE_NOMEM;
 
 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
 
@@ -465,7 +484,7 @@
 	if (err < 0)
 		NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
 		       "%d: %s", cache, nl_cache_name(cache),
-		       err, nl_geterror());
+		       err, nl_geterror(err));
 
 	nl_cb_put(cb);
 
@@ -542,14 +561,14 @@
 	int i;
 
 	if (ops->co_obj_ops != obj->ce_ops)
-		return nl_error(EINVAL, "Object mismatches cache type");
+		return -NLE_OBJ_MISMATCH;
 
 	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
 		if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype)
 			return cache_include(cache, obj, &ops->co_msgtypes[i],
 					     change_cb);
 
-	return nl_errno(EINVAL);
+	return -NLE_MSGTYPE_NOSUPPORT;
 }
 
 static int resync_cb(struct nl_object *c, struct nl_parser_param *p)
@@ -610,23 +629,19 @@
 {
 	int i, err;
 
-	if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize)) {
-		err = nl_error(EINVAL, "netlink message too short to be "
-				       "of kind %s", ops->co_name);
-		goto errout;
-	}
+	if (!nlmsg_valid_hdr(nlh, ops->co_hdrsize))
+		return -NLE_MSG_TOOSHORT;
 
 	for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) {
 		if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type) {
 			err = ops->co_msg_parser(ops, who, nlh, params);
-			if (err != -ENOENT)
+			if (err != -NLE_OPNOTSUPP)
 				goto errout;
 		}
 	}
 
 
-	err = nl_error(EINVAL, "Unsupported netlink message type %d",
-		       nlh->nlmsg_type);
+	err = -NLE_MSGTYPE_NOSUPPORT;
 errout:
 	return err;
 }
diff --git a/lib/cache_mngr.c b/lib/cache_mngr.c
index dffba90..5909795 100644
--- a/lib/cache_mngr.c
+++ b/lib/cache_mngr.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -146,17 +146,18 @@
  *
  * @return Newly allocated cache manager or NULL on failure.
  */
-struct nl_cache_mngr *nl_cache_mngr_alloc(struct nl_handle *handle,
-					  int protocol, int flags)
+int nl_cache_mngr_alloc(struct nl_handle *handle, int protocol, int flags,
+			struct nl_cache_mngr **result)
 {
 	struct nl_cache_mngr *mngr;
+	int err = -NLE_NOMEM;
 
 	if (handle == NULL)
 		BUG();
 
 	mngr = calloc(1, sizeof(*mngr));
 	if (!mngr)
-		goto enomem;
+		goto errout;
 
 	mngr->cm_handle = handle;
 	mngr->cm_nassocs = 32;
@@ -165,8 +166,7 @@
 	mngr->cm_assocs = calloc(mngr->cm_nassocs,
 				 sizeof(struct nl_cache_assoc));
 	if (!mngr->cm_assocs)
-		goto enomem;
-
+		goto errout;
 
 	nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM,
 			    event_input, mngr);
@@ -174,22 +174,21 @@
 	/* Required to receive async event notifications */
 	nl_disable_sequence_check(mngr->cm_handle);
 
-	if (nl_connect(mngr->cm_handle, protocol) < 0)
+	if ((err = nl_connect(mngr->cm_handle, protocol) < 0))
 		goto errout;
 
-	if (nl_socket_set_nonblocking(mngr->cm_handle) < 0)
+	if ((err = nl_socket_set_nonblocking(mngr->cm_handle) < 0))
 		goto errout;
 
 	NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
 	       mngr, protocol, mngr->cm_nassocs);
 
-	return mngr;
+	*result = mngr;
+	return 0;
 
-enomem:
-	nl_errno(ENOMEM);
 errout:
 	nl_cache_mngr_free(mngr);
-	return NULL;
+	return err;
 }
 
 /**
@@ -197,6 +196,7 @@
  * @arg mngr		Cache manager.
  * @arg name		Name of cache to keep track of
  * @arg cb		Function to be called upon changes.
+ * @arg result		Pointer to store added cache.
  *
  * Allocates a new cache of the specified type and adds it to the manager.
  * The operation will trigger a full dump request from the kernel to
@@ -204,10 +204,10 @@
  * to the notification group of the cache to keep track of any further
  * changes.
  *
- * @return The newly allocated cache or NULL on failure.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache *nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
-				   change_func_t cb)
+int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
+		      change_func_t cb, struct nl_cache **result)
 {
 	struct nl_cache_ops *ops;
 	struct nl_cache *cache;
@@ -215,28 +215,19 @@
 	int err, i;
 
 	ops = nl_cache_ops_lookup(name);
-	if (!ops) {
-		nl_error(ENOENT, "Unknown cache type");
-		return NULL;
-	}
+	if (!ops)
+		return -NLE_NOCACHE;
 
-	if (ops->co_protocol != mngr->cm_protocol) {
-		nl_error(EINVAL, "Netlink protocol mismatch");
-		return NULL;
-	}
+	if (ops->co_protocol != mngr->cm_protocol)
+		return -NLE_PROTO_MISMATCH;
 
-	if (ops->co_groups == NULL) {
-		nl_error(EOPNOTSUPP, NULL);
-		return NULL;
-	}
+	if (ops->co_groups == NULL)
+		return -NLE_OPNOTSUPP;
 
-	for (i = 0; i < mngr->cm_nassocs; i++) {
+	for (i = 0; i < mngr->cm_nassocs; i++)
 		if (mngr->cm_assocs[i].ca_cache &&
-		    mngr->cm_assocs[i].ca_cache->c_ops == ops) {
-			nl_error(EEXIST, "Cache of this type already managed");
-			return NULL;
-		}
-	}
+		    mngr->cm_assocs[i].ca_cache->c_ops == ops)
+			return -NLE_EXIST;
 
 retry:
 	for (i = 0; i < mngr->cm_nassocs; i++)
@@ -248,10 +239,9 @@
 		mngr->cm_assocs = realloc(mngr->cm_assocs,
 					  mngr->cm_nassocs *
 					  sizeof(struct nl_cache_assoc));
-		if (mngr->cm_assocs == NULL) {
-			nl_errno(ENOMEM);
-			return NULL;
-		} else {
+		if (mngr->cm_assocs == NULL)
+			return -NLE_NOMEM;
+		else {
 			NL_DBG(1, "Increased capacity of cache manager %p " \
 				  "to %d\n", mngr, mngr->cm_nassocs);
 			goto retry;
@@ -259,10 +249,8 @@
 	}
 
 	cache = nl_cache_alloc(ops);
-	if (!cache) {
-		nl_errno(ENOMEM);
-		return NULL;
-	}
+	if (!cache)
+		return -NLE_NOMEM;
 
 	for (grp = ops->co_groups; grp->ag_group; grp++) {
 		err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
@@ -283,7 +271,8 @@
 	NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
 	       cache, nl_cache_name(cache), mngr);
 
-	return cache;
+	*result = cache;
+	return 0;
 
 errout_drop_membership:
 	for (grp = ops->co_groups; grp->ag_group; grp++)
@@ -291,7 +280,7 @@
 errout_free_cache:
 	nl_cache_free(cache);
 
-	return NULL;
+	return err;
 }
 
 /**
@@ -334,7 +323,7 @@
 	ret = poll(&fds, 1, timeout);
 	NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
 	if (ret < 0)
-		return nl_errno(errno);
+		return -nl_syserr2nlerr(errno);
 
 	if (ret == 0)
 		return 0;
diff --git a/lib/cache_mngt.c b/lib/cache_mngt.c
index 137d6c9..4fede92 100644
--- a/lib/cache_mngt.c
+++ b/lib/cache_mngt.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -129,15 +129,12 @@
  */
 int nl_cache_mngt_register(struct nl_cache_ops *ops)
 {
-	if (!ops->co_name)
-		return nl_error(EINVAL, "No cache name specified");
-
-	if (!ops->co_obj_ops)
-		return nl_error(EINVAL, "No obj cache ops specified");
+	if (!ops->co_name || !ops->co_obj_ops)
+		return -NLE_INVAL;
 
 	if (nl_cache_ops_lookup(ops->co_name))
-		return nl_error(EEXIST, "Cache operations already exist");
-	    
+		return -NLE_EXIST;
+
 	ops->co_next = cache_ops;
 	cache_ops = ops;
 
@@ -166,7 +163,7 @@
 			break;
 
 	if (!t)
-		return nl_error(ENOENT, "No such cache operations");
+		return -NLE_NOCACHE;
 
 	NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
 
diff --git a/lib/data.c b/lib/data.c
index 7b81ceb..7bde598 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -56,7 +56,6 @@
 
 	return data;
 errout:
-	nl_errno(ENOMEM);
 	return NULL;
 }
 
@@ -105,7 +104,7 @@
 	if (size > 0) {
 		data->d_data = realloc(data->d_data, data->d_size + size);
 		if (!data->d_data)
-			return nl_errno(ENOMEM);
+			return -NLE_NOMEM;
 
 		if (buf)
 			memcpy(data->d_data + data->d_size, buf, size);
diff --git a/lib/error.c b/lib/error.c
new file mode 100644
index 0000000..1ef7e5e
--- /dev/null
+++ b/lib/error.c
@@ -0,0 +1,106 @@
+/*
+ * lib/error.c		Error Handling
+ *
+ *	This library is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU Lesser General Public
+ *	License as published by the Free Software Foundation version 2.1
+ *	of the License.
+ *
+ * Copyright (c) 2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-local.h>
+#include <netlink/netlink.h>
+
+static const char *errmsg[NLE_MAX+1] = {
+[NLE_SUCCESS]		= "Success",
+[NLE_FAILURE]		= "Unspecific failure",
+[NLE_INTR]		= "Interrupted system call",
+[NLE_BAD_SOCK]		= "Bad socket",
+[NLE_AGAIN]		= "Try again",
+[NLE_NOMEM]		= "Out of memory",
+[NLE_EXIST]		= "Object exists",
+[NLE_INVAL]		= "Invalid input data or parameter",
+[NLE_RANGE]		= "Input data out of range",
+[NLE_MSGSIZE]		= "Message size not sufficient",
+[NLE_OPNOTSUPP]		= "Operation not supported",
+[NLE_AF_NOSUPPORT]	= "Address family not supported",
+[NLE_OBJ_NOTFOUND]	= "Object not found",
+[NLE_NOATTR]		= "Attribute not available",
+[NLE_MISSING_ATTR]	= "Missing attribute",
+[NLE_AF_MISMATCH]	= "Address family mismatch",
+[NLE_SEQ_MISMATCH]	= "Message sequence number mismatch",
+[NLE_MSG_OVERFLOW]	= "Kernel reported message overflow",
+[NLE_MSG_TRUNC]		= "Kernel reported truncated message",
+[NLE_NOADDR]		= "Invalid address for specified address family",
+[NLE_SRCRT_NOSUPPORT]	= "Source based routing not supported",
+[NLE_MSG_TOOSHORT]	= "Netlink message is too short",
+[NLE_MSGTYPE_NOSUPPORT]	= "Netlink message type is not supported",
+[NLE_OBJ_MISMATCH]	= "Object type does not match cache",
+[NLE_NOCACHE]		= "Unknown or invalid cache type",
+[NLE_BUSY]		= "Object busy",
+[NLE_PROTO_MISMATCH]	= "Protocol mismatch",
+[NLE_NOACCESS]		= "No Access",
+[NLE_PERM]		= "Operation not permitted",
+};
+
+/**
+ * Return error message for an error code
+ * @return error message
+ */
+const char *nl_geterror(int error)
+{
+	error = abs(error);
+
+	if (error > NLE_MAX)
+		error = NLE_FAILURE;
+
+	return errmsg[error];
+}
+
+/**
+ * Print a libnl error message
+ * @arg s		error message prefix
+ *
+ * Prints the error message of the call that failed last.
+ *
+ * If s is not NULL and *s is not a null byte the argument
+ * string is printed, followed by a colon and a blank. Then
+ * the error message and a new-line.
+ */
+void nl_perror(int error, const char *s)
+{
+	if (s && *s)
+		fprintf(stderr, "%s: %s\n", s, nl_geterror(error));
+	else
+		fprintf(stderr, "%s\n", nl_geterror(error));
+}
+
+int nl_syserr2nlerr(int error)
+{
+	error = abs(error);
+
+	switch (error) {
+	case EBADF:		return NLE_BAD_SOCK;
+	case EADDRINUSE:	return NLE_EXIST;
+	case EADDRNOTAVAIL:	return NLE_NOADDR;
+	case ENOENT:		return NLE_OBJ_NOTFOUND;
+	case EINTR:		return NLE_INTR;
+	case EAGAIN:		return NLE_AGAIN;
+	case ENOTSOCK:		return NLE_BAD_SOCK;
+	case ENOPROTOOPT:	return NLE_INVAL;
+	case EFAULT:		return NLE_INVAL;
+	case EACCES:		return NLE_NOACCESS;
+	case EINVAL:		return NLE_INVAL;
+	case ENOBUFS:		return NLE_NOMEM;
+	case ENOMEM:		return NLE_NOMEM;
+	case EAFNOSUPPORT:	return NLE_AF_NOSUPPORT;
+	case EPROTONOSUPPORT:	return NLE_PROTO_MISMATCH;
+	case EOPNOTSUPP:	return NLE_OPNOTSUPP;
+	case EPERM:		return NLE_PERM;
+	default:		return NLE_FAILURE;
+	}
+}
+
+/** @} */
+
diff --git a/lib/fib_lookup/lookup.c b/lib/fib_lookup/lookup.c
index 5766035..b769246 100644
--- a/lib/fib_lookup/lookup.c
+++ b/lib/fib_lookup/lookup.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -63,7 +63,7 @@
 	if (src->fr_req)
 		if (!(dst->fr_req = (struct flnl_request *)
 				nl_object_clone(OBJ_CAST(src->fr_req))))
-			return nl_get_errno();
+			return -NLE_NOMEM;
 	
 	return 0;
 }
@@ -74,7 +74,7 @@
 	struct flnl_result *res;
 	struct fib_result_nl *fr;
 	struct nl_addr *addr;
-	int err = -EINVAL;
+	int err = -NLE_INVAL;
 
 	res = flnl_result_alloc();
 	if (!res)
@@ -209,7 +209,8 @@
  * @note Not all attributes can be changed, see
  *       \ref link_changeable "Changeable Attributes" for more details.
  */
-struct nl_msg *flnl_lookup_build_request(struct flnl_request *req, int flags)
+int flnl_lookup_build_request(struct flnl_request *req, int flags,
+			      struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct nl_addr *addr;
@@ -228,25 +229,24 @@
 	fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
 
 	addr = flnl_request_get_addr(req);
-	if (!addr) {
-		nl_error(EINVAL, "Request must specify the address");
-		return NULL;
-	}
+	if (!addr)
+		return -NLE_MISSING_ATTR;
 
 	fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr);
 
 	msg = nlmsg_alloc_simple(0, flags);
 	if (!msg)
-		goto errout;
+		return -NLE_NOMEM;
 
 	if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0)
 		goto errout;
 
-	return msg;
+	*result = msg;
+	return 0;
 
 errout:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
 /**
@@ -266,9 +266,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = flnl_lookup_build_request(req, 0);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(handle, msg);
 	nlmsg_free(msg);
diff --git a/lib/fib_lookup/request.c b/lib/fib_lookup/request.c
index 8b00224..ffcf8f5 100644
--- a/lib/fib_lookup/request.c
+++ b/lib/fib_lookup/request.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -48,11 +48,9 @@
 
 	if (src->lr_addr)
 		if (!(dst->lr_addr = nl_addr_clone(src->lr_addr)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static int request_compare(struct nl_object *_a, struct nl_object *_b,
@@ -152,7 +150,7 @@
 int flnl_request_set_addr(struct flnl_request *req, struct nl_addr *addr)
 {
 	if (addr->a_family != AF_INET)
-		return nl_error(EINVAL, "Address must be an IPv4 address");
+		return -NLE_AF_NOSUPPORT;
 
 	if (req->lr_addr)
 		nl_addr_put(req->lr_addr);
diff --git a/lib/genl/ctrl.c b/lib/genl/ctrl.c
index 9948a57..fc08e14 100644
--- a/lib/genl/ctrl.c
+++ b/lib/genl/ctrl.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -61,17 +61,17 @@
 
 	family = genl_family_alloc();
 	if (family == NULL) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
 	if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
-		err = nl_error(EINVAL, "Missing family name TLV");
+		err = -NLE_MISSING_ATTR;
 		goto errout;
 	}
 
 	if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
-		err = nl_error(EINVAL, "Missing family id TLV");
+		err = -NLE_MISSING_ATTR;
 		goto errout;
 	}
 
@@ -111,7 +111,7 @@
 				goto errout;
 
 			if (tb[CTRL_ATTR_OP_ID] == NULL) {
-				err = nl_errno(EINVAL);
+				err = -NLE_MISSING_ATTR;
 				goto errout;
 			}
 			
@@ -143,20 +143,9 @@
  * @{
  */
 
-struct nl_cache *genl_ctrl_alloc_cache(struct nl_handle *handle)
+int genl_ctrl_alloc_cache(struct nl_handle *sock, struct nl_cache **result)
 {
-	struct nl_cache * cache;
-	
-	cache = nl_cache_alloc(&genl_ctrl_ops);
-	if (cache == NULL)
-		return NULL;
-	
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		nl_cache_free(cache);
-		return NULL;
-	}
-
-	return cache;
+	return nl_cache_alloc_and_fill(&genl_ctrl_ops, sock, result);
 }
 
 /**
@@ -241,13 +230,12 @@
 	struct genl_family *family;
 	int err;
 
-	cache = genl_ctrl_alloc_cache(handle);
-	if (cache == NULL)
-		return nl_get_errno();
+	if ((err = genl_ctrl_alloc_cache(handle, &cache)) < 0)
+		return err;
 
 	family = genl_ctrl_search_by_name(cache, name);
 	if (family == NULL) {
-		err = nl_error(ENOENT, "Generic Netlink Family not found");
+		err = -NLE_OBJ_NOTFOUND;
 		goto errout;
 	}
 
diff --git a/lib/genl/family.c b/lib/genl/family.c
index e05b52c..ec52b73 100644
--- a/lib/genl/family.c
+++ b/lib/genl/family.c
@@ -250,7 +250,7 @@
 
 	op = calloc(1, sizeof(*op));
 	if (op == NULL)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	op->o_id = id;
 	op->o_flags = flags;
diff --git a/lib/genl/genl.c b/lib/genl/genl.c
index 04cfebf..cee7efd 100644
--- a/lib/genl/genl.c
+++ b/lib/genl/genl.c
@@ -164,7 +164,7 @@
 	struct genlmsghdr *ghdr;
 
 	if (!genlmsg_valid_hdr(nlh, hdrlen))
-		return nl_errno(EINVAL);
+		return -NLE_MSG_TOOSHORT;
 
 	ghdr = nlmsg_data(nlh);
 	return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
@@ -177,7 +177,7 @@
 	struct genlmsghdr *ghdr;
 
 	if (!genlmsg_valid_hdr(nlh, hdrlen))
-		return nl_errno(EINVAL);
+		return -NLE_MSG_TOOSHORT;
 
 	ghdr = nlmsg_data(nlh);
 	return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
diff --git a/lib/genl/mngt.c b/lib/genl/mngt.c
index d737697..7644352 100644
--- a/lib/genl/mngt.c
+++ b/lib/genl/mngt.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -108,12 +108,12 @@
 			goto found;
 	}
 
-	err = nl_errno(ENOENT);
+	err = -NLE_MSGTYPE_NOSUPPORT;
 	goto errout;
 
 found:
 	if (cmd->c_msg_parser == NULL)
-		err = nl_error(EOPNOTSUPP, "No message parser found.");
+		err = -NLE_OPNOTSUPP;
 	else {
 		struct nlattr *tb[cmd->c_maxattr + 1];
 		struct genl_info info = {
@@ -174,22 +174,17 @@
 	int err;
 
 	if (ops->co_protocol != NETLINK_GENERIC) {
-		err = nl_error(EINVAL, "cache operations not for protocol " \
-			       "NETLINK_GENERIC (protocol=%s)",
-			       ops->co_protocol);
+		err = -NLE_PROTO_MISMATCH;
 		goto errout;
 	}
 
 	if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
-		err = nl_error(EINVAL, "co_hdrsize too short, probably " \
-			       "not including genlmsghdr, minsize=%d",
-			       GENL_HDRSIZE(0));
+		err = -NLE_INVAL;
 		goto errout;
 	}
 
 	if (ops->co_genl == NULL) {
-		err = nl_error(EINVAL, "co_genl is NULL, must provide " \
-			       "valid genl operations");
+		err = -NLE_INVAL;
 		goto errout;
 	}
 
@@ -236,8 +231,7 @@
 		return 0;
 	}
 
-	return nl_error(ENOENT, "Unable to find generic netlink family \"%s\"",
-			ops->o_name);
+	return -NLE_OBJ_NOTFOUND;
 }
 
 int genl_ops_resolve(struct nl_handle *handle, struct genl_ops *ops)
@@ -245,11 +239,8 @@
 	struct nl_cache *ctrl;
 	int err;
 
-	ctrl = genl_ctrl_alloc_cache(handle);
-	if (ctrl == NULL) {
-		err = nl_get_errno();
+	if ((err = genl_ctrl_alloc_cache(handle, &ctrl)) < 0)
 		goto errout;
-	}
 
 	err = __genl_ops_resolve(ctrl, ops);
 
@@ -264,11 +255,8 @@
 	struct genl_ops *ops;
 	int err = 0;
 
-	ctrl = genl_ctrl_alloc_cache(handle);
-	if (ctrl == NULL) {
-		err = nl_get_errno();
+	if ((err = genl_ctrl_alloc_cache(handle, &ctrl)) < 0)
 		goto errout;
-	}
 
 	nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
 		err = __genl_ops_resolve(ctrl, ops);
diff --git a/lib/handlers.c b/lib/handlers.c
index 1797e4f..480df59 100644
--- a/lib/handlers.c
+++ b/lib/handlers.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -140,7 +140,7 @@
 	print_header_content(ofd, &e->msg);
 	fprintf(ofd, "\n");
 
-	return e->error;
+	return -nl_syserr2nlerr(e->error);
 }
 
 static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
@@ -261,10 +261,8 @@
 		return NULL;
 
 	cb = calloc(1, sizeof(*cb));
-	if (!cb) {
-		nl_errno(ENOMEM);
+	if (!cb)
 		return NULL;
-	}
 
 	cb->cb_refcnt = 1;
 
@@ -338,10 +336,10 @@
 	      nl_recvmsg_msg_cb_t func, void *arg)
 {
 	if (type < 0 || type > NL_CB_TYPE_MAX)
-		return nl_error(ERANGE, "Callback type out of range");
+		return -NLE_RANGE;
 
 	if (kind < 0 || kind > NL_CB_KIND_MAX)
-		return nl_error(ERANGE, "Callback kind out of range");
+		return -NLE_RANGE;
 
 	if (kind == NL_CB_CUSTOM) {
 		cb->cb_set[type] = func;
@@ -388,7 +386,7 @@
 	      nl_recvmsg_err_cb_t func, void *arg)
 {
 	if (kind < 0 || kind > NL_CB_KIND_MAX)
-		return nl_error(ERANGE, "Callback kind out of range");
+		return -NLE_RANGE;
 
 	if (kind == NL_CB_CUSTOM) {
 		cb->cb_err = func;
diff --git a/lib/msg.c b/lib/msg.c
index c5cb7b4..ad6f5a1 100644
--- a/lib/msg.c
+++ b/lib/msg.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -320,7 +320,7 @@
 		int maxtype, struct nla_policy *policy)
 {
 	if (!nlmsg_valid_hdr(nlh, hdrlen))
-		return nl_errno(EINVAL);
+		return -NLE_MSG_TOOSHORT;
 
 	return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
 			 nlmsg_attrlen(nlh, hdrlen), policy);
@@ -351,7 +351,7 @@
 		   struct nla_policy *policy)
 {
 	if (!nlmsg_valid_hdr(nlh, hdrlen))
-		return nl_errno(EINVAL);
+		return -NLE_MSG_TOOSHORT;
 
 	return nla_validate(nlmsg_attrdata(nlh, hdrlen),
 			    nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
@@ -387,7 +387,6 @@
 	return nm;
 errout:
 	free(nm);
-	nl_errno(ENOMEM);
 	return NULL;
 }
 
@@ -519,10 +518,8 @@
 
 	tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
 
-	if ((tlen + nlmsg_len) > n->nm_size) {
-		nl_errno(ENOBUFS);
+	if ((tlen + nlmsg_len) > n->nm_size)
 		return NULL;
-	}
 
 	buf += nlmsg_len;
 	n->nm_nlh->nlmsg_len += tlen;
@@ -554,7 +551,7 @@
 
 	tmp = nlmsg_reserve(n, len, pad);
 	if (tmp == NULL)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	memcpy(tmp, data, len);
 	NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
@@ -581,11 +578,11 @@
 	void *tmp;
 
 	if (newlen <= n->nm_size)
-		return nl_errno(EINVAL);
+		return -NLE_INVAL;
 
 	tmp = realloc(n->nm_nlh, newlen);
 	if (tmp == NULL)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	n->nm_nlh = tmp;
 	n->nm_size = newlen;
@@ -823,8 +820,7 @@
 	ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
 				     nlmsg_hdr(msg)->nlmsg_type);
 	if (ops == NULL)
-		return nl_error(ENOENT, "Unknown message type %d",
-				nlmsg_hdr(msg)->nlmsg_type);
+		return -NLE_MSGTYPE_NOSUPPORT;
 	p.pp_arg = &x;
 
 	return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
diff --git a/lib/netfilter/ct.c b/lib/netfilter/ct.c
index e16a606..de561d2 100644
--- a/lib/netfilter/ct.c
+++ b/lib/netfilter/ct.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  * Copyright (c= 2008 Patrick McHardy <kaber@trash.net>
@@ -152,7 +152,7 @@
 	return 0;
 
 errout_errno:
-	return nl_get_errno();
+	err = -NLE_NOMEM;
 errout:
 	return err;
 }
@@ -287,7 +287,7 @@
 	}
 }
 
-struct nfnl_ct *nfnlmsg_ct_parse(struct nlmsghdr *nlh)
+int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
 {
 	struct nfnl_ct *ct;
 	struct nlattr *tb[CTA_MAX+1];
@@ -295,7 +295,7 @@
 
 	ct = nfnl_ct_alloc();
 	if (!ct)
-		return NULL;
+		return -NLE_NOMEM;
 
 	ct->ce_msgtype = nlh->nlmsg_type;
 
@@ -346,11 +346,12 @@
 			goto errout;
 	}
 
-	return ct;
+	*result = ct;
+	return 0;
 
 errout:
 	nfnl_ct_put(ct);
-	return NULL;
+	return err;
 }
 
 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
@@ -359,9 +360,8 @@
 	struct nfnl_ct *ct;
 	int err;
 
-	ct = nfnlmsg_ct_parse(nlh);
-	if (ct == NULL)
-		goto errout_errno;
+	if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
+		goto errout;
 
 	err = pp->pp_cb((struct nl_object *) ct, pp);
 	if (err < 0)
@@ -372,10 +372,6 @@
 errout:
 	nfnl_ct_put(ct);
 	return err;
-
-errout_errno:
-	err = nl_get_errno();
-	goto errout;
 }
 
 int nfnl_ct_dump_request(struct nl_handle *h)
@@ -453,31 +449,35 @@
 	return 0;
 
 nla_put_failure:
-	return -1;
+	return -NLE_MSGSIZE;
 }
 
-static struct nl_msg *nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags)
+static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
+				 struct nl_msg **result)
 {
 	struct nl_msg *msg;
+	int err;
 
 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
 				   nfnl_ct_get_family(ct), 0);
 	if (msg == NULL)
-		return NULL;
+		return -NLE_NOMEM;
 
-	if (nfnl_ct_build_tuple(msg, ct, 0) < 0)
+	if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
 		goto err_out;
 
-	return msg;
+	*result = msg;
+	return 0;
 
 err_out:
 	nlmsg_free(msg);
-	return NULL;
+	return err;
 }
 
-struct nl_msg *nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags)
+int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
+			      struct nl_msg **result)
 {
-	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags);
+	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
 }
 
 int nfnl_ct_add(struct nl_handle *h, const struct nfnl_ct *ct, int flags)
@@ -485,9 +485,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = nfnl_ct_build_add_request(ct, flags);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(h, msg);
 	nlmsg_free(msg);
@@ -497,9 +496,10 @@
 	return nl_wait_for_ack(h);
 }
 
-struct nl_msg *nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags)
+int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
+				 struct nl_msg **result)
 {
-	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags);
+	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
 }
 
 int nfnl_ct_del(struct nl_handle *h, const struct nfnl_ct *ct, int flags)
@@ -507,9 +507,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = nfnl_ct_build_delete_request(ct, flags);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(h, msg);
 	nlmsg_free(msg);
@@ -519,9 +518,10 @@
 	return nl_wait_for_ack(h);
 }
 
-struct nl_msg *nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags)
+int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
+				struct nl_msg **result)
 {
-	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags);
+	return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
 }
 
 int nfnl_ct_query(struct nl_handle *h, const struct nfnl_ct *ct, int flags)
@@ -529,9 +529,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = nfnl_ct_build_query_request(ct, flags);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(h, msg);
 	nlmsg_free(msg);
@@ -549,28 +548,16 @@
 /**
  * Build a conntrack cache holding all conntrack currently in the kernel
  * @arg handle		netlink handle
+ * @arg result		Pointer to store resulting cache.
  *
  * Allocates a new cache, initializes it properly and updates it to
  * contain all conntracks currently in the kernel.
  *
- * @note The caller is responsible for destroying and freeing the
- *       cache after using it.
- * @return The cache or NULL if an error has occured.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache *nfnl_ct_alloc_cache(struct nl_handle *handle)
+int nfnl_ct_alloc_cache(struct nl_handle *sock, struct nl_cache **result)
 {
-	struct nl_cache *cache;
-
-	cache = nl_cache_alloc(&nfnl_ct_ops);
-	if (!cache)
-		return NULL;
-
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		free(cache);
-		return NULL;
-	}
-
-	return cache;
+	return nl_cache_alloc_and_fill(&nfnl_ct_ops, sock, result);
 }
 
 /** @} */
diff --git a/lib/netfilter/ct_obj.c b/lib/netfilter/ct_obj.c
index 96e5db6..1625efc 100644
--- a/lib/netfilter/ct_obj.c
+++ b/lib/netfilter/ct_obj.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  */
@@ -75,34 +75,32 @@
 	if (src->ct_orig.src) {
 		addr = nl_addr_clone(src->ct_orig.src);
 		if (!addr)
-			goto errout;
+			return -NLE_NOMEM;
 		dst->ct_orig.src = addr;
 	}
 
 	if (src->ct_orig.dst) {
 		addr = nl_addr_clone(src->ct_orig.dst);
 		if (!addr)
-			goto errout;
+			return -NLE_NOMEM;
 		dst->ct_orig.dst = addr;
 	}
 
 	if (src->ct_repl.src) {
 		addr = nl_addr_clone(src->ct_repl.src);
 		if (!addr)
-			goto errout;
+			return -NLE_NOMEM;
 		dst->ct_repl.src = addr;
 	}
 
 	if (src->ct_repl.dst) {
 		addr = nl_addr_clone(src->ct_repl.dst);
 		if (!addr)
-			goto errout;
+			return -NLE_NOMEM;
 		dst->ct_repl.dst = addr;
 	}
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static void ct_dump_dir(struct nfnl_ct *ct, int repl,
@@ -458,7 +456,7 @@
 {
 	if (ct->ce_mask & CT_ATTR_FAMILY) {
 		if (addr->a_family != ct->ct_family)
-			return nl_error(EINVAL, "Address family mismatch");
+			return -NLE_AF_MISMATCH;
 	} else
 		nfnl_ct_set_family(ct, addr->a_family);
 
diff --git a/lib/netfilter/log.c b/lib/netfilter/log.c
index 41a131c..0cfbc87 100644
--- a/lib/netfilter/log.c
+++ b/lib/netfilter/log.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  */
@@ -31,8 +31,8 @@
  * @{
  */
 
-static struct nl_msg *build_log_cmd_request(uint8_t family, uint16_t queuenum,
-					    uint8_t command)
+static int build_log_cmd_request(uint8_t family, uint16_t queuenum,
+				 uint8_t command, struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct nfulnl_msg_config_cmd cmd;
@@ -40,17 +40,18 @@
 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
 				   family, queuenum);
 	if (msg == NULL)
-		return NULL;
+		return -NLE_NOMEM;
 
 	cmd.command = command;
 	if (nla_put(msg, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
 		goto nla_put_failure;
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
 static int send_log_request(struct nl_handle *handle, struct nl_msg *msg)
@@ -65,49 +66,50 @@
 	return nl_wait_for_ack(handle);
 }
 
-struct nl_msg *nfnl_log_build_pf_bind(uint8_t pf)
+int nfnl_log_build_pf_bind(uint8_t pf, struct nl_msg **result)
 {
-	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_BIND);
+	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_BIND, result);
 }
 
 int nfnl_log_pf_bind(struct nl_handle *nlh, uint8_t pf)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_log_build_pf_bind(pf);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = nfnl_log_build_pf_bind(pf, &msg)) < 0)
+		return err;
 
 	return send_log_request(nlh, msg);
 }
 
-struct nl_msg *nfnl_log_build_pf_unbind(uint8_t pf)
+int nfnl_log_build_pf_unbind(uint8_t pf, struct nl_msg **result)
 {
-	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_UNBIND);
+	return build_log_cmd_request(pf, 0, NFULNL_CFG_CMD_PF_UNBIND, result);
 }
 
 int nfnl_log_pf_unbind(struct nl_handle *nlh, uint8_t pf)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_log_build_pf_unbind(pf);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = nfnl_log_build_pf_unbind(pf, &msg)) < 0)
+		return err;
 
 	return send_log_request(nlh, msg);
 }
 
-static struct nl_msg *nfnl_log_build_request(const struct nfnl_log *log)
+static int nfnl_log_build_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
 {
 	struct nl_msg *msg;
 
 	if (!nfnl_log_test_group(log))
-		return NULL;
+		return -NLE_MISSING_ATTR;
 
 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
 				   0, nfnl_log_get_group(log));
 	if (msg == NULL)
-		return NULL;
+		return -NLE_NOMEM;
 
 	/* This sucks. The nfnetlink_log interface always expects both
 	 * parameters to be present. Needs to be done properly.
@@ -148,77 +150,80 @@
 			htonl(nfnl_log_get_queue_threshold(log))) < 0)
 		goto nla_put_failure;
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
-struct nl_msg *nfnl_log_build_create_request(const struct nfnl_log *log)
+int nfnl_log_build_create_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
 {
-	struct nl_msg *msg;
 	struct nfulnl_msg_config_cmd cmd;
+	int err;
 
-	msg = nfnl_log_build_request(log);
-	if (msg == NULL)
-		return NULL;
+	if ((err = nfnl_log_build_request(log, result)) < 0)
+		return err;
 
 	cmd.command = NFULNL_CFG_CMD_BIND;
 
-	if (nla_put(msg, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
+	if (nla_put(*result, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
 		goto nla_put_failure;
 
-	return msg;
+	return 0;
 
 nla_put_failure:
-	nlmsg_free(msg);
-	return NULL;
+	nlmsg_free(*result);
+	return -NLE_MSGSIZE;
 }
 
 int nfnl_log_create(struct nl_handle *nlh, const struct nfnl_log *log)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_log_build_create_request(log);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_log_build_create_request(log, &msg)) < 0)
+		return err;
 
 	return send_log_request(nlh, msg);
 }
 
-struct nl_msg *nfnl_log_build_change_request(const struct nfnl_log *log)
+int nfnl_log_build_change_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
 {
-	return nfnl_log_build_request(log);
+	return nfnl_log_build_request(log, result);
 }
 
 int nfnl_log_change(struct nl_handle *nlh, const struct nfnl_log *log)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_log_build_change_request(log);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_log_build_change_request(log, &msg)) < 0)
+		return err;
 
 	return send_log_request(nlh, msg);
 }
 
-struct nl_msg *nfnl_log_build_delete_request(const struct nfnl_log *log)
+int nfnl_log_build_delete_request(const struct nfnl_log *log,
+				  struct nl_msg **result)
 {
 	if (!nfnl_log_test_group(log))
-		return NULL;
+		return -NLE_MISSING_ATTR;
 
 	return build_log_cmd_request(0, nfnl_log_get_group(log),
-				     NFULNL_CFG_CMD_UNBIND);
+				     NFULNL_CFG_CMD_UNBIND, result);
 }
 
 int nfnl_log_delete(struct nl_handle *nlh, const struct nfnl_log *log)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_log_build_delete_request(log);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_log_build_delete_request(log, &msg)) < 0)
+		return err;
 
 	return send_log_request(nlh, msg);
 }
diff --git a/lib/netfilter/log_msg.c b/lib/netfilter/log_msg.c
index 5243338..33de482 100644
--- a/lib/netfilter/log_msg.c
+++ b/lib/netfilter/log_msg.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
@@ -62,7 +62,7 @@
 	[NFULA_SEQ_GLOBAL]		= { .type = NLA_U32 },
 };
 
-struct nfnl_log_msg *nfnlmsg_log_msg_parse(struct nlmsghdr *nlh)
+int nfnlmsg_log_msg_parse(struct nlmsghdr *nlh, struct nfnl_log_msg **result)
 {
 	struct nfnl_log_msg *msg;
 	struct nlattr *tb[NFULA_MAX+1];
@@ -71,7 +71,7 @@
 
 	msg = nfnl_log_msg_alloc();
 	if (!msg)
-		return NULL;
+		return -NLE_NOMEM;
 
 	msg->ce_msgtype = nlh->nlmsg_type;
 
@@ -158,11 +158,12 @@
 	if (attr)
 		nfnl_log_msg_set_seq_global(msg, ntohl(nla_get_u32(attr)));
 
-	return msg;
+	*result = msg;
+	return 0;
 
 errout:
 	nfnl_log_msg_put(msg);
-	return NULL;
+	return err;
 }
 
 static int log_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
@@ -171,9 +172,8 @@
 	struct nfnl_log_msg *msg;
 	int err;
 
-	msg = nfnlmsg_log_msg_parse(nlh);
-	if (log == NULL)
-		goto errout_errno;
+	if ((err = nfnlmsg_log_msg_parse(nlh, &msg)) < 0)
+		goto errout;
 
 	err = pp->pp_cb((struct nl_object *) msg, pp);
 	if (err < 0)
@@ -184,10 +184,6 @@
 errout:
 	nfnl_log_msg_put(msg);
 	return err;
-
-errout_errno:
-	err = nl_get_errno();
-	goto errout;
 }
 
 /** @} */
diff --git a/lib/netfilter/log_msg_obj.c b/lib/netfilter/log_msg_obj.c
index ee85090..b2cd9ef 100644
--- a/lib/netfilter/log_msg_obj.c
+++ b/lib/netfilter/log_msg_obj.c
@@ -341,7 +341,7 @@
 	free(msg->log_msg_payload);
 	msg->log_msg_payload = malloc(len);
 	if (!msg->log_msg_payload)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	memcpy(msg->log_msg_payload, payload, len);
 	msg->log_msg_payload_len = len;
@@ -365,7 +365,7 @@
 	free(msg->log_msg_prefix);
 	msg->log_msg_prefix = strdup(prefix);
 	if (!msg->log_msg_prefix)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	msg->ce_mask |= LOG_MSG_ATTR_PREFIX;
 	return 0;
diff --git a/lib/netfilter/nfnl.c b/lib/netfilter/nfnl.c
index 554e234..2441f69 100644
--- a/lib/netfilter/nfnl.c
+++ b/lib/netfilter/nfnl.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
  * Copyright (c) 2007 Secure Computing Corporation
  */
@@ -178,7 +178,7 @@
 
 	nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO);
 	if (nfg == NULL)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	nfg->nfgen_family = family;
 	nfg->version = NFNETLINK_V0;
@@ -236,7 +236,7 @@
 
 	nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags);
 	if (nlh == NULL)
-		return nl_get_errno();
+		return -NLE_MSGSIZE;
 
 	return nfnlmsg_append(msg, family, res_id);
 }
diff --git a/lib/netfilter/queue.c b/lib/netfilter/queue.c
index 2bd719a..7f31c66 100644
--- a/lib/netfilter/queue.c
+++ b/lib/netfilter/queue.c
@@ -41,8 +41,8 @@
  * @{
  */
 
-static struct nl_msg *build_queue_cmd_request(uint8_t family, uint16_t queuenum,
-					      uint8_t command)
+static int build_queue_cmd_request(uint8_t family, uint16_t queuenum,
+				   uint8_t command, struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct nfqnl_msg_config_cmd cmd;
@@ -50,7 +50,7 @@
 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
 				   family, queuenum);
 	if (msg == NULL)
-		return NULL;
+		return -NLE_NOMEM;
 
 	cmd.pf = htons(family);
 	cmd._pad = 0;
@@ -58,56 +58,58 @@
 	if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
 		goto nla_put_failure;
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
-struct nl_msg *nfnl_queue_build_pf_bind(uint8_t pf)
+int nfnl_queue_build_pf_bind(uint8_t pf, struct nl_msg **result)
 {
-	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND);
+	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_BIND, result);
 }
 
 int nfnl_queue_pf_bind(struct nl_handle *nlh, uint8_t pf)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_queue_build_pf_bind(pf);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0)
+		return err;
 
 	return send_queue_request(nlh, msg);
 }
 
-struct nl_msg *nfnl_queue_build_pf_unbind(uint8_t pf)
+int nfnl_queue_build_pf_unbind(uint8_t pf, struct nl_msg **result)
 {
-	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND);
+	return build_queue_cmd_request(pf, 0, NFQNL_CFG_CMD_PF_UNBIND, result);
 }
 
 int nfnl_queue_pf_unbind(struct nl_handle *nlh, uint8_t pf)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_queue_build_pf_unbind(pf);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0)
+		return err;
 
 	return send_queue_request(nlh, msg);
 }
 
-static struct nl_msg *nfnl_queue_build_request(const struct nfnl_queue *queue)
+static int nfnl_queue_build_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
 {
 	struct nl_msg *msg;
 
 	if (!nfnl_queue_test_group(queue))
-		return NULL;
+		return -NLE_MISSING_ATTR;
 
 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
 				   0, nfnl_queue_get_group(queue));
 	if (msg == NULL)
-		return NULL;
+		return -NLE_NOMEM;
 
 	if (nfnl_queue_test_maxlen(queue) &&
 	    nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
@@ -136,79 +138,82 @@
 		if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), &params) < 0)
 			goto nla_put_failure;
 	}
-	return msg;
+
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
-struct nl_msg *nfnl_queue_build_create_request(const struct nfnl_queue *queue)
+int nfnl_queue_build_create_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
 {
-	struct nl_msg *msg;
 	struct nfqnl_msg_config_cmd cmd;
+	int err;
 
-	msg = nfnl_queue_build_request(queue);
-	if (msg == NULL)
-		return NULL;
+	if ((err = nfnl_queue_build_request(queue, result)) < 0)
+		return err;
 
 	cmd.pf = 0;
 	cmd._pad = 0;
 	cmd.command = NFQNL_CFG_CMD_BIND;
 
-	if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
-		goto nla_put_failure;
+	NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd);
 
-	return msg;
+	return 0;
 
 nla_put_failure:
-	nlmsg_free(msg);
-	return NULL;
+	nlmsg_free(*result);
+	return -NLE_MSGSIZE;
 }
 
 int nfnl_queue_create(struct nl_handle *nlh, const struct nfnl_queue *queue)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_queue_build_create_request(queue);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0)
+		return err;
 
 	return send_queue_request(nlh, msg);
 }
 
-struct nl_msg *nfnl_queue_build_change_request(const struct nfnl_queue *queue)
+int nfnl_queue_build_change_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
 {
-	return nfnl_queue_build_request(queue);
+	return nfnl_queue_build_request(queue, result);
 }
 
 int nfnl_queue_change(struct nl_handle *nlh, const struct nfnl_queue *queue)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_queue_build_change_request(queue);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0)
+		return err;
 
 	return send_queue_request(nlh, msg);
 }
 
-struct nl_msg *nfnl_queue_build_delete_request(const struct nfnl_queue *queue)
+int nfnl_queue_build_delete_request(const struct nfnl_queue *queue,
+				    struct nl_msg **result)
 {
 	if (!nfnl_queue_test_group(queue))
-		return NULL;
+		return -NLE_MISSING_ATTR;
 
 	return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
-				       NFQNL_CFG_CMD_UNBIND);
+				       NFQNL_CFG_CMD_UNBIND, result);
 }
 
 int nfnl_queue_delete(struct nl_handle *nlh, const struct nfnl_queue *queue)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nfnl_queue_build_delete_request(queue);
-	if (msg == NULL)
-		return nl_errno(ENOMEM);
+	if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0)
+		return err;
 
 	return send_queue_request(nlh, msg);
 }
diff --git a/lib/netfilter/queue_msg.c b/lib/netfilter/queue_msg.c
index a097b68..6d6ca73 100644
--- a/lib/netfilter/queue_msg.c
+++ b/lib/netfilter/queue_msg.c
@@ -58,7 +58,8 @@
 	},
 };
 
-struct nfnl_queue_msg *nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh)
+int nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh,
+			    struct nfnl_queue_msg **result)
 {
 	struct nfnl_queue_msg *msg;
 	struct nlattr *tb[NFQA_MAX+1];
@@ -67,7 +68,7 @@
 
 	msg = nfnl_queue_msg_alloc();
 	if (!msg)
-		return NULL;
+		return -NLE_NOMEM;
 
 	msg->ce_msgtype = nlh->nlmsg_type;
 
@@ -135,11 +136,12 @@
 			goto errout;
 	}
 
-	return msg;
+	*result = msg;
+	return 0;
 
 errout:
 	nfnl_queue_msg_put(msg);
-	return NULL;
+	return err;
 }
 
 static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
@@ -148,9 +150,8 @@
 	struct nfnl_queue_msg *msg;
 	int err;
 
-	msg = nfnlmsg_queue_msg_parse(nlh);
-	if (msg == NULL)
-		goto errout_errno;
+	if ((err = nfnlmsg_queue_msg_parse(nlh, &msg)) < 0)
+		goto errout;
 
 	err = pp->pp_cb((struct nl_object *) msg, pp);
 	if (err < 0)
@@ -161,10 +162,6 @@
 errout:
 	nfnl_queue_msg_put(msg);
 	return err;
-
-errout_errno:
-	err = nl_get_errno();
-	goto errout;
 }
 
 /** @} */
@@ -205,7 +202,7 @@
 
 	nlmsg = nfnl_queue_msg_build_verdict(msg);
 	if (nlmsg == NULL)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	err = nl_send_auto_complete(nlh, nlmsg);
 	nlmsg_free(nlmsg);
diff --git a/lib/netfilter/queue_msg_obj.c b/lib/netfilter/queue_msg_obj.c
index 476d920..5796c34 100644
--- a/lib/netfilter/queue_msg_obj.c
+++ b/lib/netfilter/queue_msg_obj.c
@@ -400,7 +400,7 @@
 	free(msg->queue_msg_payload);
 	msg->queue_msg_payload = malloc(len);
 	if (!msg->queue_msg_payload)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	memcpy(msg->queue_msg_payload, payload, len);
 	msg->queue_msg_payload_len = len;
diff --git a/lib/nl.c b/lib/nl.c
index 9b6fb9b..ba5262b 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -195,7 +195,7 @@
 
 	handle->h_fd = socket(AF_NETLINK, SOCK_RAW, protocol);
 	if (handle->h_fd < 0) {
-		err = nl_error(1, "socket(AF_NETLINK, ...) failed");
+		err = -nl_syserr2nlerr(errno);
 		goto errout;
 	}
 
@@ -208,7 +208,7 @@
 	err = bind(handle->h_fd, (struct sockaddr*) &handle->h_local,
 		   sizeof(handle->h_local));
 	if (err < 0) {
-		err = nl_error(1, "bind() failed");
+		err = -nl_syserr2nlerr(errno);
 		goto errout;
 	}
 
@@ -216,17 +216,17 @@
 	err = getsockname(handle->h_fd, (struct sockaddr *) &handle->h_local,
 			  &addrlen);
 	if (err < 0) {
-		err = nl_error(1, "getsockname failed");
+		err = -nl_syserr2nlerr(errno);
 		goto errout;
 	}
 
 	if (addrlen != sizeof(handle->h_local)) {
-		err = nl_error(EADDRNOTAVAIL, "Invalid address length");
+		err = -NLE_NOADDR;
 		goto errout;
 	}
 
 	if (handle->h_local.nl_family != AF_NETLINK) {
-		err = nl_error(EPFNOSUPPORT, "Address format not supported");
+		err = -NLE_AF_NOSUPPORT;
 		goto errout;
 	}
 
@@ -275,7 +275,7 @@
 	ret = sendto(handle->h_fd, buf, size, 0, (struct sockaddr *)
 		     &handle->h_peer, sizeof(handle->h_peer));
 	if (ret < 0)
-		return nl_errno(errno);
+		return -nl_syserr2nlerr(errno);
 
 	return ret;
 }
@@ -309,7 +309,7 @@
 
 	ret = sendmsg(handle->h_fd, hdr, 0);
 	if (ret < 0)
-		return nl_errno(errno);
+		return -nl_syserr2nlerr(errno);
 
 	return ret;
 }
@@ -415,7 +415,7 @@
 
 	msg = nlmsg_alloc_simple(type, flags);
 	if (!msg)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (buf && size) {
 		err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
@@ -503,7 +503,7 @@
 		} else {
 			free(msg.msg_control);
 			free(*buf);
-			return nl_error(errno, "recvmsg failed");
+			return -nl_syserr2nlerr(errno);
 		}
 	}
 
@@ -527,7 +527,7 @@
 	if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
 		free(msg.msg_control);
 		free(*buf);
-		return nl_error(EADDRNOTAVAIL, "socket address size mismatch");
+		return -NLE_NOADDR;
 	}
 
 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
@@ -611,7 +611,7 @@
 		free_msg = 1;	/* By default, we free the message data */
 		msg = nlmsg_convert(hdr);
 		if (!msg) {
-			err = nl_errno(ENOMEM);
+			err = -NLE_NOMEM;
 			goto out;
 		}
 
@@ -634,8 +634,7 @@
 			if (cb->cb_set[NL_CB_INVALID])
 				NL_CB_CALL(cb, NL_CB_INVALID, msg);
 			else {
-				err = nl_error(EINVAL,
-					"Sequence number mismatch");
+				err = -NLE_SEQ_MISMATCH;
 				goto out;
 			}
 		}
@@ -692,7 +691,7 @@
 			if (cb->cb_set[NL_CB_OVERRUN])
 				NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
 			else {
-				err = nl_error(EOVERFLOW, "Overrun");
+				err = -NLE_MSG_OVERFLOW;
 				goto out;
 			}
 		}
@@ -709,8 +708,7 @@
 				if (cb->cb_set[NL_CB_INVALID])
 					NL_CB_CALL(cb, NL_CB_INVALID, msg);
 				else {
-					err = nl_error(EINVAL,
-					        "Truncated error message");
+					err = -NLE_MSG_TRUNC;
 					goto out;
 				}
 			} else if (e->error) {
@@ -723,13 +721,11 @@
 					else if (err == NL_SKIP)
 						goto skip;
 					else if (err == NL_STOP) {
-						err = nl_error(-e->error,
-						         "Netlink Error");
+						err = -nl_syserr2nlerr(e->error);
 						goto out;
 					}
 				} else {
-					err = nl_error(-e->error,
-						  "Netlink Error");
+					err = -nl_syserr2nlerr(e->error);
 					goto out;
 				}
 			} else if (cb->cb_set[NL_CB_ACK])
@@ -823,7 +819,7 @@
 
 	cb = nl_cb_clone(handle->h_cb);
 	if (cb == NULL)
-		return nl_get_errno();
+		return -NLE_NOMEM;
 
 	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
 	err = nl_recvmsgs(handle, cb);
diff --git a/lib/object.c b/lib/object.c
index 72e4ba4..3771af9 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -47,10 +47,8 @@
 		BUG();
 
 	new = calloc(1, ops->oo_size);
-	if (!new) {
-		nl_errno(ENOMEM);
+	if (!new)
 		return NULL;
-	}
 
 	new->ce_refcnt = 1;
 	nl_init_list_head(&new->ce_list);
@@ -69,17 +67,18 @@
  * @arg kind		name of object type
  * @return The new object or nULL
  */
-struct nl_object *nl_object_alloc_name(const char *kind)
+int nl_object_alloc_name(const char *kind, struct nl_object **result)
 {
 	struct nl_cache_ops *ops;
 
 	ops = nl_cache_ops_lookup(kind);
-	if (!ops) {
-		nl_error(ENOENT, "Unable to lookup cache kind \"%s\"", kind);
-		return NULL;
-	}
+	if (!ops)
+		return -NLE_OPNOTSUPP;
 
-	return nl_object_alloc(ops->co_obj_ops);
+	if (!(*result = nl_object_alloc(ops->co_obj_ops)))
+		return -NLE_NOMEM;
+
+	return 0;
 }
 
 struct nl_derived_object {
diff --git a/lib/route/addr.c b/lib/route/addr.c
index a4a9acf..0d86293 100644
--- a/lib/route/addr.c
+++ b/lib/route/addr.c
@@ -6,8 +6,8 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
- *                         Baruch Even <baruch@ev-en.org>,
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
  *                         Mediatrix Telecom, inc. <ericb@mediatrix.com>
  */
 
@@ -154,27 +154,25 @@
 
 	if (src->a_peer)
 		if (!(dst->a_peer = nl_addr_clone(src->a_peer)))
-			goto errout;
+			return -NLE_NOMEM;
 	
 	if (src->a_local)
 		if (!(dst->a_local = nl_addr_clone(src->a_local)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->a_bcast)
 		if (!(dst->a_bcast = nl_addr_clone(src->a_bcast)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->a_anycast)
 		if (!(dst->a_anycast = nl_addr_clone(src->a_anycast)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->a_multicast)
 		if (!(dst->a_multicast = nl_addr_clone(src->a_multicast)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static struct nla_policy addr_policy[IFA_MAX+1] = {
@@ -189,11 +187,11 @@
 	struct rtnl_addr *addr;
 	struct ifaddrmsg *ifa;
 	struct nlattr *tb[IFA_MAX+1];
-	int err = -ENOMEM, peer_prefix = 0;
+	int err, peer_prefix = 0;
 
 	addr = rtnl_addr_alloc();
 	if (!addr) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 	addr->ce_msgtype = nlh->nlmsg_type;
@@ -639,25 +637,15 @@
  * @{
  */
 
-struct nl_cache *rtnl_addr_alloc_cache(struct nl_handle *handle)
+int rtnl_addr_alloc_cache(struct nl_handle *sock, struct nl_cache **result)
 {
-	struct nl_cache *cache;
-	
-	cache = nl_cache_alloc(&rtnl_addr_ops);
-	if (!cache)
-		return NULL;
-
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		nl_cache_free(cache);
-		return NULL;
-	}
-
-	return cache;
+	return nl_cache_alloc_and_fill(&rtnl_addr_ops, sock, result);
 }
 
 /** @} */
 
-static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags)
+static int build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags,
+			  struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct ifaddrmsg am = {
@@ -680,7 +668,7 @@
 
 	msg = nlmsg_alloc_simple(cmd, flags);
 	if (!msg)
-		goto nla_put_failure;
+		return -NLE_NOMEM;
 
 	if (nlmsg_append(msg, &am, sizeof(am), NLMSG_ALIGNTO) < 0)
 		goto nla_put_failure;
@@ -702,11 +690,12 @@
 	if (tmpl->ce_mask & ADDR_ATTR_ANYCAST)
 		NLA_PUT_ADDR(msg, IFA_ANYCAST, tmpl->a_anycast);
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
 /**
@@ -718,6 +707,7 @@
  * Build netlink request message to request addition of new address
  * @arg addr		Address object representing the new address.
  * @arg flags		Additional netlink message flags.
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting the addition of a new
  * address. The netlink message header isn't fully equipped with
@@ -732,20 +722,19 @@
  * which case a host scope is used if not specified otherwise.
  *
  * @note Free the memory after usage using nlmsg_free().
- * @return Newly allocated netlink message or NULL if an error occured.
+ *
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags)
+int rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags,
+				struct nl_msg **result)
 {
 	int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY |
 		       ADDR_ATTR_PREFIXLEN | ADDR_ATTR_LOCAL;
 
-	if ((addr->ce_mask & required) != required) {
-		nl_error(EINVAL, "Missing mandatory attributes, required are: "
-				 "ifindex, family, prefixlen, local address.");
-		return NULL;
-	}
+	if ((addr->ce_mask & required) != required)
+		return -NLE_MISSING_ATTR;
 	
-	return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags);
+	return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags, result);
 }
 
 /**
@@ -767,9 +756,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_addr_build_add_request(addr, flags);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = rtnl_addr_build_add_request(addr, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(handle, msg);
 	nlmsg_free(msg);
@@ -790,6 +778,7 @@
  * Build a netlink request message to request deletion of an address
  * @arg addr		Address object to be deleteted.
  * @arg flags		Additional netlink message flags.
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a deletion of an address.
  * The netlink message header isn't fully equipped with all relevant
@@ -806,19 +795,18 @@
  *   - peer address (rtnl_addr_set_peer(), IPv4 only)
  *
  * @note Free the memory after usage using nlmsg_free().
- * @return Newly allocated netlink message or NULL if an error occured.
+ *
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags)
+int rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags,
+				   struct nl_msg **result)
 {
 	int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY;
 
-	if ((addr->ce_mask & required) != required) {
-		nl_error(EINVAL, "Missing mandatory attributes, required are: "
-				 "ifindex, family");
-		return NULL;
-	}
-	
-	return build_addr_msg(addr, RTM_DELADDR, flags);
+	if ((addr->ce_mask & required) != required)
+		return -NLE_MISSING_ATTR;
+
+	return build_addr_msg(addr, RTM_DELADDR, flags, result);
 }
 
 /**
@@ -841,9 +829,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_addr_build_delete_request(addr, flags);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = rtnl_addr_build_delete_request(addr, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(handle, msg);
 	nlmsg_free(msg);
@@ -954,7 +941,7 @@
 {
 	if (addr->ce_mask & ADDR_ATTR_FAMILY) {
 		if (new->a_family != addr->a_family)
-			return nl_error(EINVAL, "Address family mismatch");
+			return -NLE_AF_MISMATCH;
 	} else
 		addr->a_family = new->a_family;
 
diff --git a/lib/route/class.c b/lib/route/class.c
index 7966b09..9a1784f 100644
--- a/lib/route/class.c
+++ b/lib/route/class.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -36,7 +36,7 @@
 
 	class = rtnl_class_alloc();
 	if (!class) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 	class->ce_msgtype = n->nlmsg_type;
@@ -81,15 +81,15 @@
  * @{
  */
 
-static struct nl_msg *class_build(struct rtnl_class *class, int type, int flags)
+static int class_build(struct rtnl_class *class, int type, int flags,
+		       struct nl_msg **result)
 {
 	struct rtnl_class_ops *cops;
-	struct nl_msg *msg;
 	int err;
 
-	msg = tca_build_msg((struct rtnl_tca *) class, type, flags);
-	if (!msg)
-		goto errout;
+	err = tca_build_msg((struct rtnl_tca *) class, type, flags, result);
+	if (err < 0)
+		return err;
 
 	cops = rtnl_class_lookup_ops(class);
 	if (cops && cops->co_get_opts) {
@@ -97,23 +97,24 @@
 		
 		opts = cops->co_get_opts(class);
 		if (opts) {
-			err = nla_put_nested(msg, TCA_OPTIONS, opts);
+			err = nla_put_nested(*result, TCA_OPTIONS, opts);
 			nlmsg_free(opts);
 			if (err < 0)
 				goto errout;
 		}
 	}
 
-	return msg;
+	return 0;
 errout:
-	nlmsg_free(msg);
-	return NULL;
+	nlmsg_free(*result);
+	return err;
 }
 
 /**
  * Build a netlink message to add a new class
  * @arg class		class to add 
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting an addition of a class.
  * The netlink message header isn't fully equipped with all relevant
@@ -123,11 +124,12 @@
  * Common message flags
  *   - NLM_F_REPLACE - replace possibly existing classes
  *
- * @return New netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_class_build_add_request(struct rtnl_class *class, int flags)
+int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
+				 struct nl_msg **result)
 {
-	return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags);
+	return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result);
 }
 
 /**
@@ -151,12 +153,10 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_class_build_add_request(class, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
+		return err;
 
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -181,22 +181,25 @@
  *
  * @return The cache or NULL if an error has occured.
  */
-struct nl_cache * rtnl_class_alloc_cache(struct nl_handle *handle, int ifindex)
+int rtnl_class_alloc_cache(struct nl_handle *handle, int ifindex,
+			   struct nl_cache **result)
 {
 	struct nl_cache * cache;
+	int err;
 	
 	cache = nl_cache_alloc(&rtnl_class_ops);
 	if (!cache)
-		return NULL;
+		return -NLE_NOMEM;
 
 	cache->c_iarg1 = ifindex;
 	
-	if (handle && nl_cache_refill(handle, cache) < 0) {
+	if (handle && (err = nl_cache_refill(handle, cache)) < 0) {
 		nl_cache_free(cache);
-		return NULL;
+		return err;
 	}
 
-	return cache;
+	*result = cache;
+	return 0;
 }
 
 /** @} */
diff --git a/lib/route/class_api.c b/lib/route/class_api.c
index c814486..374cf0f 100644
--- a/lib/route/class_api.c
+++ b/lib/route/class_api.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -43,7 +43,7 @@
 
 	for (op = &class_ops_list; (o = *op) != NULL; op = &o->co_next)
 		if (!strcasecmp(cops->co_kind, o->co_kind))
-			return nl_errno(EEXIST);
+			return -NLE_EXIST;
 
 	cops->co_next = NULL;
 	*op = cops;
@@ -64,7 +64,7 @@
 			break;
 
 	if (!o)
-		return nl_errno(ENOENT);
+		return -NLE_OBJ_NOTFOUND;
 
 	*op = cops->co_next;
 
diff --git a/lib/route/classifier.c b/lib/route/classifier.c
index df6d3ae..8008bc4 100644
--- a/lib/route/classifier.c
+++ b/lib/route/classifier.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -44,7 +44,7 @@
 
 	cls = rtnl_cls_alloc();
 	if (!cls) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 	cls->ce_msgtype = nlh->nlmsg_type;
@@ -88,18 +88,18 @@
 }
 
 
-static struct nl_msg *cls_build(struct rtnl_cls *cls, int type, int flags)
+static int cls_build(struct rtnl_cls *cls, int type, int flags,
+		     struct nl_msg **result)
 {
-	struct nl_msg *msg;
 	struct rtnl_cls_ops *cops;
 	int err, prio, proto;
 	struct tcmsg *tchdr;
 
-	msg = tca_build_msg((struct rtnl_tca *) cls, type, flags);
-	if (!msg)
-		goto errout;
+	err = tca_build_msg((struct rtnl_tca *) cls, type, flags, result);
+	if (err < 0)
+		return err;
 
-	tchdr = nlmsg_data(nlmsg_hdr(msg));
+	tchdr = nlmsg_data(nlmsg_hdr(*result));
 	prio = rtnl_cls_get_prio(cls);
 	proto = rtnl_cls_get_protocol(cls);
 	tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)),
@@ -110,17 +110,17 @@
 		
 		opts = cops->co_get_opts(cls);
 		if (opts) {
-			err = nla_put_nested(msg, TCA_OPTIONS, opts);
+			err = nla_put_nested(*result, TCA_OPTIONS, opts);
 			nlmsg_free(opts);
 			if (err < 0)
 				goto errout;
 		}
 	}
 
-	return msg;
+	return 0;
 errout:
-	nlmsg_free(msg);
-	return NULL;
+	nlmsg_free(*result);
+	return err;
 }
 
 /**
@@ -132,6 +132,7 @@
  * Build a netlink message to add a new classifier
  * @arg cls		classifier to add
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting an addition of a classifier
  * The netlink message header isn't fully equipped with all relevant
@@ -140,11 +141,12 @@
  * the new classifier set via \c rtnl_cls_set_* functions. \a opts
  * may point to the clsasifier specific options.
  *
- * @return New netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg * rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags)
+int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
+			       struct nl_msg **result)
 {
-	return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags);
+	return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result);
 }
 
 /**
@@ -161,15 +163,13 @@
  */
 int rtnl_cls_add(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_cls_build_add_request(cls, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
+		return err;
 	
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -180,17 +180,19 @@
  * Build a netlink message to change classifier attributes
  * @arg cls		classifier to change
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a change of a neigh
  * attributes. The netlink message header isn't fully equipped with
  * all relevant fields and must thus be sent out via nl_send_auto_complete()
  * or supplemented as needed.
  *
- * @return The netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags)
+int rtnl_cls_build_change_request(struct rtnl_cls *cls, int flags,
+				  struct nl_msg **result)
 {
-	return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags);
+	return cls_build(cls, RTM_NEWTFILTER, NLM_F_REPLACE | flags, result);
 }
 
 /**
@@ -208,15 +210,13 @@
 int rtnl_cls_change(struct nl_handle *handle, struct rtnl_cls *cls,
 		    int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_cls_build_change_request(cls, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
+		return err;
 	
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -227,17 +227,19 @@
  * Build a netlink request message to delete a classifier
  * @arg cls		classifier to delete
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a deletion of a classifier.
  * The netlink message header isn't fully equipped with all relevant
  * fields and must thus be sent out via nl_send_auto_complete()
  * or supplemented as needed.
  *
- * @return New netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags)
+int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
+				  struct nl_msg **result)
 {
-	return cls_build(cls, RTM_DELTFILTER, flags);
+	return cls_build(cls, RTM_DELTFILTER, flags, result);
 }
 
 
@@ -255,15 +257,13 @@
  */
 int rtnl_cls_delete(struct nl_handle *handle, struct rtnl_cls *cls, int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_cls_build_delete_request(cls, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
+		return err;
 	
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -284,32 +284,33 @@
  * @arg ifindex		interface index of the link the classes are
  *                      attached to.
  * @arg parent          parent qdisc/class
+ * @arg result		Pointer to store resulting cache.
  *
  * Allocates a new cache, initializes it properly and updates it to
  * include all classes attached to the specified interface.
  *
  * @note The caller is responsible for destroying and freeing the
  *       cache after using it.
- * @return The cache or NULL if an error has occured.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache *rtnl_cls_alloc_cache(struct nl_handle *handle,
-				      int ifindex, uint32_t parent)
+int rtnl_cls_alloc_cache(struct nl_handle *handle, int ifindex, uint32_t parent,			 struct nl_cache **result)
 {
 	struct nl_cache * cache;
+	int err;
 	
-	cache = nl_cache_alloc(&rtnl_cls_ops);
-	if (cache == NULL)
-		return NULL;
+	if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
+		return -NLE_NOMEM;
 
 	cache->c_iarg1 = ifindex;
 	cache->c_iarg2 = parent;
 	
-	if (handle && nl_cache_refill(handle, cache) < 0) {
+	if (handle && (err = nl_cache_refill(handle, cache)) < 0) {
 		nl_cache_free(cache);
-		return NULL;
+		return err;
 	}
 
-	return cache;
+	*result = cache;
+	return 0;
 }
 
 /** @} */
diff --git a/lib/route/cls/fw.c b/lib/route/cls/fw.c
index 7ca7619..61972de 100644
--- a/lib/route/cls/fw.c
+++ b/lib/route/cls/fw.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  * Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
  * Copyright (c) 2006 Siemens AG Oesterreich
  */
@@ -63,7 +63,7 @@
 
 	f = fw_alloc(cls);
 	if (!f)
-		goto errout_nomem;
+		return -NLE_NOMEM;
 
 	if (tb[TCA_FW_CLASSID]) {
 		f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]);
@@ -73,14 +73,14 @@
 	if (tb[TCA_FW_ACT]) {
 		f->cf_act = nla_get_data(tb[TCA_FW_ACT]);
 		if (!f->cf_act)
-			goto errout_nomem;
+			return -NLE_NOMEM;
 		f->cf_mask |= FW_ATTR_ACTION;
 	}
 
 	if (tb[TCA_FW_POLICE]) {
 		f->cf_police = nla_get_data(tb[TCA_FW_POLICE]);
 		if (!f->cf_police)
-			goto errout_nomem;
+			return -NLE_NOMEM;
 		f->cf_mask |= FW_ATTR_POLICE;
 	}
 
@@ -90,11 +90,6 @@
 	}
 
 	return 0;
-
-errout_nomem:
-	err = nl_errno(ENOMEM);
-
-	return err;
 }
 
 static void fw_free_data(struct rtnl_cls *cls)
@@ -119,19 +114,17 @@
 
 	dst = fw_alloc(_dst);
 	if (!dst)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (src->cf_act)
 		if (!(dst->cf_act = nl_data_clone(src->cf_act)))
-			goto errout;
+			return -NLE_NOMEM;
 	
 	if (src->cf_police)
 		if (!(dst->cf_police = nl_data_clone(src->cf_police)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static int fw_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
@@ -217,7 +210,7 @@
 	
 	f = fw_alloc(cls);
 	if (!f)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	f->cf_classid = classid;
 	f->cf_mask |= FW_ATTR_CLASSID;
diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c
index 596e63f..1f881d3 100644
--- a/lib/route/cls/u32.c
+++ b/lib/route/cls/u32.c
@@ -137,8 +137,7 @@
 		int pcnt_size;
 
 		if (!tb[TCA_U32_SEL]) {
-			err = nl_error(EINVAL, "Missing TCA_U32_SEL required "
-					       "for TCA_U32_PCNT");
+			err = -NLE_MISSING_ATTR;
 			goto errout;
 		}
 		
@@ -146,7 +145,7 @@
 		pcnt_size = sizeof(struct tc_u32_pcnt) +
 				(sel->nkeys * sizeof(uint64_t));
 		if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
-			err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT");
+			err = -NLE_INVAL;
 			goto errout;
 		}
 
@@ -164,7 +163,7 @@
 	return 0;
 
 errout_nomem:
-	err = nl_errno(ENOMEM);
+	err = -NLE_NOMEM;
 errout:
 	return err;
 }
@@ -193,27 +192,25 @@
 
 	dst = u32_alloc(_dst);
 	if (!dst)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (src->cu_selector)
 		if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->cu_act)
 		if (!(dst->cu_act = nl_data_clone(src->cu_act)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->cu_police)
 		if (!(dst->cu_police = nl_data_clone(src->cu_police)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->cu_pcnt)
 		if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
@@ -419,7 +416,7 @@
 	
 	u = u32_alloc(cls);
 	if (!u)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	u->cu_classid = classid;
 	u->cu_mask |= U32_ATTR_CLASSID;
@@ -441,11 +438,11 @@
 
 	u = u32_alloc(cls);
 	if (!u)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	sel = u32_selector_alloc(u);
 	if (!sel)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	sel->flags |= flags;
 	u->cu_mask |= U32_ATTR_SELECTOR;
@@ -476,11 +473,11 @@
 
 	u = u32_alloc(cls);
 	if (!u)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	sel = u32_selector_alloc(u);
 	if (!sel)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
 	if (err < 0)
@@ -523,7 +520,7 @@
 {
 	int shift = ((off & 3) == 0 ? 16 : 0);
 	if (off % 2)
-		return nl_error(EINVAL, "Invalid offset alignment");
+		return -NLE_INVAL;
 
 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
 				htonl((uint32_t)mask << shift),
diff --git a/lib/route/cls_api.c b/lib/route/cls_api.c
index f5a083a..73f05df 100644
--- a/lib/route/cls_api.c
+++ b/lib/route/cls_api.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -44,7 +44,7 @@
 
 	for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next)
 		if (!strcasecmp(cops->co_kind, o->co_kind))
-			return nl_errno(EEXIST);
+			return -NLE_EXIST;
 
 	cops->co_next = NULL;
 	*op = cops;
@@ -65,7 +65,7 @@
 			break;
 
 	if (!o)
-		return nl_errno(ENOENT);
+		return -NLE_OBJ_NOTFOUND;
 
 	*op = cops->co_next;
 
diff --git a/lib/route/link.c b/lib/route/link.c
index 13d3e93..cd8cd8a 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -215,21 +215,19 @@
 
 	if (src->l_addr)
 		if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->l_bcast)
 		if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->l_info_ops && src->l_info_ops->io_clone) {
 		err = src->l_info_ops->io_clone(dst, src);
 		if (err < 0)
-			goto errout;
+			return err;
 	}
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static struct nla_policy link_policy[IFLA_MAX+1] = {
@@ -265,7 +263,7 @@
 
 	link = rtnl_link_alloc();
 	if (link == NULL) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 		
@@ -276,7 +274,7 @@
 		goto errout;
 
 	if (tb[IFLA_IFNAME] == NULL) {
-		err = nl_error(EINVAL, "Missing link name TLV");
+		err = -NLE_MISSING_ATTR;
 		goto errout;
 	}
 
@@ -859,27 +857,16 @@
 /**
  * Allocate link cache and fill in all configured links.
  * @arg handle		Netlink handle.
+ * @arg result		Pointer to store resulting cache.
  *
  * Allocates a new link cache, initializes it properly and updates it
  * to include all links currently configured in the kernel.
  *
- * @note Free the memory after usage.
- * @return Newly allocated cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache *rtnl_link_alloc_cache(struct nl_handle *handle)
+int rtnl_link_alloc_cache(struct nl_handle *sock, struct nl_cache **result)
 {
-	struct nl_cache * cache;
-	
-	cache = nl_cache_alloc(&rtnl_link_ops);
-	if (cache == NULL)
-		return NULL;
-	
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		nl_cache_free(cache);
-		return NULL;
-	}
-
-	return cache;
+	return nl_cache_alloc_and_fill(&rtnl_link_ops, sock, result);
 }
 
 /**
@@ -962,9 +949,9 @@
  * @note Not all attributes can be changed, see
  *       \ref link_changeable "Changeable Attributes" for more details.
  */
-struct nl_msg * rtnl_link_build_change_request(struct rtnl_link *old,
-					       struct rtnl_link *tmpl,
-					       int flags)
+int rtnl_link_build_change_request(struct rtnl_link *old,
+				   struct rtnl_link *tmpl, int flags,
+				   struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct ifinfomsg ifi = {
@@ -979,7 +966,7 @@
 
 	msg = nlmsg_alloc_simple(RTM_SETLINK, flags);
 	if (!msg)
-		goto nla_put_failure;
+		return -NLE_NOMEM;
 
 	if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
 		goto nla_put_failure;
@@ -1023,11 +1010,12 @@
 		nla_nest_end(msg, info);
 	}
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
 /**
@@ -1048,15 +1036,13 @@
 int rtnl_link_change(struct nl_handle *handle, struct rtnl_link *old,
 		     struct rtnl_link *tmpl, int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_link_build_change_request(old, tmpl, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_link_build_change_request(old, tmpl, flags, &msg)) < 0)
+		return err;
 	
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -1504,7 +1490,7 @@
 	int err;
 
 	if ((io = rtnl_link_info_ops_lookup(type)) == NULL)
-		return nl_error(ENOENT, "No such link info type exists");
+		return -NLE_OPNOTSUPP;
 
 	if (link->l_info_ops)
 		release_link_info(link);
diff --git a/lib/route/link/api.c b/lib/route/link/api.c
index afe00b1..a0e7679 100644
--- a/lib/route/link/api.c
+++ b/lib/route/link/api.c
@@ -61,10 +61,10 @@
 int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
 {
 	if (ops->io_name == NULL)
-		return nl_error(EINVAL, "No name specified");
+		return -NLE_INVAL;
 
 	if (rtnl_link_info_ops_lookup(ops->io_name))
-		return nl_error(EEXIST, "Link info operations already exist");
+		return -NLE_EXIST;
 
 	NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
 
@@ -83,10 +83,10 @@
 			break;
 
 	if (!t)
-		return nl_error(ENOENT, "No such link info operations");
+		return -NLE_OPNOTSUPP;
 
 	if (t->io_refcnt > 0)
-		return nl_error(EBUSY, "Info operations in use");
+		return -NLE_BUSY;
 
 	NL_DBG(1, "Unregistered link info perations %s\n", ops->io_name);
 
diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c
index c148dca..ea5699f 100644
--- a/lib/route/link/vlan.c
+++ b/lib/route/link/vlan.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2007 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -73,7 +73,7 @@
 	struct vlan_info *vi;
 
 	if ((vi = calloc(1, sizeof(*vi))) == NULL)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	link->l_info = vi;
 
@@ -119,12 +119,11 @@
 
 		nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
 			if (nla_len(nla) < sizeof(*map))
-				return nl_error(EINVAL, "Malformed mapping");
+				return -NLE_INVAL;
 
 			map = nla_data(nla);
 			if (map->from < 0 || map->from > VLAN_PRIO_MAX) {
-				return nl_error(EINVAL, "VLAN prio %d out of "
-						"range", map->from);
+				return -NLE_INVAL;
 			}
 
 			vi->vi_ingress_qos[map->from] = map->to;
@@ -140,7 +139,7 @@
 
 		nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
 			if (nla_len(nla) < sizeof(*map))
-				return nl_error(EINVAL, "Malformed mapping");
+				return -NLE_INVAL;
 			i++;
 		}
 
@@ -148,7 +147,7 @@
 		vi->vi_egress_size = (i + 32) & ~31;
 		vi->vi_egress_qos = calloc(vi->vi_egress_size, sizeof(*map));
 		if (vi->vi_egress_qos == NULL)
-			return nl_errno(ENOMEM);
+			return -NLE_NOMEM;
 
 		i = 0;
 		nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
@@ -260,7 +259,7 @@
 	vdst->vi_egress_qos = calloc(vsrc->vi_egress_size,
 				     sizeof(struct vlan_map));
 	if (!vdst->vi_egress_qos)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
 	       vsrc->vi_egress_size * sizeof(struct vlan_map));
@@ -274,7 +273,7 @@
 	struct nlattr *data;
 
 	if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
-		return nl_errno(ENOBUFS);
+		return -NLE_MSGSIZE;
 
 	if (vi->vi_mask & VLAN_HAS_ID)
 		NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
@@ -349,7 +348,7 @@
 	struct vlan_info *vi = link->l_info;
 
 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
-		return nl_error(EOPNOTSUPP, "Not a VLAN link");
+		return -NLE_OPNOTSUPP;
 
 	vi->vi_vlan_id = id;
 	vi->vi_mask |= VLAN_HAS_ID;
@@ -362,7 +361,7 @@
 	struct vlan_info *vi = link->l_info;
 
 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
-		return nl_error(EOPNOTSUPP, "Not a VLAN link");
+		return -NLE_OPNOTSUPP;
 
 	if (vi->vi_mask & VLAN_HAS_ID)
 		return vi->vi_vlan_id;
@@ -375,7 +374,7 @@
 	struct vlan_info *vi = link->l_info;
 
 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
-		return nl_error(EOPNOTSUPP, "Not a VLAN link");
+		return -NLE_OPNOTSUPP;
 
 	vi->vi_flags_mask |= flags;
 	vi->vi_flags |= flags;
@@ -389,7 +388,7 @@
 	struct vlan_info *vi = link->l_info;
 
 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
-		return nl_error(EOPNOTSUPP, "Not a VLAN link");
+		return -NLE_OPNOTSUPP;
 
 	vi->vi_flags_mask |= flags;
 	vi->vi_flags &= ~flags;
@@ -403,7 +402,7 @@
 	struct vlan_info *vi = link->l_info;
 
 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
-		return nl_error(EOPNOTSUPP, "Not a VLAN link");
+		return -NLE_OPNOTSUPP;
 
 	return vi->vi_flags;
 }
@@ -414,11 +413,10 @@
 	struct vlan_info *vi = link->l_info;
 
 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
-		return nl_error(EOPNOTSUPP, "Not a VLAN link");
+		return -NLE_OPNOTSUPP;
 
 	if (from < 0 || from > VLAN_PRIO_MAX)
-		return nl_error(EINVAL, "Invalid vlan prio 0..%d",
-			VLAN_PRIO_MAX);
+		return -NLE_INVAL;
 
 	vi->vi_ingress_qos[from] = to;
 	vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
@@ -430,10 +428,8 @@
 {
 	struct vlan_info *vi = link->l_info;
 
-	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) {
-		nl_error(EOPNOTSUPP, "Not a VLAN link");
+	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
 		return NULL;
-	}
 
 	if (vi->vi_mask & VLAN_HAS_INGRESS_QOS)
 		return vi->vi_ingress_qos;
@@ -446,11 +442,10 @@
 	struct vlan_info *vi = link->l_info;
 
 	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
-		return nl_error(EOPNOTSUPP, "Not a VLAN link");
+		return -NLE_OPNOTSUPP;
 
 	if (to < 0 || to > VLAN_PRIO_MAX)
-		return nl_error(EINVAL, "Invalid vlan prio 0..%d",
-			VLAN_PRIO_MAX);
+		return -NLE_INVAL;
 
 	if (vi->vi_negress >= vi->vi_egress_size) {
 		int new_size = vi->vi_egress_size + 32;
@@ -458,7 +453,7 @@
 
 		ptr = realloc(vi->vi_egress_qos, new_size);
 		if (!ptr)
-			return nl_errno(ENOMEM);
+			return -NLE_NOMEM;
 
 		vi->vi_egress_qos = ptr;
 		vi->vi_egress_size = new_size;
@@ -477,15 +472,11 @@
 {
 	struct vlan_info *vi = link->l_info;
 
-	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops) {
-		nl_error(EOPNOTSUPP, "Not a VLAN link");
+	if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
 		return NULL;
-	}
 
-	if (negress == NULL) {
-		nl_error(EINVAL, "Require pointer to store negress");
+	if (negress == NULL)
 		return NULL;
-	}
 
 	if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
 		*negress = vi->vi_negress;
diff --git a/lib/route/neigh.c b/lib/route/neigh.c
index fa1dc59..b3c8e5e 100644
--- a/lib/route/neigh.c
+++ b/lib/route/neigh.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -187,15 +187,13 @@
 
 	if (src->n_lladdr)
 		if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->n_dst)
 		if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
@@ -261,7 +259,7 @@
 
 	neigh = rtnl_neigh_alloc();
 	if (!neigh) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
@@ -523,30 +521,16 @@
 /**
  * Build a neighbour cache including all neighbours currently configured in the kernel.
  * @arg handle		netlink handle
+ * @arg result		Pointer to store resulting cache.
  *
  * Allocates a new neighbour cache, initializes it properly and updates it
  * to include all neighbours currently configured in the kernel.
  *
- * @note The caller is responsible for destroying and freeing the
- *       cache after using it.
- * @return The new cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache *rtnl_neigh_alloc_cache(struct nl_handle *handle)
+int rtnl_neigh_alloc_cache(struct nl_handle *sock, struct nl_cache **result)
 {
-	struct nl_cache *cache;
-
-	cache = nl_cache_alloc(&rtnl_neigh_ops);
-	if (cache == NULL)
-		return NULL;
-
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		nl_cache_free(cache);
-		return NULL;
-	}
-
-	NL_DBG(2, "Returning new cache %p\n", cache);
-
-	return cache;
+	return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
 }
 
 /**
@@ -579,8 +563,8 @@
  * @{
  */
 
-static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd,
-				       int flags)
+static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
+			   struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct ndmsg nhdr = {
@@ -594,7 +578,7 @@
 
 	msg = nlmsg_alloc_simple(cmd, flags);
 	if (!msg)
-		return NULL;
+		return -NLE_NOMEM;
 
 	if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
 		goto nla_put_failure;
@@ -604,17 +588,19 @@
 	if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
 		NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
 /**
  * Build netlink request message to add a new neighbour
  * @arg tmpl		template with data of new neighbour
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a addition of a new
  * neighbour. The netlink message header isn't fully equipped with
@@ -628,11 +614,13 @@
  *  - Destination address (rtnl_neigh_set_dst())
  *  - Link layer address (rtnl_neigh_set_lladdr())
  *
- * @return The netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags)
+int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
+				 struct nl_msg **result)
 {
-	return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE | flags);
+	return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE | flags,
+			       result);
 }
 
 /**
@@ -658,12 +646,10 @@
 	int err;
 	struct nl_msg *msg;
 	
-	msg = rtnl_neigh_build_add_request(tmpl, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
+		return err;
 
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -681,6 +667,7 @@
  * Build a netlink request message to delete a neighbour
  * @arg neigh		neighbour to delete
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a deletion of a neighbour.
  * The netlink message header isn't fully equipped with all relevant
@@ -688,12 +675,12 @@
  * or supplemented as needed. \a neigh must point to an existing
  * neighbour.
  *
- * @return The netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh,
-					       int flags)
+int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
+				    struct nl_msg **result)
 {
-	return build_neigh_msg(neigh, RTM_DELNEIGH, flags);
+	return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
 }
 
 /**
@@ -711,15 +698,13 @@
 int rtnl_neigh_delete(struct nl_handle *handle, struct rtnl_neigh *neigh,
 		      int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_neigh_build_delete_request(neigh, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
+		return err;
 
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -737,20 +722,23 @@
  * Build a netlink request message to change neighbour attributes
  * @arg neigh		the neighbour to change
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a change of a neigh
  * attributes. The netlink message header isn't fully equipped with
  * all relevant fields and must thus be sent out via nl_send_auto_complete()
  * or supplemented as needed.
  *
- * @return The netlink message
  * @note Not all attributes can be changed, see
  *       \ref neigh_changeable "Changeable Attributes" for a list.
+ *
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_neigh_build_change_request(struct rtnl_neigh *neigh,
-					       int flags)
+int rtnl_neigh_build_change_request(struct rtnl_neigh *neigh, int flags,
+				    struct nl_msg **result)
 {
-	return build_neigh_msg(neigh, RTM_NEWNEIGH, NLM_F_REPLACE | flags);
+	return build_neigh_msg(neigh, RTM_NEWNEIGH, NLM_F_REPLACE | flags,
+			       result);
 }
 
 /**
@@ -770,15 +758,13 @@
 int rtnl_neigh_change(struct nl_handle *handle, struct rtnl_neigh *neigh,
 		      int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_neigh_build_change_request(neigh, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_neigh_build_change_request(neigh, flags, &msg)) < 0)
+		return err;
 
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -905,8 +891,7 @@
 	if (!nocheck) {
 		if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
 			if (new->a_family != neigh->n_family)
-				return nl_error(EINVAL,
-						"Address family mismatch");
+				return -NLE_AF_MISMATCH;
 		} else {
 			neigh->n_family = new->a_family;
 			neigh->ce_mask |= NEIGH_ATTR_FAMILY;
diff --git a/lib/route/neightbl.c b/lib/route/neightbl.c
index 3191b5b..6010da0 100644
--- a/lib/route/neightbl.c
+++ b/lib/route/neightbl.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -129,7 +129,7 @@
 
 	ntbl = rtnl_neightbl_alloc();
 	if (!ntbl) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
@@ -143,7 +143,7 @@
 	ntbl->nt_family = rtmsg->rtgen_family;
 
 	if (tb[NDTA_NAME] == NULL) {
-		err = nl_error(EINVAL, "NDTA_NAME is missing");
+		return -NLE_MISSING_ATTR;
 		goto errout;
 	}
 
@@ -395,29 +395,17 @@
 /**
  * Build a neighbour table cache including all neighbour tables currently configured in the kernel.
  * @arg handle		netlink handle
+ * @arg result		Pointer to store resulting cache.
  *
  * Allocates a new neighbour table cache, initializes it properly and
  * updates it to include all neighbour tables currently configured in
  * the kernel.
  *
- * @note The caller is responsible for destroying and freeing the
- *       cache after using it.
- * @return The new cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache * rtnl_neightbl_alloc_cache(struct nl_handle *handle)
+int rtnl_neightbl_alloc_cache(struct nl_handle *sock, struct nl_cache **result)
 {
-	struct nl_cache * cache;
-	
-	cache = nl_cache_alloc(&rtnl_neightbl_ops);
-	if (cache == NULL)
-		return NULL;
-	
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		nl_cache_free(cache);
-		return NULL;
-	}
-
-	return cache;
+	return nl_cache_alloc_and_fill(&rtnl_neightbl_ops, sock, result);
 }
 
 /**
@@ -464,6 +452,7 @@
  * Builds a netlink change request message to change neighbour table attributes
  * @arg old		neighbour table to change
  * @arg tmpl		template with requested changes
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a change of neighbour table
  * attributes. The netlink message header isn't fully equipped with all
@@ -473,93 +462,110 @@
  * kernel and \a tmpl must contain the attributes to be changed set via
  * \c rtnl_neightbl_set_* functions.
  *
- * @return New netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg * rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
-						   struct rtnl_neightbl *tmpl)
+int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
+				       struct rtnl_neightbl *tmpl,
+				       struct nl_msg **result)
 {
-	struct nl_msg *m;
+	struct nl_msg *m, *parms = NULL;
 	struct ndtmsg ndt = {
 		.ndtm_family = old->nt_family,
 	};
 
 	m = nlmsg_alloc_simple(RTM_SETNEIGHTBL, 0);
-	nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO);
+	if (!m)
+		return -NLE_NOMEM;
 
-	nla_put_string(m, NDTA_NAME, old->nt_name);
+	if (nlmsg_append(m, &ndt, sizeof(ndt), NLMSG_ALIGNTO) < 0)
+		goto nla_put_failure;
+
+	NLA_PUT_STRING(m, NDTA_NAME, old->nt_name);
 
 	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH1)
-		nla_put_u32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1);
+		NLA_PUT_U32(m, NDTA_THRESH1, tmpl->nt_gc_thresh1);
 
 	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
-		nla_put_u32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
+		NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
 
 	if (tmpl->ce_mask & NEIGHTBL_ATTR_THRESH2)
-		nla_put_u32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
+		NLA_PUT_U32(m, NDTA_THRESH2, tmpl->nt_gc_thresh2);
 
 	if (tmpl->ce_mask & NEIGHTBL_ATTR_GC_INTERVAL)
-		nla_put_u64(m, NDTA_GC_INTERVAL,
+		NLA_PUT_U64(m, NDTA_GC_INTERVAL,
 				      tmpl->nt_gc_interval);
 
 	if (tmpl->ce_mask & NEIGHTBL_ATTR_PARMS) {
 		struct rtnl_neightbl_parms *p = &tmpl->nt_parms;
-		struct nl_msg *parms = nlmsg_alloc();
+
+		parms = nlmsg_alloc();
+		if (!parms)
+			goto nla_put_failure;
 
 		if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX)
-			nla_put_u32(parms, NDTPA_IFINDEX,
+			NLA_PUT_U32(parms, NDTPA_IFINDEX,
 					      old->nt_parms.ntp_ifindex);
 
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_QUEUE_LEN)
-			nla_put_u32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len);
+			NLA_PUT_U32(parms, NDTPA_QUEUE_LEN, p->ntp_queue_len);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_APP_PROBES)
-			nla_put_u32(parms, NDTPA_APP_PROBES, p->ntp_app_probes);
+			NLA_PUT_U32(parms, NDTPA_APP_PROBES, p->ntp_app_probes);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_UCAST_PROBES)
-			nla_put_u32(parms, NDTPA_UCAST_PROBES,
+			NLA_PUT_U32(parms, NDTPA_UCAST_PROBES,
 				    p->ntp_ucast_probes);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_MCAST_PROBES)
-			nla_put_u32(parms, NDTPA_MCAST_PROBES,
+			NLA_PUT_U32(parms, NDTPA_MCAST_PROBES,
 				    p->ntp_mcast_probes);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_QLEN)
-			nla_put_u32(parms, NDTPA_PROXY_QLEN,
+			NLA_PUT_U32(parms, NDTPA_PROXY_QLEN,
 				    p->ntp_proxy_qlen);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME)
-			nla_put_u64(parms, NDTPA_BASE_REACHABLE_TIME,
+			NLA_PUT_U64(parms, NDTPA_BASE_REACHABLE_TIME,
 				    p->ntp_base_reachable_time);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_RETRANS_TIME)
-			nla_put_u64(parms, NDTPA_RETRANS_TIME,
+			NLA_PUT_U64(parms, NDTPA_RETRANS_TIME,
 				    p->ntp_retrans_time);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_GC_STALETIME)
-			nla_put_u64(parms, NDTPA_GC_STALETIME,
+			NLA_PUT_U64(parms, NDTPA_GC_STALETIME,
 				    p->ntp_gc_stale_time);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME)
-			nla_put_u64(parms, NDTPA_DELAY_PROBE_TIME,
+			NLA_PUT_U64(parms, NDTPA_DELAY_PROBE_TIME,
 				    p->ntp_proxy_delay);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_ANYCAST_DELAY)
-			nla_put_u64(parms, NDTPA_ANYCAST_DELAY,
+			NLA_PUT_U64(parms, NDTPA_ANYCAST_DELAY,
 				    p->ntp_anycast_delay);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_PROXY_DELAY)
-			nla_put_u64(parms, NDTPA_PROXY_DELAY,
+			NLA_PUT_U64(parms, NDTPA_PROXY_DELAY,
 					      p->ntp_proxy_delay);
 
 		if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME)
-			nla_put_u64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
+			NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
 
-		nla_put_nested(m, NDTA_PARMS, parms);
+		if (nla_put_nested(m, NDTA_PARMS, parms) < 0)
+			goto nla_put_failure;
+
 		nlmsg_free(parms);
 	}
-	
-	return m;
+
+	*result = m;
+	return 0;
+
+nla_put_failure:
+	if (parms)
+		nlmsg_free(parms);
+	nlmsg_free(m);
+	return -NLE_MSGSIZE;
 }
 
 /**
@@ -578,12 +584,13 @@
 int rtnl_neightbl_change(struct nl_handle *handle, struct rtnl_neightbl *old,
 			 struct rtnl_neightbl *tmpl)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_neightbl_build_change_request(old, tmpl);
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0)
+		return err;
+
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c
index 2db6d90..e5348b0 100644
--- a/lib/route/nexthop.c
+++ b/lib/route/nexthop.c
@@ -39,10 +39,8 @@
 	struct rtnl_nexthop *nh;
 
 	nh = calloc(1, sizeof(*nh));
-	if (!nh) {
-		nl_errno(ENOMEM);
+	if (!nh)
 		return NULL;
-	}
 
 	nl_init_list_head(&nh->rtnh_list);
 
diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c
index bc89663..8b2de2f 100644
--- a/lib/route/qdisc.c
+++ b/lib/route/qdisc.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -98,13 +98,13 @@
 static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
 			    struct nlmsghdr *n, struct nl_parser_param *pp)
 {
-	int err = -ENOMEM;
+	int err;
 	struct rtnl_qdisc *qdisc;
 	struct rtnl_qdisc_ops *qops;
 
 	qdisc = rtnl_qdisc_alloc();
 	if (!qdisc) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
@@ -149,15 +149,15 @@
  * @{
  */
 
-static struct nl_msg *qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags)
+static int qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags,
+		       struct nl_msg **result)
 {
 	struct rtnl_qdisc_ops *qops;
-	struct nl_msg *msg;
 	int err;
 
-	msg = tca_build_msg((struct rtnl_tca *) qdisc, type, flags);
-	if (!msg)
-		goto errout;
+	err = tca_build_msg((struct rtnl_tca *) qdisc, type, flags, result);
+	if (err < 0)
+		return err;
 
 	qops = rtnl_qdisc_lookup_ops(qdisc);
 	if (qops && qops->qo_get_opts) {
@@ -165,7 +165,7 @@
 		
 		opts = qops->qo_get_opts(qdisc);
 		if (opts) {
-			err = nla_put_nested(msg, TCA_OPTIONS, opts);
+			err = nla_put_nested(*result, TCA_OPTIONS, opts);
 			nlmsg_free(opts);
 			if (err < 0)
 				goto errout;
@@ -175,22 +175,23 @@
 	 * accomodate for this, they can complete the message themselves.
 	 */		
 	else if (qops && qops->qo_build_msg) {
-		err = qops->qo_build_msg(qdisc, msg);
-		if ( err < 0 )
+		err = qops->qo_build_msg(qdisc, *result);
+		if (err < 0)
 			goto errout;
 	}
 
-	return msg;
+	return 0;
 errout:
-	nlmsg_free(msg);
+	nlmsg_free(*result);
 
-	return NULL;
+	return err;
 }
 
 /**
  * Build a netlink message to add a new qdisc
  * @arg qdisc		qdisc to add 
  * @arg flags		additional netlink message flags
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting an addition of a qdisc.
  * The netlink message header isn't fully equipped with all relevant
@@ -200,18 +201,12 @@
  * Common message flags used:
  *  - NLM_F_REPLACE - replace a potential existing qdisc
  *
- * @return New netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc,
-					    int flags)
+int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags,
+				 struct nl_msg **result)
 {
-	struct nl_msg *msg;
-
-	msg = qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags);
-	if (!msg)
-		nl_errno(ENOMEM);
-
-	return msg;
+	return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags, result);
 }
 
 /**
@@ -235,12 +230,10 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_qdisc_build_add_request(qdisc, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_qdisc_build_add_request(qdisc, flags, &msg)) < 0)
+		return err;
 
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -258,18 +251,20 @@
  * Build a netlink message to change attributes of a existing qdisc
  * @arg qdisc		qdisc to change
  * @arg new		new qdisc attributes
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting an change of qdisc
  * attributes. The netlink message header isn't fully equipped
  * with all relevant fields and must be sent out via
  * nl_send_auto_complete() or supplemented as needed. 
  *
- * @return New netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
-					       struct rtnl_qdisc *new)
+int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
+				    struct rtnl_qdisc *new,
+				    struct nl_msg **result)
 {
-	return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE);
+	return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE, result);
 }
 
 /**
@@ -290,12 +285,10 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_qdisc_build_change_request(qdisc, new);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_qdisc_build_change_request(qdisc, new, &msg)) < 0)
+		return err;
 
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -312,15 +305,17 @@
 /**
  * Build a netlink request message to delete a qdisc
  * @arg qdisc		qdisc to delete
+ * @arg result		Pointer to store resulting message.
  *
  * Builds a new netlink message requesting a deletion of a qdisc.
  * The netlink message header isn't fully equipped with all relevant
  * fields and must thus be sent out via nl_send_auto_complete()
  * or supplemented as needed.
  *
- * @return New netlink message
+ * @return 0 on success or a negative error code.
  */
-struct nl_msg *rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc)
+int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc,
+				    struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct tcmsg tchdr;
@@ -331,15 +326,19 @@
 
 	msg = nlmsg_alloc_simple(RTM_DELQDISC, 0);
 	if (!msg)
-		return NULL;
+		return -NLE_NOMEM;
 
-	tchdr.tcm_family = AF_UNSPEC,
-	tchdr.tcm_handle = qdisc->q_handle,
-	tchdr.tcm_parent = qdisc->q_parent,
-	tchdr.tcm_ifindex = qdisc->q_ifindex,
-	nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO);
+	tchdr.tcm_family = AF_UNSPEC;
+	tchdr.tcm_handle = qdisc->q_handle;
+	tchdr.tcm_parent = qdisc->q_parent;
+	tchdr.tcm_ifindex = qdisc->q_ifindex;
+	if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
+		nlmsg_free(msg);
+		return -NLE_MSGSIZE;
+	}
 
-	return msg;
+	*result = msg;
+	return 0;
 }
 
 /**
@@ -358,12 +357,10 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_qdisc_build_delete_request(qdisc);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_qdisc_build_delete_request(qdisc, &msg)) < 0)
+		return err;
 
-	err = nl_send_auto_complete(handle, msg);
-	if (err < 0)
+	if ((err = nl_send_auto_complete(handle, msg)) < 0)
 		return err;
 
 	nlmsg_free(msg);
@@ -380,29 +377,17 @@
 /**
  * Build a qdisc cache including all qdiscs currently configured in
  * the kernel
- * @arg handle		netlink handle
+ * @arg sock		netlink handle
+ * @arg result		Pointer to store resulting message.
  *
  * Allocates a new cache, initializes it properly and updates it to
  * include all qdiscs currently configured in the kernel.
  *
- * @note The caller is responsible for destroying and freeing the
- *       cache after using it.
- * @return The cache or NULL if an error has occured.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache * rtnl_qdisc_alloc_cache(struct nl_handle *handle)
+int rtnl_qdisc_alloc_cache(struct nl_handle *sock, struct nl_cache **result)
 {
-	struct nl_cache * cache;
-	
-	cache = nl_cache_alloc(&rtnl_qdisc_ops);
-	if (cache == NULL)
-		return NULL;
-
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		nl_cache_free(cache);
-		return NULL;
-	}
-
-	return cache;
+	return nl_cache_alloc_and_fill(&rtnl_qdisc_ops, sock, result);
 }
 
 /**
diff --git a/lib/route/qdisc_api.c b/lib/route/qdisc_api.c
index ef4d07a..089f212 100644
--- a/lib/route/qdisc_api.c
+++ b/lib/route/qdisc_api.c
@@ -46,7 +46,7 @@
 
 	for (op = &qdisc_ops_list; (o = *op) != NULL; op = &o->qo_next)
 		if (!strcasecmp(qops->qo_kind, o->qo_kind))
-			return nl_errno(EEXIST);
+			return -NLE_EXIST;
 
 	qops->qo_next = NULL;
 	*op = qops;
@@ -67,7 +67,7 @@
 			break;
 
 	if (!o)
-		return nl_errno(ENOENT);
+		return -NLE_OBJ_NOTFOUND;
 
 	*op = qops->qo_next;
 
diff --git a/lib/route/route.c b/lib/route/route.c
index 260d3e2..823d695 100644
--- a/lib/route/route.c
+++ b/lib/route/route.c
@@ -33,8 +33,8 @@
 	struct rtnl_route *route;
 	int err;
 
-	if (!(route = rtnl_route_parse(nlh)))
-		return -EINVAL;
+	if ((err = rtnl_route_parse(nlh, &route)) < 0)
+		return err;
 
 	if ((err = pp->pp_cb((struct nl_object *) route, pp)) < 0)
 		goto errout;
@@ -76,24 +76,25 @@
  *       cache after using it.
  * @return The cache or NULL if an error has occured.
  */
-struct nl_cache *rtnl_route_alloc_cache(struct nl_handle *handle,
-					int family, int flags)
+int rtnl_route_alloc_cache(struct nl_handle *handle, int family, int flags,
+			   struct nl_cache **result)
 {
 	struct nl_cache *cache;
+	int err;
 
-	cache = nl_cache_alloc(&rtnl_route_ops);
-	if (!cache)
-		return NULL;
+	if (!(cache = nl_cache_alloc(&rtnl_route_ops)))
+		return -NLE_NOMEM;
 
 	cache->c_iarg1 = family;
 	cache->c_iarg2 = flags;
 
-	if (handle && nl_cache_refill(handle, cache) < 0) {
+	if (handle && (err = nl_cache_refill(handle, cache)) < 0) {
 		free(cache);
-		return NULL;
+		return err;
 	}
 
-	return cache;
+	*result = cache;
+	return 0;
 }
 
 /** @} */
@@ -103,26 +104,29 @@
  * @{
  */
 
-static struct nl_msg *build_route_msg(struct rtnl_route *tmpl, int cmd,
-				      int flags)
+static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags,
+			   struct nl_msg **result)
 {
 	struct nl_msg *msg;
+	int err;
 
-	msg = nlmsg_alloc_simple(cmd, flags);
-	if (msg == NULL)
-		return NULL;
+	if (!(msg = nlmsg_alloc_simple(cmd, flags)))
+		return -NLE_NOMEM;
 
-	if (rtnl_route_build_msg(msg, tmpl) < 0) {
+	if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) {
 		nlmsg_free(msg);
-		return NULL;
+		return err;
 	}
 
-	return msg;
+	*result = msg;
+	return 0;
 }
 
-struct nl_msg *rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags)
+int rtnl_route_build_add_request(struct rtnl_route *tmpl, int flags,
+				 struct nl_msg **result)
 {
-	return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags);
+	return build_route_msg(tmpl, RTM_NEWROUTE, NLM_F_CREATE | flags,
+			       result);
 }
 
 int rtnl_route_add(struct nl_handle *handle, struct rtnl_route *route,
@@ -131,9 +135,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_route_build_add_request(route, flags);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(handle, msg);
 	nlmsg_free(msg);
@@ -143,9 +146,10 @@
 	return nl_wait_for_ack(handle);
 }
 
-struct nl_msg *rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags)
+int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags,
+				 struct nl_msg **result)
 {
-	return build_route_msg(tmpl, RTM_DELROUTE, flags);
+	return build_route_msg(tmpl, RTM_DELROUTE, flags, result);
 }
 
 int rtnl_route_delete(struct nl_handle *handle, struct rtnl_route *route,
@@ -154,9 +158,8 @@
 	struct nl_msg *msg;
 	int err;
 
-	msg = rtnl_route_build_del_request(route, flags);
-	if (!msg)
-		return nl_get_errno();
+	if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(handle, msg);
 	nlmsg_free(msg);
diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
index 200f561..2be6d62 100644
--- a/lib/route/route_obj.c
+++ b/lib/route/route_obj.c
@@ -100,28 +100,26 @@
 
 	if (src->rt_dst)
 		if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->rt_src)
 		if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->rt_pref_src)
 		if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	nl_init_list_head(&dst->rt_nexthops);
 	nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
 		new = rtnl_route_nh_clone(nh);
 		if (!new)
-			goto errout;
+			return -NLE_NOMEM;
 
 		rtnl_route_add_nexthop(dst, new);
 	}
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static int route_dump_oneline(struct nl_object *a, struct nl_dump_params *p)
@@ -559,8 +557,7 @@
 int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
 {
 	if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
-		return nl_error(EINVAL, "Unsupported address family, "
-		                "supported: { INET | INET6 | DECnet }");
+		return -NLE_AF_NOSUPPORT;
 
 	route->rt_family = family;
 	route->ce_mask |= ROUTE_ATTR_FAMILY;
@@ -577,7 +574,7 @@
 {
 	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
 		if (addr->a_family != route->rt_family)
-			return nl_error(EINVAL, "Address family mismatch");
+			return -NLE_AF_MISMATCH;
 	} else
 		route->rt_family = addr->a_family;
 
@@ -600,12 +597,11 @@
 int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
 {
 	if (addr->a_family == AF_INET)
-		return nl_error(EINVAL, "IPv4 does not support source based "
-				"routing.");
+		return -NLE_SRCRT_NOSUPPORT;
 
 	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
 		if (addr->a_family != route->rt_family)
-			return nl_error(EINVAL, "Address family mismatch");
+			return -NLE_AF_MISMATCH;
 	} else
 		route->rt_family = addr->a_family;
 
@@ -627,8 +623,8 @@
 int rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
 {
 	if (type > RTN_MAX)
-		return nl_error(ERANGE, "Invalid route type %d, valid range "
-				"is 0..%d", type, RTN_MAX);
+		return -NLE_RANGE;
+
 	route->rt_type = type;
 	route->ce_mask |= ROUTE_ATTR_TYPE;
 
@@ -662,8 +658,7 @@
 int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
 {
 	if (metric > RTAX_MAX || metric < 1)
-		return nl_error(EINVAL, "Metric out of range (1..%d)",
-		    RTAX_MAX);
+		return -NLE_RANGE;
 
 	route->rt_metrics[metric - 1] = value;
 
@@ -680,8 +675,7 @@
 int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
 {
 	if (metric > RTAX_MAX || metric < 1)
-		return nl_error(EINVAL, "Metric out of range (1..%d)",
-		    RTAX_MAX);
+		return -NLE_RANGE;
 
 	if (route->rt_metrics_mask & (1 << (metric - 1))) {
 		route->rt_nmetrics--;
@@ -694,11 +688,10 @@
 int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
 {
 	if (metric > RTAX_MAX || metric < 1)
-		return nl_error(EINVAL, "Metric out of range (1..%d)",
-		    RTAX_MAX);
+		return -NLE_RANGE;
 
 	if (!(route->rt_metrics_mask & (1 << (metric - 1))))
-		return nl_error(ENOENT, "Metric %d not available", metric);
+		return -NLE_OBJ_NOTFOUND;
 
 	if (value)
 		*value = route->rt_metrics[metric - 1];
@@ -710,7 +703,7 @@
 {
 	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
 		if (addr->a_family != route->rt_family)
-			return nl_error(EINVAL, "Address family mismatch");
+			return -NLE_AF_MISMATCH;
 	} else
 		route->rt_family = addr->a_family;
 
@@ -844,7 +837,7 @@
 	[RTA_MULTIPATH]	= { .type = NLA_NESTED },
 };
 
-struct rtnl_route *rtnl_route_parse(struct nlmsghdr *nlh)
+int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 {
 	struct rtmsg *rtm;
 	struct rtnl_route *route;
@@ -855,7 +848,7 @@
 
 	route = rtnl_route_alloc();
 	if (!route) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
@@ -1034,8 +1027,7 @@
 
 			if (rtnl_route_nh_compare(old_nh, first,
 						  old_nh->ce_mask, 0)) {
-				nl_error(EINVAL, "Mismatch of multipath "
-					"configuration.");
+				err = -NLE_INVAL;
 				goto errout;
 			}
 
@@ -1043,11 +1035,12 @@
 		}
 	}
 
-	return route;
+	*result = route;
+	return 0;
 
 errout:
 	rtnl_route_put(route);
-	return NULL;
+	return err;
 }
 
 int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
@@ -1065,8 +1058,7 @@
 	};
 
 	if (route->rt_dst == NULL)
-		return nl_error(EINVAL, "Cannot build route message, please "
-				"specify route destination.");
+		return -NLE_MISSING_ATTR;
 
 	rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
 	if (route->rt_src)
@@ -1145,7 +1137,7 @@
 	return 0;
 
 nla_put_failure:
-	return -ENOBUFS;
+	return -NLE_MSGSIZE;
 }
 
 /** @cond SKIP */
diff --git a/lib/route/rule.c b/lib/route/rule.c
index 0493818..8684cf2 100644
--- a/lib/route/rule.c
+++ b/lib/route/rule.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -60,15 +60,13 @@
 
 	if (src->r_src)
 		if (!(dst->r_src = nl_addr_clone(src->r_src)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	if (src->r_dst)
 		if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
-			goto errout;
+			return -NLE_NOMEM;
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 static struct nla_policy rule_policy[RTA_MAX+1] = {
@@ -89,7 +87,7 @@
 
 	rule = rtnl_rule_alloc();
 	if (!rule) {
-		err = nl_errno(ENOMEM);
+		err = -NLE_NOMEM;
 		goto errout;
 	}
 
@@ -118,7 +116,7 @@
 	if (tb[RTA_SRC]) {
 		rule->r_src = nla_get_addr(tb[RTA_SRC], r->rtm_family);
 		if (!rule->r_src) {
-			err = nl_errno(ENOMEM);
+			err = -NLE_NOMEM;
 			goto errout;
 		}
 		nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len);
@@ -128,7 +126,7 @@
 	if (tb[RTA_DST]) {
 		rule->r_dst = nla_get_addr(tb[RTA_DST], r->rtm_family);
 		if (!rule->r_dst) {
-			err = nl_errno(ENOMEM);
+			err = -NLE_NOMEM;
 			goto errout;
 		}
 		nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len);
@@ -153,7 +151,7 @@
 	if (tb[RTA_GATEWAY]) {
 		rule->r_srcmap = nla_get_addr(tb[RTA_GATEWAY], r->rtm_family);
 		if (!rule->r_srcmap) {
-			err = nl_errno(ENOMEM);
+			err = -NLE_NOMEM;
 			goto errout;
 		}
 		rule->ce_mask |= RULE_ATTR_SRCMAP;
@@ -440,51 +438,34 @@
  */
 
 /**
- * Build a rule cache including all rules of the specified family currently configured in the kernel.
- * @arg handle		netlink handle
- * @arg family		address family
- *
- * Allocates a new rule cache, initializes it properly and updates it
- * to include all rules of the specified address family currently
- * configured in the kernel.
- *
- * @note The caller is responsible for destroying and freeing the
- *       cache after using it. (nl_cache_destroy_and_free())
- * @return The new cache or NULL if an error occured.
- */
-struct nl_cache * rtnl_rule_alloc_cache_by_family(struct nl_handle *handle,
-						  int family)
-{
-	struct nl_cache * cache;
-
-	cache = nl_cache_alloc(&rtnl_rule_ops);
-	if (cache == NULL)
-		return NULL;
-
-	/* XXX RULE_CACHE_FAMILY(cache) = family; */
-
-	if (handle && nl_cache_refill(handle, cache) < 0) {
-		free(cache);
-		return NULL;
-	}
-
-	return cache;
-}
-
-/**
  * Build a rule cache including all rules currently configured in the kernel.
  * @arg handle		netlink handle
+ * @arg family		Address family or AF_UNSPEC.
+ * @arg result		Pointer to store resulting cache.
  *
  * Allocates a new rule cache, initializes it properly and updates it
  * to include all rules currently configured in the kernel.
  *
- * @note The caller is responsible for destroying and freeing the
- *       cache after using it. (nl_cache_destroy_and_free())
- * @return The new cache or NULL if an error occured.
+ * @return 0 on success or a negative error code.
  */
-struct nl_cache * rtnl_rule_alloc_cache(struct nl_handle *handle)
+int rtnl_rule_alloc_cache(struct nl_handle *sock, int family,
+			  struct nl_cache **result)
 {
-	return rtnl_rule_alloc_cache_by_family(handle, AF_UNSPEC);
+	struct nl_cache * cache;
+	int err;
+
+	if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
+		return -NLE_NOMEM;
+
+	cache->c_iarg1 = family;
+
+	if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
+		free(cache);
+		return err;
+	}
+
+	*result = cache;
+	return 0;
 }
 
 /** @} */
@@ -494,7 +475,8 @@
  * @{
  */
 
-static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags)
+static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
+			  struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct rtmsg rtm = {
@@ -524,7 +506,7 @@
 
 	msg = nlmsg_alloc_simple(cmd, flags);
 	if (!msg)
-		goto nla_put_failure;
+		return -NLE_NOMEM;
 
 	if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0)
 		goto nla_put_failure;
@@ -547,11 +529,12 @@
 	if (tmpl->ce_mask & RULE_ATTR_IIF)
 		NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif);
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
 /**
@@ -567,9 +550,11 @@
  * 
  * @return The netlink message
  */
-struct nl_msg *rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags)
+int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
+				struct nl_msg **result)
 {
-	return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags);
+	return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
+			      result);
 }
 
 /**
@@ -586,18 +571,17 @@
  */
 int rtnl_rule_add(struct nl_handle *handle, struct rtnl_rule *tmpl, int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_rule_build_add_request(tmpl, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(handle, msg);
+	nlmsg_free(msg);
 	if (err < 0)
 		return err;
 
-	nlmsg_free(msg);
 	return nl_wait_for_ack(handle);
 }
 
@@ -621,9 +605,10 @@
  *
  * @return The netlink message
  */
-struct nl_msg *rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags)
+int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
+				   struct nl_msg **result)
 {
-	return build_rule_msg(rule, RTM_DELRULE, flags);
+	return build_rule_msg(rule, RTM_DELRULE, flags, result);
 }
 
 /**
@@ -641,18 +626,17 @@
 int rtnl_rule_delete(struct nl_handle *handle, struct rtnl_rule *rule,
 		     int flags)
 {
-	int err;
 	struct nl_msg *msg;
+	int err;
 	
-	msg = rtnl_rule_build_delete_request(rule, flags);
-	if (!msg)
-		return nl_errno(ENOMEM);
+	if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
+		return err;
 
 	err = nl_send_auto_complete(handle, msg);
+	nlmsg_free(msg);
 	if (err < 0)
 		return err;
 
-	nlmsg_free(msg);
 	return nl_wait_for_ack(handle);
 }
 
@@ -770,7 +754,7 @@
 {
 	if (rule->ce_mask & RULE_ATTR_FAMILY) {
 		if (new->a_family != rule->r_family)
-			return nl_error(EINVAL, "Address family mismatch");
+			return -NLE_AF_MISMATCH;
 	} else
 		rule->r_family = new->a_family;
 
@@ -817,7 +801,7 @@
 int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
 {
 	if (strlen(dev) > IFNAMSIZ-1)
-		return nl_errno(ERANGE);
+		return -NLE_RANGE;
 
 	strcpy(rule->r_iif, dev);
 	rule->ce_mask |= RULE_ATTR_IIF;
@@ -843,7 +827,7 @@
 	if (rule->ce_mask & RULE_ATTR_TYPE)
 		return rule->r_type;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
diff --git a/lib/route/sch/cbq.c b/lib/route/sch/cbq.c
index 9808509..50fb7b2 100644
--- a/lib/route/sch/cbq.c
+++ b/lib/route/sch/cbq.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 #include <netlink-local.h>
@@ -99,7 +99,7 @@
 
 	cbq = cbq_alloc(tca);
 	if (!cbq)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss));
 	nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate));
@@ -133,7 +133,7 @@
 	struct rtnl_cbq *src = cbq_qdisc(_src);
 
 	if (src && !cbq_alloc(_dst))
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 	else
 		return 0;
 }
diff --git a/lib/route/sch/dsmark.c b/lib/route/sch/dsmark.c
index 5ba6b92..b0787a9 100644
--- a/lib/route/sch/dsmark.c
+++ b/lib/route/sch/dsmark.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -70,7 +70,7 @@
 
 	dsmark = dsmark_qdisc_alloc(qdisc);
 	if (!dsmark)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (tb[TCA_DSMARK_INDICES]) {
 		dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]);
@@ -118,7 +118,7 @@
 
 	dsmark = dsmark_class_alloc(class);
 	if (!dsmark)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (tb[TCA_DSMARK_MASK]) {
 		dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]);
@@ -251,7 +251,7 @@
 	
 	dsmark = dsmark_class(class);
 	if (!dsmark)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	dsmark->cdm_bmask = mask;
 	dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
@@ -272,7 +272,7 @@
 	if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
 		return dsmark->cdm_bmask;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -287,7 +287,7 @@
 
 	dsmark = dsmark_class(class);
 	if (!dsmark)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	dsmark->cdm_value = value;
 	dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
@@ -308,7 +308,7 @@
 	if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
 		return dsmark->cdm_value;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
@@ -329,7 +329,7 @@
 
 	dsmark = dsmark_qdisc(qdisc);
 	if (!dsmark)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	dsmark->qdm_indices = indices;
 	dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
@@ -350,7 +350,7 @@
 	if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
 		return dsmark->qdm_indices;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -366,7 +366,7 @@
 
 	dsmark = dsmark_qdisc(qdisc);
 	if (!dsmark)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	dsmark->qdm_default_index = default_index;
 	dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
@@ -387,7 +387,7 @@
 	if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
 		return dsmark->qdm_default_index;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -402,7 +402,7 @@
 
 	dsmark = dsmark_qdisc(qdisc);
 	if (!dsmark)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	dsmark->qdm_set_tc_index = !!flag;
 	dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
@@ -424,7 +424,7 @@
 	if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
 		return dsmark->qdm_set_tc_index;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
diff --git a/lib/route/sch/fifo.c b/lib/route/sch/fifo.c
index 4f8d202..a8953f9 100644
--- a/lib/route/sch/fifo.c
+++ b/lib/route/sch/fifo.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -60,11 +60,11 @@
 	struct tc_fifo_qopt *opt;
 
 	if (qdisc->q_opts->d_size < sizeof(struct tc_fifo_qopt))
-		return nl_error(EINVAL, "FIFO options size mismatch");
+		return -NLE_INVAL;
 
 	fifo = fifo_alloc(qdisc);
 	if (!fifo)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	opt = (struct tc_fifo_qopt *) qdisc->q_opts->d_data;
 	fifo->qf_limit = opt->limit;
@@ -148,7 +148,7 @@
 	
 	fifo = fifo_alloc(qdisc);
 	if (!fifo)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 		
 	fifo->qf_limit = limit;
 	fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT;
@@ -169,7 +169,7 @@
 	if (fifo && fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)
 		return fifo->qf_limit;
 	else
-		return nl_errno(ENOMEM);
+		return -NLE_NOATTR;
 }
 
 /** @} */
diff --git a/lib/route/sch/netem.c b/lib/route/sch/netem.c
index cb9eca7..34a3d14 100644
--- a/lib/route/sch/netem.c
+++ b/lib/route/sch/netem.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -69,11 +69,11 @@
 	struct tc_netem_qopt *opts;
 
 	if (qdisc->q_opts->d_size < sizeof(*opts))
-		return nl_error(EINVAL, "Netem specific options size mismatch");
+		return -NLE_INVAL;
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	opts = (struct tc_netem_qopt *) qdisc->q_opts->d_data;
 	netem->qnm_latency = opts->latency;
@@ -202,56 +202,48 @@
 	
 	if ( netem->qnm_ro.nmro_probability != 0 ) {
 		if (netem->qnm_latency == 0) {
-			return nl_error(EINVAL,
-				"netem: Specified reorder gap without latency.");
+			return -NLE_MISSING_ATTR;
 		}
 		if (netem->qnm_gap == 0) netem->qnm_gap = 1;
 	}
 	else if ( netem->qnm_gap ) { 
-		return nl_error(EINVAL,
-			"netem: Specified reorder gap without reorder probability.");
+		return -NLE_MISSING_ATTR;
 	}
 
 	if ( netem->qnm_corr.nmc_delay != 0 ) {
 		if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
-			return nl_error(EINVAL,
-				"netem: Specified delay correlation without delay size / jitter.");
+			return -NLE_MISSING_ATTR;
 		}
 		set_correlation = 1;
 	}
 	
 	if ( netem->qnm_corr.nmc_loss != 0 ) {
 		if ( netem->qnm_loss == 0 ) {
-			return nl_error(EINVAL,
-				"netem: Specified loss correlation without loss probability.");
+			return -NLE_MISSING_ATTR;
 		}
 		set_correlation = 1;
 	}
 
 	if ( netem->qnm_corr.nmc_duplicate != 0 ) {
 		if ( netem->qnm_duplicate == 0 ) {
-			return nl_error(EINVAL,
-				"netem: Specified dup correlation without duplication probability.");
+			return -NLE_MISSING_ATTR;
 		}
 		set_correlation = 1;
 	}
 	
 	if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1;
 	else if ( netem->qnm_ro.nmro_correlation != 0 ) {
-			return nl_error(EINVAL,
-				"netem: Specified reorder correlation without reorder probability.");
+			return -NLE_MISSING_ATTR;
 	}
 	
 	if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1;
 	else if ( netem->qnm_crpt.nmcr_correlation != 0 ) {
-			return nl_error(EINVAL,
-				"netem: Specified corrupt correlation without corrupt probability.");
+			return -NLE_MISSING_ATTR;
 	}
 	
 	if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) {
 		if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
-		return nl_error(EINVAL, 
-			"netem: Distribution specified with empty latency and jitter values.");
+			return -NLE_MISSING_ATTR;
 	}
 	else {
 		/* Resize to accomodate the large distribution table */
@@ -260,8 +252,7 @@
 		
 		msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len);
 		if ( msg->nm_nlh == NULL )
-			return nl_error(ENOMEM, 
-				"netem: Unable to reallocate message size to contain delay distribution data.");
+			return -NLE_NOMEM;
 		msg->nm_size = new_msg_len;
 			set_dist = 1;
 		}
@@ -274,44 +265,34 @@
 	opts.duplicate = netem->qnm_duplicate;
 	opts.jitter = netem->qnm_jitter;
 	
-	err = nla_put(msg, TCA_OPTIONS, sizeof(opts), &opts);
-	if (err)
-		return nl_error(err, "netem: Unable to add TCA_OPTIONS to nl_msg.");
+	NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts);
 	
 	if ( set_correlation ) {
 		cor.delay_corr = netem->qnm_corr.nmc_delay;
 		cor.loss_corr = netem->qnm_corr.nmc_loss;
 		cor.dup_corr = netem->qnm_corr.nmc_duplicate;
 
-		err = nla_put(msg, TCA_NETEM_CORR, sizeof(cor), &cor);
-		if (err)
-			return nl_error(err, "netem: Unable to add TCA_NETEM_CORR to nl_msg.");
+		NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor);
 	}
 	
 	if ( set_reorder ) {
 		reorder.probability = netem->qnm_ro.nmro_probability;
 		reorder.correlation = netem->qnm_ro.nmro_correlation;
 
-		err = nla_put(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
-		if (err)
-			return nl_error(err, "netem: Unable to add TCA_NETEM_REORDER to nl_msg.");
+		NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
 	}
 	
 	if ( set_corrupt ) {
 		corrupt.probability = netem->qnm_crpt.nmcr_probability;
 		corrupt.correlation = netem->qnm_crpt.nmcr_correlation;
 
-		err = nla_put(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
-		if (err)
-			return nl_error(err, "netem: Unable to add TCA_NETEM_CORRUPT to nl_msg.");
+		NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
 	}
 	
 	if ( set_dist ) {
-		err = nla_put(msg, TCA_NETEM_DELAY_DIST,
+		NLA_PUT(msg, TCA_NETEM_DELAY_DIST,
 			netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]),
 			netem->qnm_dist.dist_data);
-		if (err)
-			return nl_error(err, "netem: Unable to add TCA_NETEM_DELAY_DIST to nl_msg.");
 	}
 
 	/* Length specified in the TCA_OPTIONS section must span the entire
@@ -329,6 +310,8 @@
 	msg->nm_nlh->nlmsg_len += (head->nla_len - old_len);
 	
 	return err;
+nla_put_failure:
+	return -NLE_MSGSIZE;
 }
 
 /**
@@ -348,7 +331,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 	
 	netem->qnm_limit = limit;
 	netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT;
@@ -369,7 +352,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT))
 		return netem->qnm_limit;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
@@ -391,7 +374,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_gap = gap;
 	netem->qnm_mask |= SCH_NETEM_ATTR_GAP;
@@ -412,7 +395,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_GAP))
 		return netem->qnm_gap;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -427,7 +410,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_ro.nmro_probability = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB;
@@ -448,7 +431,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB))
 		return netem->qnm_ro.nmro_probability;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -463,7 +446,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_ro.nmro_correlation = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR;
@@ -484,7 +467,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR))
 		return netem->qnm_ro.nmro_correlation;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
@@ -506,7 +489,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_crpt.nmcr_probability = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB;
@@ -527,7 +510,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB))
 		return netem->qnm_crpt.nmcr_probability;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -542,7 +525,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_crpt.nmcr_correlation = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR;
@@ -563,7 +546,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR))
 		return netem->qnm_crpt.nmcr_correlation;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
@@ -585,7 +568,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_loss = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_LOSS;
@@ -606,7 +589,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS))
 		return netem->qnm_loss;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -621,7 +604,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_corr.nmc_loss = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR;
@@ -642,7 +625,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR))
 		return netem->qnm_corr.nmc_loss;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
@@ -664,7 +647,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_duplicate = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE;
@@ -685,7 +668,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE))
 		return netem->qnm_duplicate;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -700,7 +683,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_corr.nmc_duplicate = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR;
@@ -721,7 +704,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR))
 		return netem->qnm_corr.nmc_duplicate;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
@@ -743,7 +726,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_latency = nl_us2ticks(delay);
 	netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY;
@@ -764,7 +747,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY))
 		return nl_ticks2us(netem->qnm_latency);
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -779,7 +762,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_jitter = nl_us2ticks(jitter);
 	netem->qnm_mask |= SCH_NETEM_ATTR_JITTER;
@@ -800,7 +783,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_JITTER))
 		return nl_ticks2us(netem->qnm_jitter);
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -814,7 +797,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	netem->qnm_corr.nmc_delay = prob;
 	netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR;
@@ -835,7 +818,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR))
 		return netem->qnm_corr.nmc_delay;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -851,7 +834,7 @@
 	if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DIST))
 		return netem->qnm_dist.dist_size;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -870,7 +853,7 @@
 		return 0;
 	}
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -884,7 +867,7 @@
 
 	netem = netem_alloc(qdisc);
 	if (!netem)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 		
 	FILE *f = NULL;
 	int i, n = 0;
@@ -906,7 +889,8 @@
 		f = fopen(name, "r");
 	}
 	
-	if ( f == NULL ) return nl_error(errno, "netem: Unable to open distribution file.");
+	if ( f == NULL )
+		return -nl_syserr2nlerr(errno);
 	
 	netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
 	
@@ -925,7 +909,7 @@
 			if (n >= MAXDIST) {
 				free(line);
 				fclose(f);
-				return nl_error(EINVAL,	"netem: Distribution file too long.");
+				return -NLE_INVAL;
 			}
 			netem->qnm_dist.dist_data[n++] = x;
 		}		
diff --git a/lib/route/sch/prio.c b/lib/route/sch/prio.c
index 4e3d624..cd5526c 100644
--- a/lib/route/sch/prio.c
+++ b/lib/route/sch/prio.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -58,11 +58,11 @@
 	struct tc_prio_qopt *opt;
 
 	if (qdisc->q_opts->d_size < sizeof(*opt))
-		return nl_error(EINVAL, "prio specific option size mismatch");
+		return -NLE_INVAL;
 
 	prio = prio_alloc(qdisc);
 	if (!prio)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	opt = (struct tc_prio_qopt *) qdisc->q_opts->d_data;
 	prio->qp_bands = opt->bands;
@@ -173,7 +173,7 @@
 	
 	prio = prio_alloc(qdisc);
 	if (!prio)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	prio->qp_bands = bands;
 	prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
@@ -194,7 +194,7 @@
 	if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS)
 		return prio->qp_bands;
 	else
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 }
 
 /**
@@ -212,18 +212,17 @@
 
 	prio = prio_alloc(qdisc);
 	if (!prio)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
-		return nl_error(EINVAL, "Set number of bands first");
+		return -NLE_MISSING_ATTR;
 
 	if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
-		return nl_error(ERANGE, "priomap length out of bounds");
+		return -NLE_RANGE;
 
 	for (i = 0; i <= TC_PRIO_MAX; i++) {
 		if (priomap[i] > prio->qp_bands)
-			return nl_error(ERANGE, "priomap element %d " \
-			    "out of bounds, increase bands number");
+			return -NLE_RANGE;
 	}
 
 	memcpy(prio->qp_priomap, priomap, len);
@@ -245,10 +244,8 @@
 	prio = prio_qdisc(qdisc);
 	if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
 		return prio->qp_priomap;
-	else {
-		nl_errno(ENOENT);
+	else
 		return NULL;
-	}
 }
 
 /** @} */
diff --git a/lib/route/sch/red.c b/lib/route/sch/red.c
index a31c358..40481de 100644
--- a/lib/route/sch/red.c
+++ b/lib/route/sch/red.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -66,11 +66,11 @@
 		return err;
 
 	if (!tb[TCA_RED_PARMS])
-		return nl_error(EINVAL, "Missing TCA_RED_PARMS");
+		return -NLE_MISSING_ATTR;
 
 	red = red_alloc(qdisc);
 	if (!red)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	opts = nla_data(tb[TCA_RED_PARMS]);
 
@@ -171,7 +171,7 @@
 
 	red = red_alloc(qdisc);
 	if (!red)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	red->qr_limit = limit;
 	red->qr_mask |= RED_ATTR_LIMIT;
@@ -192,7 +192,7 @@
 	if (red && (red->qr_mask & RED_ATTR_LIMIT))
 		return red->qr_limit;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
diff --git a/lib/route/sch/sfq.c b/lib/route/sch/sfq.c
index d530c0f..eaac58b 100644
--- a/lib/route/sch/sfq.c
+++ b/lib/route/sch/sfq.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -61,11 +61,11 @@
 		return 0;
 
 	if (qdisc->q_opts->d_size < sizeof(*opts))
-		return nl_error(EINVAL, "SFQ specific options size mismatch");
+		return -NLE_INVAL;
 
 	sfq = sfq_alloc(qdisc);
 	if (!sfq)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data;
 
@@ -157,7 +157,7 @@
 	
 	sfq = sfq_alloc(qdisc);
 	if (!sfq)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	sfq->qs_quantum = quantum;
 	sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
@@ -178,7 +178,7 @@
 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
 		return sfq->qs_quantum;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -193,7 +193,7 @@
 
 	sfq = sfq_alloc(qdisc);
 	if (!sfq)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	sfq->qs_limit = limit;
 	sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
@@ -214,7 +214,7 @@
 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
 		return sfq->qs_limit;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -230,7 +230,7 @@
 
 	sfq = sfq_alloc(qdisc);
 	if (!sfq)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	sfq->qs_perturb = perturb;
 	sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
@@ -251,7 +251,7 @@
 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
 		return sfq->qs_perturb;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /**
@@ -267,7 +267,7 @@
 	if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
 		return sfq->qs_divisor;
 	else
-		return nl_errno(ENOENT);
+		return -NLE_NOATTR;
 }
 
 /** @} */
diff --git a/lib/route/sch/tbf.c b/lib/route/sch/tbf.c
index 8dd5e0a..a23c338 100644
--- a/lib/route/sch/tbf.c
+++ b/lib/route/sch/tbf.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -64,7 +64,7 @@
 	
 	tbf = tbf_alloc(q);
 	if (!tbf)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (tb[TCA_TBF_PARMS]) {
 		struct tc_tbf_qopt opts;
@@ -226,7 +226,7 @@
 	
 	tbf = tbf_alloc(qdisc);
 	if (!tbf)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	tbf->qt_limit = limit;
 	tbf->qt_mask |= TBF_ATTR_LIMIT;
@@ -270,11 +270,10 @@
 
 	tbf = tbf_alloc(qdisc);
 	if (!tbf)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	if (!(tbf->qt_mask & TBF_ATTR_RATE))
-		return nl_error(EINVAL, "The rate must be specified before "
-				"limit can be calculated based on latency.");
+		return -NLE_MISSING_ATTR;
 
 	limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
 
@@ -301,8 +300,8 @@
 	tbf = tbf_qdisc(qdisc);
 	if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT))
 		return tbf->qt_limit;
-	return
-		nl_errno(ENOENT);
+	else
+		return -NLE_NOATTR;
 }
 
 /**
@@ -317,7 +316,7 @@
 	
 	tbf = tbf_alloc(qdisc);
 	if (!tbf)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	tbf->qt_mpu = mpu;
 	tbf->qt_mask |= TBF_ATTR_MPU;
@@ -337,8 +336,8 @@
 	tbf = tbf_qdisc(qdisc);
 	if (tbf && (tbf->qt_mask & TBF_ATTR_MPU))
 		return tbf->qt_mpu;
-	return
-		nl_errno(ENOENT);
+	else
+		return -NLE_NOATTR;
 }
 
 static inline int calc_cell_log(int cell, int bucket)
@@ -374,7 +373,7 @@
 	
 	tbf = tbf_alloc(qdisc);
 	if (!tbf)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	cell_log = calc_cell_log(cell, bucket);
 	if (cell_log < 0)
@@ -453,7 +452,7 @@
 	
 	tbf = tbf_alloc(qdisc);
 	if (!tbf)
-		return nl_errno(ENOMEM);
+		return -NLE_NOMEM;
 
 	cell_log = calc_cell_log(cell, bucket);
 	if (cell_log < 0)
diff --git a/lib/route/tc.c b/lib/route/tc.c
index 1351fa2..1114eac 100644
--- a/lib/route/tc.c
+++ b/lib/route/tc.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -66,7 +66,7 @@
 		return err;
 
 	if (tb[TCA_KIND] == NULL)
-		return nl_error(EINVAL, "Missing tca kind TLV");
+		return -NLE_MISSING_ATTR;
 
 	nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ);
 
@@ -83,7 +83,7 @@
 	if (tb[TCA_OPTIONS]) {
 		g->tc_opts = nla_get_data(tb[TCA_OPTIONS]);
 		if (!g->tc_opts)
-			return nl_errno(ENOMEM);
+			return -NLE_NOMEM;
 		g->ce_mask |= TCA_ATTR_OPTS;
 	}
 	
@@ -128,7 +128,7 @@
 		if (tbs[TCA_STATS_APP]) {
 			g->tc_xstats = nla_get_data(tbs[TCA_STATS_APP]);
 			if (g->tc_xstats == NULL)
-				return -ENOMEM;
+				return -NLE_NOMEM;
 		} else
 			goto compat_xstats;
 	} else {
@@ -151,7 +151,7 @@
 		if (tb[TCA_XSTATS]) {
 			g->tc_xstats = nla_get_data(tb[TCA_XSTATS]);
 			if (g->tc_xstats == NULL)
-				return -ENOMEM;
+				return -NLE_NOMEM;
 			g->ce_mask |= TCA_ATTR_XSTATS;
 		}
 	}
@@ -171,18 +171,16 @@
 	if (src->tc_opts) {
 		dst->tc_opts = nl_data_clone(src->tc_opts);
 		if (!dst->tc_opts)
-			goto errout;
+			return -NLE_NOMEM;
 	}
 	
 	if (src->tc_xstats) {
 		dst->tc_xstats = nl_data_clone(src->tc_xstats);
 		if (!dst->tc_xstats)
-			goto errout;
+			return -NLE_NOMEM;
 	}
 
 	return 0;
-errout:
-	return nl_get_errno();
 }
 
 int tca_dump_brief(struct rtnl_tca *g, const char *type,
@@ -332,7 +330,8 @@
 	return t->tc_stats[id];
 }
 
-struct nl_msg *tca_build_msg(struct rtnl_tca *tca, int type, int flags)
+int tca_build_msg(struct rtnl_tca *tca, int type, int flags,
+		  struct nl_msg **result)
 {
 	struct nl_msg *msg;
 	struct tcmsg tchdr = {
@@ -344,7 +343,7 @@
 
 	msg = nlmsg_alloc_simple(type, flags);
 	if (!msg)
-		goto nla_put_failure;
+		return -NLE_NOMEM;
 
 	if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
 		goto nla_put_failure;
@@ -352,11 +351,12 @@
 	if (tca->ce_mask & TCA_ATTR_KIND)
 	    NLA_PUT_STRING(msg, TCA_KIND, tca->tc_kind);
 
-	return msg;
+	*result = msg;
+	return 0;
 
 nla_put_failure:
 	nlmsg_free(msg);
-	return NULL;
+	return -NLE_MSGSIZE;
 }
 
 /** @endcond */
@@ -425,7 +425,7 @@
 		if ((1 << i) == cell_size)
 			return i;
 
-	return nl_errno(EINVAL);
+	return -NLE_INVAL;
 }
 
 
@@ -546,13 +546,13 @@
 		/* :YYYY */
 		h = 0;
 		if (':' != *colon)
-			return -EINVAL;
+			return -NLE_INVAL;
 	}
 
 	if (':' == *colon) {
 		/* check if we would lose bits */
 		if (TC_H_MAJ(h))
-			return -ERANGE;
+			return -NLE_RANGE;
 		h <<= 16;
 
 		if ('\0' == colon[1]) {
@@ -564,10 +564,10 @@
 
 			/* check if we overlap with major part */
 			if (TC_H_MAJ(l))
-				return -ERANGE;
+				return -NLE_RANGE;
 
 			if ('\0' != *end)
-				return -EINVAL;
+				return -NLE_INVAL;
 
 			*res = (h | l);
 		}
@@ -575,7 +575,7 @@
 		/* XXXXYYYY */
 		*res = h;
 	} else
-		return -EINVAL;
+		return -NLE_INVAL;
 
 	return 0;
 }
diff --git a/lib/socket.c b/lib/socket.c
index aae8f54..088cd10 100644
--- a/lib/socket.c
+++ b/lib/socket.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -166,10 +166,8 @@
 	struct nl_handle *handle;
 
 	handle = calloc(1, sizeof(*handle));
-	if (!handle) {
-		nl_errno(ENOMEM);
+	if (!handle)
 		return NULL;
-	}
 
 	handle->h_fd = -1;
 	handle->h_cb = cb;
@@ -179,7 +177,6 @@
 	handle->h_local.nl_pid = generate_local_port();
 	if (handle->h_local.nl_pid == UINT_MAX) {
 		nl_handle_destroy(handle);
-		nl_error(ENOBUFS, "Out of local ports");
 		return NULL;
 	}
 
@@ -196,10 +193,8 @@
 	struct nl_cb *cb;
 	
 	cb = nl_cb_alloc(default_cb);
-	if (!cb) {
-		nl_errno(ENOMEM);
+	if (!cb)
 		return NULL;
-	}
 
 	return __alloc_handle(cb);
 }
@@ -345,13 +340,12 @@
 	int err;
 
 	if (handle->h_fd == -1)
-		return nl_error(EBADFD, "Socket not connected");
+		return -NLE_BAD_SOCK;
 
 	err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
 			 &group, sizeof(group));
 	if (err < 0)
-		return nl_error(errno, "setsockopt(NETLINK_ADD_MEMBERSHIP) "
-				       "failed");
+		return -nl_syserr2nlerr(errno);
 
 	return 0;
 }
@@ -372,13 +366,12 @@
 	int err;
 
 	if (handle->h_fd == -1)
-		return nl_error(EBADFD, "Socket not connected");
+		return -NLE_BAD_SOCK;
 
 	err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
 			 &group, sizeof(group));
 	if (err < 0)
-		return nl_error(errno, "setsockopt(NETLINK_DROP_MEMBERSHIP) "
-				       "failed");
+		return -nl_syserr2nlerr(errno);
 
 	return 0;
 }
@@ -436,10 +429,10 @@
 int nl_socket_set_nonblocking(struct nl_handle *handle)
 {
 	if (handle->h_fd == -1)
-		return nl_error(EBADFD, "Socket not connected");
+		return -NLE_BAD_SOCK;
 
 	if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0)
-		return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed");
+		return -nl_syserr2nlerr(errno);
 
 	return 0;
 }
@@ -528,17 +521,17 @@
 		txbuf = 32768;
 
 	if (handle->h_fd == -1)
-		return nl_error(EBADFD, "Socket not connected");
+		return -NLE_BAD_SOCK;
 	
 	err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF,
 			 &txbuf, sizeof(txbuf));
 	if (err < 0)
-		return nl_error(errno, "setsockopt(SO_SNDBUF) failed");
+		return -nl_syserr2nlerr(errno);
 
 	err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF,
 			 &rxbuf, sizeof(rxbuf));
 	if (err < 0)
-		return nl_error(errno, "setsockopt(SO_RCVBUF) failed");
+		return -nl_syserr2nlerr(errno);
 
 	handle->h_flags |= NL_SOCK_BUFSIZE_SET;
 
@@ -557,12 +550,12 @@
 	int err;
 
 	if (handle->h_fd == -1)
-		return nl_error(EBADFD, "Socket not connected");
+		return -NLE_BAD_SOCK;
 
 	err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED,
 			 &state, sizeof(state));
 	if (err < 0)
-		return nl_error(errno, "setsockopt(SO_PASSCRED) failed");
+		return -nl_syserr2nlerr(errno);
 
 	if (state)
 		handle->h_flags |= NL_SOCK_PASSCRED;
@@ -584,12 +577,12 @@
 	int err;
 
 	if (handle->h_fd == -1)
-		return nl_error(EBADFD, "Socket not connected");
+		return -NLE_BAD_SOCK;
 
 	err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO,
 			 &state, sizeof(state));
 	if (err < 0)
-		return nl_error(errno, "setsockopt(NETLINK_PKTINFO) failed");
+		return -nl_syserr2nlerr(errno);
 
 	return 0;
 }
diff --git a/lib/utils.c b/lib/utils.c
index db11fb8..5c4c476 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -6,7 +6,7 @@
  *	License as published by the Free Software Foundation version 2.1
  *	of the License.
  *
- * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
  */
 
 /**
@@ -41,48 +41,6 @@
 	nl_debug_dp.dp_fd = stderr;
 }
 
-/**
- * @name Error Code Helpers
- * @{
- */
-
-static char *errbuf;
-static int nlerrno;
-
-/** @cond SKIP */
-int __nl_error(int err, const char *file, unsigned int line, const char *func,
-	       const char *fmt, ...)
-{
-	char *user_err;
-	va_list args;
-
-	if (errbuf) {
-		free(errbuf);
-		errbuf = NULL;
-	}
-
-	nlerrno = err;
-
-	if (fmt) {
-		va_start(args, fmt);
-		vasprintf(&user_err, fmt, args);
-		va_end(args);
-	}
-
-#ifdef VERBOSE_ERRORS
-	asprintf(&errbuf, "%s:%u:%s: %s (errno = %s)",
-		 file, line, func, fmt ? user_err : "", strerror(err));
-#else
-	asprintf(&errbuf, "%s (errno = %s)",
-		 fmt ? user_err : "", strerror(err));
-#endif
-
-	if (fmt)
-		free(user_err);
-
-	return -err;
-}
-
 int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
 {
 	FILE *fd;
@@ -90,8 +48,7 @@
 
 	fd = fopen(path, "r");
 	if (fd == NULL)
-		return nl_error(errno, "Unable to open file %s for reading",
-				path);
+		return -nl_syserr2nlerr(errno);
 
 	while (fgets(buf, sizeof(buf), fd)) {
 		int goodlen, err;
@@ -103,17 +60,17 @@
 
 		num = strtol(buf, &end, 0);
 		if (end == buf)
-			return nl_error(EINVAL, "Parsing error");
+			return -NLE_INVAL;
 
 		if (num == LONG_MIN || num == LONG_MAX)
-			return nl_error(errno, "Number of out range");
+			return -NLE_RANGE;
 
 		while (*end == ' ' || *end == '\t')
 			end++;
 
 		goodlen = strcspn(end, "#\r\n\t ");
 		if (goodlen == 0)
-			return nl_error(EINVAL, "Empty string");
+			return -NLE_INVAL;
 
 		end[goodlen] = '\0';
 
@@ -127,49 +84,6 @@
 	return 0;
 }
 
-/** @endcond */
-
-int nl_get_errno(void)
-{
-	return nlerrno;
-}
-
-
-/**
- * Return error message for an error code
- * @return error message
- */
-char *nl_geterror(void)
-{
-	if (errbuf)
-		return errbuf;
-
-	if (nlerrno)
-		return strerror(nlerrno);
-
-	return "Success\n";
-}
-
-/**
- * Print a libnl error message
- * @arg s		error message prefix
- *
- * Prints the error message of the call that failed last.
- *
- * If s is not NULL and *s is not a null byte the argument
- * string is printed, followed by a colon and a blank. Then
- * the error message and a new-line.
- */
-void nl_perror(const char *s)
-{
-	if (s && *s)
-		fprintf(stderr, "%s: %s\n", s, nl_geterror());
-	else
-		fprintf(stderr, "%s\n", nl_geterror());
-}
-
-/** @} */
-
 /**
  * @name Unit Pretty-Printing
  * @{