Imported Upstream version 3.2.22 upstream upstream/3.2.22
authorArron Wang <arron.wang@intel.com>
Mon, 21 Oct 2013 03:11:55 +0000 (11:11 +0800)
committerArron Wang <arron.wang@intel.com>
Mon, 21 Oct 2013 03:11:55 +0000 (11:11 +0800)
355 files changed:
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
build-aux/ar-lib [new file with mode: 0755]
build-aux/compile [new file with mode: 0755]
build-aux/config.guess [new file with mode: 0755]
build-aux/config.sub [new file with mode: 0755]
build-aux/depcomp [new file with mode: 0755]
build-aux/install-sh [new file with mode: 0755]
build-aux/ltmain.sh [new file with mode: 0644]
build-aux/missing [new file with mode: 0755]
configure [new file with mode: 0755]
configure.ac [new file with mode: 0644]
etc/classid [new file with mode: 0644]
etc/pktloc [new file with mode: 0644]
include/Makefile.am [new file with mode: 0644]
include/Makefile.in [new file with mode: 0644]
include/linux/can/netlink.h [new file with mode: 0644]
include/linux/fib_rules.h [new file with mode: 0644]
include/linux/gen_stats.h [new file with mode: 0644]
include/linux/genetlink.h [new file with mode: 0644]
include/linux/if.h [new file with mode: 0644]
include/linux/if_addr.h [new file with mode: 0644]
include/linux/if_arp.h [new file with mode: 0644]
include/linux/if_bridge.h [new file with mode: 0644]
include/linux/if_ether.h [new file with mode: 0644]
include/linux/if_link.h [new file with mode: 0644]
include/linux/if_vlan.h [new file with mode: 0644]
include/linux/inetdevice.h [new file with mode: 0644]
include/linux/ip_mp_alg.h [new file with mode: 0644]
include/linux/ipv6.h [new file with mode: 0644]
include/linux/neighbour.h [new file with mode: 0644]
include/linux/netfilter.h [new file with mode: 0644]
include/linux/netfilter/nf_conntrack_common.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink_compat.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink_conntrack.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink_log.h [new file with mode: 0644]
include/linux/netfilter/nfnetlink_queue.h [new file with mode: 0644]
include/linux/netlink.h [new file with mode: 0644]
include/linux/pkt_cls.h [new file with mode: 0644]
include/linux/pkt_sched.h [new file with mode: 0644]
include/linux/rtnetlink.h [new file with mode: 0644]
include/linux/snmp.h [new file with mode: 0644]
include/linux/tc_ematch/tc_em_meta.h [new file with mode: 0644]
include/netlink-private/cache-api.h [new file with mode: 0644]
include/netlink-private/genl.h [new file with mode: 0644]
include/netlink-private/netlink.h [new file with mode: 0644]
include/netlink-private/object-api.h [new file with mode: 0644]
include/netlink-private/route/link/api.h [new file with mode: 0644]
include/netlink-private/route/tc-api.h [new file with mode: 0644]
include/netlink-private/tc.h [new file with mode: 0644]
include/netlink-private/types.h [new file with mode: 0644]
include/netlink/addr.h [new file with mode: 0644]
include/netlink/attr.h [new file with mode: 0644]
include/netlink/cache-api.h [new file with mode: 0644]
include/netlink/cache.h [new file with mode: 0644]
include/netlink/cli/addr.h [new file with mode: 0644]
include/netlink/cli/class.h [new file with mode: 0644]
include/netlink/cli/cls.h [new file with mode: 0644]
include/netlink/cli/ct.h [new file with mode: 0644]
include/netlink/cli/exp.h [new file with mode: 0644]
include/netlink/cli/link.h [new file with mode: 0644]
include/netlink/cli/neigh.h [new file with mode: 0644]
include/netlink/cli/qdisc.h [new file with mode: 0644]
include/netlink/cli/route.h [new file with mode: 0644]
include/netlink/cli/rule.h [new file with mode: 0644]
include/netlink/cli/tc.h [new file with mode: 0644]
include/netlink/cli/utils.h [new file with mode: 0644]
include/netlink/data.h [new file with mode: 0644]
include/netlink/errno.h [new file with mode: 0644]
include/netlink/fib_lookup/lookup.h [new file with mode: 0644]
include/netlink/fib_lookup/request.h [new file with mode: 0644]
include/netlink/genl/ctrl.h [new file with mode: 0644]
include/netlink/genl/family.h [new file with mode: 0644]
include/netlink/genl/genl.h [new file with mode: 0644]
include/netlink/genl/mngt.h [new file with mode: 0644]
include/netlink/handlers.h [new file with mode: 0644]
include/netlink/hash.h [new file with mode: 0644]
include/netlink/hashtable.h [new file with mode: 0644]
include/netlink/list.h [new file with mode: 0644]
include/netlink/msg.h [new file with mode: 0644]
include/netlink/netfilter/ct.h [new file with mode: 0644]
include/netlink/netfilter/exp.h [new file with mode: 0644]
include/netlink/netfilter/log.h [new file with mode: 0644]
include/netlink/netfilter/log_msg.h [new file with mode: 0644]
include/netlink/netfilter/netfilter.h [new file with mode: 0644]
include/netlink/netfilter/nfnl.h [new file with mode: 0644]
include/netlink/netfilter/queue.h [new file with mode: 0644]
include/netlink/netfilter/queue_msg.h [new file with mode: 0644]
include/netlink/netlink-compat.h [new file with mode: 0644]
include/netlink/netlink-kernel.h [new file with mode: 0644]
include/netlink/netlink.h [new file with mode: 0644]
include/netlink/object-api.h [new file with mode: 0644]
include/netlink/object.h [new file with mode: 0644]
include/netlink/route/addr.h [new file with mode: 0644]
include/netlink/route/class.h [new file with mode: 0644]
include/netlink/route/classifier.h [new file with mode: 0644]
include/netlink/route/cls/basic.h [new file with mode: 0644]
include/netlink/route/cls/cgroup.h [new file with mode: 0644]
include/netlink/route/cls/ematch.h [new file with mode: 0644]
include/netlink/route/cls/ematch/cmp.h [new file with mode: 0644]
include/netlink/route/cls/ematch/meta.h [new file with mode: 0644]
include/netlink/route/cls/ematch/nbyte.h [new file with mode: 0644]
include/netlink/route/cls/ematch/text.h [new file with mode: 0644]
include/netlink/route/cls/fw.h [new file with mode: 0644]
include/netlink/route/cls/police.h [new file with mode: 0644]
include/netlink/route/cls/u32.h [new file with mode: 0644]
include/netlink/route/link.h [new file with mode: 0644]
include/netlink/route/link/api.h [new file with mode: 0644]
include/netlink/route/link/bonding.h [new file with mode: 0644]
include/netlink/route/link/bridge.h [new file with mode: 0644]
include/netlink/route/link/can.h [new file with mode: 0644]
include/netlink/route/link/inet.h [new file with mode: 0644]
include/netlink/route/link/info-api.h [new file with mode: 0644]
include/netlink/route/link/vlan.h [new file with mode: 0644]
include/netlink/route/neighbour.h [new file with mode: 0644]
include/netlink/route/neightbl.h [new file with mode: 0644]
include/netlink/route/nexthop.h [new file with mode: 0644]
include/netlink/route/pktloc.h [new file with mode: 0644]
include/netlink/route/qdisc.h [new file with mode: 0644]
include/netlink/route/qdisc/cbq.h [new file with mode: 0644]
include/netlink/route/qdisc/dsmark.h [new file with mode: 0644]
include/netlink/route/qdisc/fifo.h [new file with mode: 0644]
include/netlink/route/qdisc/htb.h [new file with mode: 0644]
include/netlink/route/qdisc/netem.h [new file with mode: 0644]
include/netlink/route/qdisc/plug.h [new file with mode: 0644]
include/netlink/route/qdisc/prio.h [new file with mode: 0644]
include/netlink/route/qdisc/red.h [new file with mode: 0644]
include/netlink/route/qdisc/sfq.h [new file with mode: 0644]
include/netlink/route/qdisc/tbf.h [new file with mode: 0644]
include/netlink/route/route.h [new file with mode: 0644]
include/netlink/route/rtnl.h [new file with mode: 0644]
include/netlink/route/rule.h [new file with mode: 0644]
include/netlink/route/tc-api.h [new file with mode: 0644]
include/netlink/route/tc.h [new file with mode: 0644]
include/netlink/socket.h [new file with mode: 0644]
include/netlink/types.h [new file with mode: 0644]
include/netlink/utils.h [new file with mode: 0644]
include/netlink/version.h [new file with mode: 0644]
include/netlink/version.h.in [new file with mode: 0644]
lib/Makefile.am [new file with mode: 0644]
lib/Makefile.in [new file with mode: 0644]
lib/addr.c [new file with mode: 0644]
lib/attr.c [new file with mode: 0644]
lib/cache.c [new file with mode: 0644]
lib/cache_mngr.c [new file with mode: 0644]
lib/cache_mngt.c [new file with mode: 0644]
lib/cli/cls/basic.c [new file with mode: 0644]
lib/cli/cls/cgroup.c [new file with mode: 0644]
lib/cli/qdisc/bfifo.c [new file with mode: 0644]
lib/cli/qdisc/blackhole.c [new file with mode: 0644]
lib/cli/qdisc/htb.c [new file with mode: 0644]
lib/cli/qdisc/pfifo.c [new file with mode: 0644]
lib/cli/qdisc/plug.c [new file with mode: 0644]
lib/data.c [new file with mode: 0644]
lib/defs.h.in [new file with mode: 0644]
lib/error.c [new file with mode: 0644]
lib/fib_lookup/lookup.c [new file with mode: 0644]
lib/fib_lookup/request.c [new file with mode: 0644]
lib/genl/ctrl.c [new file with mode: 0644]
lib/genl/family.c [new file with mode: 0644]
lib/genl/genl.c [new file with mode: 0644]
lib/genl/mngt.c [new file with mode: 0644]
lib/handlers.c [new file with mode: 0644]
lib/hash.c [new file with mode: 0644]
lib/hashtable.c [new file with mode: 0644]
lib/msg.c [new file with mode: 0644]
lib/netfilter/ct.c [new file with mode: 0644]
lib/netfilter/ct_obj.c [new file with mode: 0644]
lib/netfilter/exp.c [new file with mode: 0644]
lib/netfilter/exp_obj.c [new file with mode: 0644]
lib/netfilter/log.c [new file with mode: 0644]
lib/netfilter/log_msg.c [new file with mode: 0644]
lib/netfilter/log_msg_obj.c [new file with mode: 0644]
lib/netfilter/log_obj.c [new file with mode: 0644]
lib/netfilter/netfilter.c [new file with mode: 0644]
lib/netfilter/nfnl.c [new file with mode: 0644]
lib/netfilter/queue.c [new file with mode: 0644]
lib/netfilter/queue_msg.c [new file with mode: 0644]
lib/netfilter/queue_msg_obj.c [new file with mode: 0644]
lib/netfilter/queue_obj.c [new file with mode: 0644]
lib/nl.c [new file with mode: 0644]
lib/object.c [new file with mode: 0644]
lib/route/addr.c [new file with mode: 0644]
lib/route/class.c [new file with mode: 0644]
lib/route/classid.c [new file with mode: 0644]
lib/route/cls.c [new file with mode: 0644]
lib/route/cls/basic.c [new file with mode: 0644]
lib/route/cls/cgroup.c [new file with mode: 0644]
lib/route/cls/ematch.c [new file with mode: 0644]
lib/route/cls/ematch/cmp.c [new file with mode: 0644]
lib/route/cls/ematch/container.c [new file with mode: 0644]
lib/route/cls/ematch/meta.c [new file with mode: 0644]
lib/route/cls/ematch/nbyte.c [new file with mode: 0644]
lib/route/cls/ematch/text.c [new file with mode: 0644]
lib/route/cls/ematch_grammar.l [new file with mode: 0644]
lib/route/cls/ematch_syntax.y [new file with mode: 0644]
lib/route/cls/fw.c [new file with mode: 0644]
lib/route/cls/police.c [new file with mode: 0644]
lib/route/cls/u32.c [new file with mode: 0644]
lib/route/link.c [new file with mode: 0644]
lib/route/link/api.c [new file with mode: 0644]
lib/route/link/bonding.c [new file with mode: 0644]
lib/route/link/bridge.c [new file with mode: 0644]
lib/route/link/can.c [new file with mode: 0644]
lib/route/link/dummy.c [new file with mode: 0644]
lib/route/link/inet.c [new file with mode: 0644]
lib/route/link/inet6.c [new file with mode: 0644]
lib/route/link/vlan.c [new file with mode: 0644]
lib/route/neigh.c [new file with mode: 0644]
lib/route/neightbl.c [new file with mode: 0644]
lib/route/nexthop.c [new file with mode: 0644]
lib/route/pktloc.c [new file with mode: 0644]
lib/route/pktloc_grammar.l [new file with mode: 0644]
lib/route/pktloc_syntax.y [new file with mode: 0644]
lib/route/qdisc.c [new file with mode: 0644]
lib/route/qdisc/blackhole.c [new file with mode: 0644]
lib/route/qdisc/cbq.c [new file with mode: 0644]
lib/route/qdisc/dsmark.c [new file with mode: 0644]
lib/route/qdisc/fifo.c [new file with mode: 0644]
lib/route/qdisc/htb.c [new file with mode: 0644]
lib/route/qdisc/netem.c [new file with mode: 0644]
lib/route/qdisc/plug.c [new file with mode: 0644]
lib/route/qdisc/prio.c [new file with mode: 0644]
lib/route/qdisc/red.c [new file with mode: 0644]
lib/route/qdisc/sfq.c [new file with mode: 0644]
lib/route/qdisc/tbf.c [new file with mode: 0644]
lib/route/route.c [new file with mode: 0644]
lib/route/route_obj.c [new file with mode: 0644]
lib/route/route_utils.c [new file with mode: 0644]
lib/route/rtnl.c [new file with mode: 0644]
lib/route/rule.c [new file with mode: 0644]
lib/route/tc.c [new file with mode: 0644]
lib/socket.c [new file with mode: 0644]
lib/utils.c [new file with mode: 0644]
lib/version.c [new file with mode: 0644]
libnl-3.0.pc.in [new file with mode: 0644]
libnl-cli-3.0.pc.in [new file with mode: 0644]
libnl-genl-3.0.pc.in [new file with mode: 0644]
libnl-nf-3.0.pc.in [new file with mode: 0644]
libnl-route-3.0.pc.in [new file with mode: 0644]
m4/libtool.m4 [new file with mode: 0644]
m4/ltoptions.m4 [new file with mode: 0644]
m4/ltsugar.m4 [new file with mode: 0644]
m4/ltversion.m4 [new file with mode: 0644]
m4/lt~obsolete.m4 [new file with mode: 0644]
man/Makefile.am [new file with mode: 0644]
man/Makefile.in [new file with mode: 0644]
man/genl-ctrl-list.8 [new file with mode: 0644]
man/nl-classid-lookup.8 [new file with mode: 0644]
man/nl-pktloc-lookup.8 [new file with mode: 0644]
man/nl-qdisc-add.8 [new file with mode: 0644]
man/nl-qdisc-delete.8 [new file with mode: 0644]
man/nl-qdisc-list.8 [new file with mode: 0644]
python/Makefile.am [new file with mode: 0644]
python/Makefile.in [new file with mode: 0644]
python/README [new file with mode: 0644]
python/netlink/Makefile.am [new file with mode: 0644]
python/netlink/Makefile.in [new file with mode: 0644]
python/netlink/__init__.py [new file with mode: 0644]
python/netlink/capi.i [new file with mode: 0644]
python/netlink/core.py [new file with mode: 0644]
python/netlink/fixes.h [new file with mode: 0644]
python/netlink/route/Makefile.am [new file with mode: 0644]
python/netlink/route/Makefile.in [new file with mode: 0644]
python/netlink/route/__init__.py [new file with mode: 0644]
python/netlink/route/address.py [new file with mode: 0644]
python/netlink/route/capi.i [new file with mode: 0644]
python/netlink/route/link.py [new file with mode: 0644]
python/netlink/route/links/__init__.py [new file with mode: 0644]
python/netlink/route/links/dummy.py [new file with mode: 0644]
python/netlink/route/links/inet.py [new file with mode: 0644]
python/netlink/route/links/vlan.py [new file with mode: 0644]
python/netlink/route/qdisc/__init__.py [new file with mode: 0644]
python/netlink/route/qdisc/htb.py [new file with mode: 0644]
python/netlink/route/tc.py [new file with mode: 0644]
python/netlink/util.py [new file with mode: 0644]
python/setup.py.in [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/Makefile.in [new file with mode: 0644]
src/genl-ctrl-list.c [new file with mode: 0644]
src/lib/Makefile.am [new file with mode: 0644]
src/lib/Makefile.in [new file with mode: 0644]
src/lib/addr.c [new file with mode: 0644]
src/lib/class.c [new file with mode: 0644]
src/lib/cls.c [new file with mode: 0644]
src/lib/ct.c [new file with mode: 0644]
src/lib/exp.c [new file with mode: 0644]
src/lib/link.c [new file with mode: 0644]
src/lib/neigh.c [new file with mode: 0644]
src/lib/qdisc.c [new file with mode: 0644]
src/lib/route.c [new file with mode: 0644]
src/lib/rule.c [new file with mode: 0644]
src/lib/tc.c [new file with mode: 0644]
src/lib/utils.c [new file with mode: 0644]
src/nf-ct-list.c [new file with mode: 0644]
src/nf-exp-add.c [new file with mode: 0644]
src/nf-exp-delete.c [new file with mode: 0644]
src/nf-exp-list.c [new file with mode: 0644]
src/nf-log.c [new file with mode: 0644]
src/nf-monitor.c [new file with mode: 0644]
src/nf-queue.c [new file with mode: 0644]
src/nl-addr-add.c [new file with mode: 0644]
src/nl-addr-delete.c [new file with mode: 0644]
src/nl-addr-list.c [new file with mode: 0644]
src/nl-class-add.c [new file with mode: 0644]
src/nl-class-delete.c [new file with mode: 0644]
src/nl-class-list.c [new file with mode: 0644]
src/nl-classid-lookup.c [new file with mode: 0644]
src/nl-cls-add.c [new file with mode: 0644]
src/nl-cls-delete.c [new file with mode: 0644]
src/nl-cls-list.c [new file with mode: 0644]
src/nl-fib-lookup.c [new file with mode: 0644]
src/nl-link-enslave.c [new file with mode: 0644]
src/nl-link-ifindex2name.c [new file with mode: 0644]
src/nl-link-list.c [new file with mode: 0644]
src/nl-link-name2ifindex.c [new file with mode: 0644]
src/nl-link-release.c [new file with mode: 0644]
src/nl-link-set.c [new file with mode: 0644]
src/nl-link-stats.c [new file with mode: 0644]
src/nl-list-caches.c [new file with mode: 0644]
src/nl-list-sockets.c [new file with mode: 0644]
src/nl-monitor.c [new file with mode: 0644]
src/nl-neigh-add.c [new file with mode: 0644]
src/nl-neigh-delete.c [new file with mode: 0644]
src/nl-neigh-list.c [new file with mode: 0644]
src/nl-neightbl-list.c [new file with mode: 0644]
src/nl-pktloc-lookup.c [new file with mode: 0644]
src/nl-qdisc-add.c [new file with mode: 0644]
src/nl-qdisc-delete.c [new file with mode: 0644]
src/nl-qdisc-list.c [new file with mode: 0644]
src/nl-route-add.c [new file with mode: 0644]
src/nl-route-delete.c [new file with mode: 0644]
src/nl-route-get.c [new file with mode: 0644]
src/nl-route-list.c [new file with mode: 0644]
src/nl-rule-list.c [new file with mode: 0644]
src/nl-tctree-list.c [new file with mode: 0644]
src/nl-util-addr.c [new file with mode: 0644]
tests/Makefile.am [new file with mode: 0644]
tests/Makefile.in [new file with mode: 0644]
tests/check-addr.c [new file with mode: 0644]
tests/check-all.c [new file with mode: 0644]
tests/check-attr.c [new file with mode: 0644]
tests/test-cache-mngr.c [new file with mode: 0644]
tests/test-complex-HTB-with-hash-filters.c [new file with mode: 0644]
tests/test-create-bond.c [new file with mode: 0644]
tests/test-create-vlan.c [new file with mode: 0644]
tests/test-delete-link.c [new file with mode: 0644]
tests/test-genl.c [new file with mode: 0644]
tests/test-nf-cache-mngr.c [new file with mode: 0644]
tests/test-socket-creation.c [new file with mode: 0644]
tests/util.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..4362b49
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..cdd78a8
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,336 @@
+ChangeLog discontinued, git history can be found here:
+http://git.infradead.org/users/tgr/libnl.git
+
+Summary of Changes from 1.0-pre6 to 1.0-pre7
+================================================
+       Thomas Graf <tgraf@suug.ch>
+         o Generic netlink support
+         o Route Addition/Deletion
+         o Added nl_cache_subset()
+         o Have nl_object_clone() make real clones without
+           sharing any data.
+         o Remove old nl_object_alloc() not based on a object
+           operations to avoid bugs due to missing init.
+         o Added nl-list-caches utility
+         o Removed nlmsg_build_no_hdr(), duplicate
+         o Reworked message interface
+         o Fixed nlmsg_put() and genlmsg_put() to correctly reserve
+           tail room for user specific headers.
+         o Added nl_cache_move()
+         o Renamed nl_cache_delete() to nl_cache_remove() (no API break)
+         o Fixed reference counting while objects stay in caches.
+         o Object marking
+         o Moved attribute mask for objects into generic structure
+         o nl-list-caches: List available dump procedures
+         o Use PAGE_SIZE as initial buffer size when reading from
+           netlink socket
+         o Double buffer size when recv() returns MSG_TRUNC
+         o Replaced filter object operation with new compare operation
+           capable of listing differences between two objects
+         o Added nl_object_identical() to check if two objects are
+           identical from a uniqueness point of view
+         o Added nl_object_diff() returning a bitmask of differences in
+           attributes
+         o Added nl_object_attr_list() generating a list of attribute
+           name the object has assigned 
+         o Cache updates based on event notifications, code based on
+           Patrick McHardy's patches
+         o Cache Manager
+         o Added NL_AUTO_PID, NL_AUTO_SEQ for convenience
+         o Disable MSG_PEEK by default and provide nl_socket_enable_msg_peek()
+         o Fixed nl_recvmsgs() to return 0 when interrupted via NL_STOP or
+           NL_SKIP
+         o Fixed nl_recvmsgs() to stop reading after parsing if not in the
+           middle of a multipart message.
+         o Fixed nl_recvmsgs() to not stop after receving an ACK
+         o Fixed nl_recvmsgs() to not blindly discard remaining messages
+           if a NLMSG_DONE message is received.
+       
+       Petr Gotthard <petr.gotthard@siemens.com>
+       Siemens AG Oesterreich
+         o Fix u32 to properly handle multiple keys
+         o rtnl_htb_set_(r|c)buffer()
+         o Fixed MTU handling in HTB class, problem pointed out
+           by Edouard Thuleau
+       
+       Zilvinas Valinskas <zilvinas@wilibox.com>
+         o Fix wrong msg_namelen in nl_recv()
+         o Fix memory leak in flnl_request_put()
+
+       Helmut Schaa <hschaa@suse.de>
+         o Fix for using libnl from within C++
+
+       Patrick McHardy <kaber@trash.net>
+         o *_alloc_cache(): Only refill cache if handle is provided
+       
+       James Oakley <jfunk@funktronics.ca>
+         o Fix rtnl_link_set_arptype() typo
+
+       Philip Craig <philipc@snapgear.com>
+         o Change address family type from char to int
+         o Fix the error handling when the build fails.
+         o add nl_cache_mngr_get_fd()
+         o add netfilter support
+         o add netfilter conntrack support
+         o add netfilter log support
+
+Summary of Changes from 1.0-pre5 to 1.0-pre6
+================================================
+       Christopher Aillon <caillon@redhat.com>
+         o Use $(libdir) instead of $(prefix)/lib for 64bit awesomeness.
+
+       Thomas Graf <tgraf@suug.ch>
+         o Extend nl_msg to include source address, destination address
+           and the protocol being used.
+         o Make nl_send*() take a nl_msg instead of a nlmsghdr (API BREAK)
+         o Change callbacks to take a nl_msg instead of source address
+           and nlmsghdr (API BREAK)
+         o caches must specify the protocol they're hooked up from now on
+           if they intend to be associated with message types.
+         o cache_mngt_associate now takes the protocol besides the message
+           type to allow for multiple protocols to be supported (API BREAK)
+         o overwrite destination address in nl_send() when specified in the
+           message itself, allows for unbound addressing.
+         o Support for netlink based fib_lookup()
+         o Documentation fixes
+         o Fix double nlmsg_free() in nl_recvmsgs() while receiving
+           a multipart message and the read was interrupted.
+         o Change cache operations to store names for message types.
+         o Provide interface to convert message type to character string.
+         o Add dp_dump_msgtype to prefix each dumped element with a
+           pretty printed message type.
+         o netlink fib lookup support
+         o nl_recvmsgs() debugging
+         o use nl_cachemngt_type2name() when pretty printing netlink header
+         o Routing protocol translations.
+         o Routing metric translations.
+         o Revised route dumping
+         o Nexthop flag translations.
+         o Add support for IFF_DORMANT
+
+       Petr Gotthard <petr.gotthard@siemens.com>
+       Siemens AG Oesterreich
+         o Fix access to obj after freeing it
+         o Fix u32 selector access after realloc() 
+         o Fix missing out-of-memory error handling in various places
+         o Enhance nl-monitor to have group selection selectable and
+           demonstrate usage of select()
+         o Don't ignore IFF_RUNNING any longer
+         o fw classifier support
+       
+       Patrick McHardy <kaber@trash.net>
+         o Fix conflicting types for __u64
+         o Fix printf format string warnings
+         o Fix object cloning
+         o Deal with structure padding in nl_object_clone
+         o Fix nl_addr leak
+         o Set ce_msgtype in all parsed objects
+         o Fix addr flag filter
+         o Fix RTNLGRP definitions (was based on broken kernel version)
+         o Export nl_get_errno()
+         o Add function to get/set peer pid
+         o Add IFF_LOWER_UP
+         o Add/export some missing accessor functions
+         o print /0 prefix in nl_addr2str()
+         o Fix invalid free in nl_addr_parse for AF_UNSPEC addresses
+         o Use __str2flags instead of __str2type in rtnl_link_str2flags()
+         o Make sure object and filter types match in nl_object_match()
+         o Add support for credential passing over netlink sockets (API BREAK)
+         o Add support for custom dump callbacks
+         o Add NL_DUMP_ENV format
+
+       Michael Biebl <biebl@teco.edu>
+       "Alex V. Myltsev" <avm@altlinux.ru>
+         o Makefile fixes
+
+
+Summary of Changes from 1.0-pre4 to 1.0-pre5
+================================================
+       Thomas Graf <tgraf@suug.ch>
+         o Use minimized local copies for <linux/if.h>, <linux/if_arp.h>,
+           and <linux/if_ether.h> to avoid compile troubles with
+           applications including <net/if*.h>
+           Reported by Christopher Aillon.
+
+Summary of Changes from 1.0-pre3 to 1.0-pre4
+================================================
+       Thomas Graf <tgraf@suug.ch>
+         o Fix wrong rtnl_addr_set_prefixlen() external declaration,
+           reported by Dan Williams.
+         o Fix nl_addr_parse() to not change the original string
+           for prefixes.
+         o Do not build documentation per default, but have the user
+           issue 'make gendoc'
+         o Assume neighbours to be permanent, set NUD_PERMANENT if not
+           specified otherwise.
+
+Summary of Changes from 1.0-pre2 to 1.0-pre3
+================================================
+       Thomas Graf <tgraf@suug.ch>
+         o Fix SFQ parser to allocate qdisc options.
+         o Fix rule statistics dumping to not call itself.
+         o Complete Netem qdisc interface.
+         o Add rtnl_*_put() and rtnl_*_free() to increase readability.
+         o Cleanup of nl-* tools
+         o Fix inclusion guards of route/neightbl.h
+         o Fix nl_connect() to only modify rx/tx socket buffers if not
+           already modified by the user.
+         o Fix wrong nl_handle_alloc() prototype.
+         o Fix typo in route/addr.c causing label to be marked as
+           local address.
+         o Use ~0UL as default prefix length instead of 0.
+         o Fix neighbour message parser to correctly store core.
+           attributes and provide them again.
+         o Fix neighbour message parser to correctly guess address family.
+           to make it compatible with nl_addr_parse() and ether llc
+           addresses.
+         o Add rtnl_route_table2str(), rtnl_route_str2table().
+         o Add nl_cache_nitems_filter() to find out if a filter produces
+           any matches.
+         o Remove rtnl_rule_set_(dst|src)_str() (obsolete).
+         o Remove scope and protocol field of routing rule.
+         o Complete routing rules module.
+         o Move realms translations from route to rtnl module.
+
+Summary of Changes from 1.0-pre1 to 1.0-pre2
+================================================
+       Thomas Graf <tgraf@suug.ch>
+         o More API documentation
+         o Added flags argument to rtnl_addr_(add|build_add_request)().
+         o Added rtnl_addr_(set|get)_multicast().
+         o Moved scope translations routines from route/route.c to
+           route/rtnl.c, required by other modules as well.
+         o Removed old rtattr bits from rtnetlink-kernel.h
+         o Customized libnl.css for doxygen documentation
+         o Removed non-reentrant translation routines, only bloating
+           the code and too risky.
+         o Fixed wrong version number from 1.0-pre1.
+         o Reenabled unfinished policer module.
+         o Reworked TBF module, automatic caluclation of transmit times,
+           limit setable via latency, automatic cell size calculation,
+           options TLV generation. (untested)
+         o Renamed nl_xmittime() to rtnl_tc_calc_txtime().
+         o Renamde nl_build_rtable() to rtnl_tc_build_rate_table()
+
+       Petr Gotthard <petr.gotthard@siemens.com>,
+       Siemens AG Oesterreich
+         o Fix symlinks to libnl library files to be moveable
+         o Fix extern struct prototypes meant to be static.
+         o Add empty install target to src/Makefile
+
+       Simon Stelling <blubb@gentoo.org>
+         o Use LIBDIR instead of $(prefix)/lib for users to alllow librariers
+           into $(prefix)/lib64.
+
+Summary of Changes from 0.5.0 to 1.0-pre1
+================================================
+       Thomas Graf <tgraf@suug.ch>
+         o Uncountable number of changes, rewrite of certain modules,
+           several major API breakages
+       
+       Petr Gotthard <petr.gotthard@siemens.com>,
+       Siemens AG Oesterreich
+         o added class_build, rtnl_class_build_add_request, rtnl_class_add
+         o added HTB (Hierachical Token Bucket) class support
+         o added nl_xmittime, nl_build_rtable
+         o added nl_data_append to realloc a nl_data structure
+         o added rtnl_rcopy_ratespec as reverse to rtnl_copy_ratespec
+         o fixed byte order conversion of rtnl_filter.protocol
+         o SuSE and Fedora Linux compile fixes
+         o fixed u32 classifier support
+         o added rtnl_u32_set_handle, rtnl_u32_set_classid, rtnl_u32_set_flags
+           and several rtnl_u32_add_key_... operations to u32 classifier
+
+Summary of Changes from 0.4.4 to 0.5.0
+================================================
+       Thomas Graf <tgraf@suug.ch>
+         o API documentation
+         o nl_cache_filter to manually filter on a object
+         o partial routing support
+         o routing rules support
+         o Propely set address family when setting addresses
+         o debug flag and some rare messages, more to come
+         o make error mesage verboseness configureable
+         o tc fixes to wait for ack
+         o cleanup and adaption of address code to latest internal API
+         o various cleanups
+         o dozens of API breakages (better now than later)
+
+       Daniel Hottinger <hotti@hotti.ch>
+         o arch 64bit printf length modifier fixes
+
+       Baruch Even <baruch@ev-en.org>,
+       Mediatrix Telecom, inc. <ericb@mediatrix.com>
+         o address support
+
+Summary of changes from 0.4.3 to 0.4.4
+================================================
+       Thomas Graf <tgraf@suug.ch>:
+         o overall cleanups for better code quality
+         o replace dump_(brief|full|with_stats) ops with
+           dump[NL_DUMP_MAX] array to allow further additions without
+           breaking the ABI.
+         o add of send_ack callback, called whenever when oppenent
+           asks for an ACK.
+         o make nl_parse_rtattr initialize the tb buffer like in the
+           kernel, caller must no longer take care of it.
+         o remove nl_addrnattr (obsolete)
+         o fixed nl_msg_append_raw to correctly calculate length
+           for raw data not aligned to NLMSG_ALIGN
+         o fix memory leak in nl_recv in case of errors
+         o correctly check sequence numbers if more than one message
+           was sent out before the answer is being received.
+         o add workaround for buggy netlink applications not properly
+           setting NLM_F_MULTI.
+
+Summary of changes from 0.4.2 to 0.4.3
+================================================
+
+       Thomas Graf <tgraf@suug.ch>:
+         o use parser_param in nl_cache_parse
+         o EGP: dump nfilters attribute
+         o allow retrieving of filters attached to classes via
+           FILTER_CACHE_PARENT(C) cache argument
+         o filter message building API
+
+Summary of changes from 0.4.1 to 0.4.2
+================================================
+
+       Baruch Even <baruch@ev-en.org>:
+         o memory leak fix in nl_parse_rtattr
+         o reset padding to 0 when appending raw data to a nl_msg
+         o avoid overwriting nlmsg ptr when buffer extending fails
+         o typo fixes
+         o create symlinks libnl.so.0 and libnl.so
+       
+       Thomas Graf <tgraf@suug.ch>:
+         o EGP classifier support
+         o avoid null pointer in printf call
+         o added nl_cache_parse to put nl_msg's into a cache
+         o added rtnl_filter_build to build a nl_msg filter message
+         o correctly install header files
+         o nl_msg_payload/nl_msg_payloadlen to access nl_msg payload
+         o nl_parse_nested macro to simplify nested TLV parsing
+         o NL_ERROR_ASSERT compile flag to assert(0) on errors
+         o rta alignment fix in nl_msg_append_tlv
+         o added nl_msg_parse_rtattr as shortcut for nl_parse_rtattr
+           for nl_msg API
+         o added nl_parse_nested for nested TLVs
+         o added RTA_ARRAY_ELEMS macro to calculate array length
+           for array TLVs
+         o added nl_wait_for_ack to wait for the next ack
+         o added rtnl_link_build_change_request(...)
+         o added rtnl_neigh_build_*_request
+         o converted neighbour code to use nl_wait_for_ack
+         o cb_recvmsgs_ow callback to overwrite internal calls to
+           nl_recvmsgs_def
+         o cb_seq_check callback to overwrite default sequence checking
+         o added nl_parser_param as argument for message parsers including
+           a callback to be called upon successful parsing of a message.
+           Removes the requirement of having all parsed messages to be added
+           to a cache.
+         o added cb_recv_ow and nl_send_ow callbacks to overwrite internal
+           calls to nl_recv and nl_send.
+
+       Jamal Hadi Salim <hadi@cyberus.ca>
+         o Linux 2.4 compile fixes
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..bc4266d
--- /dev/null
@@ -0,0 +1,22 @@
+# -*- Makefile -*-
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = include lib man python tests
+
+pkgconfig_DATA = libnl-3.0.pc \
+                libnl-route-3.0.pc \
+                libnl-genl-3.0.pc \
+                libnl-nf-3.0.pc
+
+if ENABLE_CLI
+SUBDIRS += src
+pkgconfig_DATA += libnl-cli-3.0.pc
+endif
+
+
+pkgsysconfdir = ${sysconfdir}/libnl
+pkgsysconf_DATA = etc/pktloc etc/classid
+
+EXTRA_DIST = \
+       $(pkgsysconf_DATA)
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..03c8d14
--- /dev/null
@@ -0,0 +1,874 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@ENABLE_CLI_TRUE@am__append_1 = src
+@ENABLE_CLI_TRUE@am__append_2 = libnl-cli-3.0.pc
+subdir = .
+DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \
+       $(srcdir)/Makefile.in $(srcdir)/libnl-3.0.pc.in \
+       $(srcdir)/libnl-cli-3.0.pc.in $(srcdir)/libnl-genl-3.0.pc.in \
+       $(srcdir)/libnl-nf-3.0.pc.in $(srcdir)/libnl-route-3.0.pc.in \
+       $(top_srcdir)/configure \
+       $(top_srcdir)/include/netlink/version.h.in COPYING ChangeLog \
+       build-aux/ar-lib build-aux/compile build-aux/config.guess \
+       build-aux/config.sub build-aux/depcomp build-aux/install-sh \
+       build-aux/ltmain.sh build-aux/missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES = libnl-3.0.pc libnl-route-3.0.pc libnl-genl-3.0.pc \
+       libnl-nf-3.0.pc libnl-cli-3.0.pc include/netlink/version.h
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(pkgconfigdir)" \
+       "$(DESTDIR)$(pkgsysconfdir)"
+DATA = $(pkgconfig_DATA) $(pkgsysconf_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+       $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+       distdir dist dist-all distcheck
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = include lib man python tests src
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = include lib man python tests $(am__append_1)
+pkgconfig_DATA = libnl-3.0.pc libnl-route-3.0.pc libnl-genl-3.0.pc \
+       libnl-nf-3.0.pc $(am__append_2)
+pkgsysconfdir = ${sysconfdir}/libnl
+pkgsysconf_DATA = etc/pktloc etc/classid
+EXTRA_DIST = \
+       $(pkgsysconf_DATA)
+
+all: all-recursive
+
+.SUFFIXES:
+am--refresh: Makefile
+       @:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+             $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+               && exit 0; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           echo ' $(SHELL) ./config.status'; \
+           $(SHELL) ./config.status;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+libnl-3.0.pc: $(top_builddir)/config.status $(srcdir)/libnl-3.0.pc.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+libnl-route-3.0.pc: $(top_builddir)/config.status $(srcdir)/libnl-route-3.0.pc.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+libnl-genl-3.0.pc: $(top_builddir)/config.status $(srcdir)/libnl-genl-3.0.pc.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+libnl-nf-3.0.pc: $(top_builddir)/config.status $(srcdir)/libnl-nf-3.0.pc.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+libnl-cli-3.0.pc: $(top_builddir)/config.status $(srcdir)/libnl-cli-3.0.pc.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+include/netlink/version.h: $(top_builddir)/config.status $(top_srcdir)/include/netlink/version.h.in
+       cd $(top_builddir) && $(SHELL) ./config.status $@
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+       -rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+       @$(NORMAL_INSTALL)
+       @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+       fi; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+       done
+
+uninstall-pkgconfigDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+install-pkgsysconfDATA: $(pkgsysconf_DATA)
+       @$(NORMAL_INSTALL)
+       @list='$(pkgsysconf_DATA)'; test -n "$(pkgsysconfdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(pkgsysconfdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(pkgsysconfdir)" || exit 1; \
+       fi; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgsysconfdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgsysconfdir)" || exit $$?; \
+       done
+
+uninstall-pkgsysconfDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(pkgsysconf_DATA)'; test -n "$(pkgsysconfdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(pkgsysconfdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       $(am__remove_distdir)
+       test -d "$(distdir)" || mkdir "$(distdir)"
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+       -test -n "$(am__skip_mode_fix)" \
+       || find "$(distdir)" -type d ! -perm -755 \
+               -exec chmod u+rwx,go+rx {} \; -o \
+         ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+         ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+         ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+       || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+       tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+       $(am__remove_distdir)
+
+dist-bzip2: distdir
+       tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+       $(am__remove_distdir)
+
+dist-lzip: distdir
+       tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+       $(am__remove_distdir)
+
+dist-lzma: distdir
+       tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+       $(am__remove_distdir)
+
+dist-xz: distdir
+       tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+       $(am__remove_distdir)
+
+dist-tarZ: distdir
+       tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+       $(am__remove_distdir)
+
+dist-shar: distdir
+       shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+       $(am__remove_distdir)
+
+dist-zip: distdir
+       -rm -f $(distdir).zip
+       zip -rq $(distdir).zip $(distdir)
+       $(am__remove_distdir)
+
+dist dist-all: distdir
+       tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+       $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+       case '$(DIST_ARCHIVES)' in \
+       *.tar.gz*) \
+         GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+       *.tar.bz2*) \
+         bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+       *.tar.lzma*) \
+         lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
+       *.tar.lz*) \
+         lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+       *.tar.xz*) \
+         xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+       *.tar.Z*) \
+         uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+       *.shar.gz*) \
+         GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+       *.zip*) \
+         unzip $(distdir).zip ;;\
+       esac
+       chmod -R a-w $(distdir); chmod u+w $(distdir)
+       mkdir $(distdir)/_build
+       mkdir $(distdir)/_inst
+       chmod a-w $(distdir)
+       test -d $(distdir)/_build || exit 0; \
+       dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+         && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+         && am__cwd=`pwd` \
+         && $(am__cd) $(distdir)/_build \
+         && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+           $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+           $(DISTCHECK_CONFIGURE_FLAGS) \
+         && $(MAKE) $(AM_MAKEFLAGS) \
+         && $(MAKE) $(AM_MAKEFLAGS) dvi \
+         && $(MAKE) $(AM_MAKEFLAGS) check \
+         && $(MAKE) $(AM_MAKEFLAGS) install \
+         && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+         && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+         && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+               distuninstallcheck \
+         && chmod -R a-w "$$dc_install_base" \
+         && ({ \
+              (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+                   distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+             } || { rm -rf "$$dc_destdir"; exit 1; }) \
+         && rm -rf "$$dc_destdir" \
+         && $(MAKE) $(AM_MAKEFLAGS) dist \
+         && rm -rf $(DIST_ARCHIVES) \
+         && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+         && cd "$$am__cwd" \
+         || exit 1
+       $(am__remove_distdir)
+       @(echo "$(distdir) archives ready for distribution: "; \
+         list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+         sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+       @test -n '$(distuninstallcheck_dir)' || { \
+         echo 'ERROR: trying to run $@ with an empty' \
+              '$$(distuninstallcheck_dir)' >&2; \
+         exit 1; \
+       }; \
+       $(am__cd) '$(distuninstallcheck_dir)' || { \
+         echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+         exit 1; \
+       }; \
+       test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+          || { echo "ERROR: files left after uninstall:" ; \
+               if test -n "$(DESTDIR)"; then \
+                 echo "  (check DESTDIR support)"; \
+               fi ; \
+               $(distuninstallcheck_listfiles) ; \
+               exit 1; } >&2
+distcleancheck: distclean
+       @if test '$(srcdir)' = . ; then \
+         echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+         exit 1 ; \
+       fi
+       @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+         || { echo "ERROR: files left in build directory after distclean:" ; \
+              $(distcleancheck_listfiles) ; \
+              exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+       for dir in "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(pkgsysconfdir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool \
+       distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-pkgconfigDATA install-pkgsysconfDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -rf $(top_srcdir)/autom4te.cache
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-pkgconfigDATA uninstall-pkgsysconfDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+       install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am am--refresh check check-am clean clean-generic \
+       clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
+       dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ dist-xz \
+       dist-zip distcheck distclean distclean-generic \
+       distclean-libtool distclean-tags distcleancheck distdir \
+       distuninstallcheck dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-pkgconfigDATA \
+       install-pkgsysconfDATA install-ps install-ps-am install-strip \
+       installcheck installcheck-am installdirs installdirs-am \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags tags-recursive uninstall uninstall-am \
+       uninstall-pkgconfigDATA uninstall-pkgsysconfDATA
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..af98b20
--- /dev/null
@@ -0,0 +1,1287 @@
+# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+# Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
+[m4_warning([this file was generated for autoconf 2.68.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+# 
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=m4_default([$1], [0.9.0])
+       AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
+               PKG_CONFIG=""
+       fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists.  Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_default([$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+                    [pkg_failed=yes])
+ else
+    pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+       AC_MSG_RESULT([no])
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
+        else 
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+       m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])
+        ])
+elif test $pkg_failed = untried; then
+       AC_MSG_RESULT([no])
+       m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])
+        ])
+else
+       $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+       $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+       $3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.11.6], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11.6])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed.  If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+  [am_cv_ar_interface=ar
+   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+     [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([am_ar_try])
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+        AC_TRY_EVAL([am_ar_try])
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+     ])
+   ])
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  m4_default([$1],
+             [AC_MSG_ERROR([could not determine $AR interface])])
+  ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009,
+# 2010, 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 12
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], UPC,  [depcc="$UPC"  am_compiler_list=],
+       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                   [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+       continue
+      else
+       break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named `Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running `make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+        sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+             [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+                            [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+                 [_AM_DEPENDENCIES(CC)],
+                 [define([AC_PROG_CC],
+                         defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+                 [_AM_DEPENDENCIES(CXX)],
+                 [define([AC_PROG_CXX],
+                         defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+                 [_AM_DEPENDENCIES(OBJC)],
+                 [define([AC_PROG_OBJC],
+                         defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation,
+# Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\    *)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes.                 -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+       @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_PROG_CC_C_O
+# --------------
+# Like AC_PROG_CC_C_O, but changed for automake.
+AC_DEFUN([AM_PROG_CC_C_O],
+[AC_REQUIRE([AC_PROG_CC_C_O])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
+if test "$am_t" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+dnl Make sure AC_PROG_CC is never called again, or it will override our
+dnl setting of CC.
+m4_define([AC_PROG_CC],
+          [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\    *)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation,
+# Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p.  We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+  [[\\/$]]* | ?:[[\\/]]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \   ]]*)
+    AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+   if test "$[*]" = "X"; then
+      # -L didn't work.
+      set X `ls -t "$srcdir/configure" conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$[*]" != "X $srcdir/configure conftest.file" \
+      && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2009, 2011  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# (`yes' being less verbose, `no' or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules],
+[  --enable-silent-rules          less verbose build output (undo: `make V=1')
+  --disable-silent-rules         verbose build output (undo: `make V=0')])
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no)  AM_DEFAULT_VERBOSITY=1;;
+*)   AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few `make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+       @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using `$V' instead of `$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+m4_if([$1], [v7],
+     [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+     [m4_case([$1], [ustar],, [pax],,
+              [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+  case $_am_tool in
+  gnutar)
+    for _am_tar in tar gnutar gtar;
+    do
+      AM_RUN_LOG([$_am_tar --version]) && break
+    done
+    am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+    am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+    am__untar="$_am_tar -xf -"
+    ;;
+  plaintar)
+    # Must skip GNU tar: if it does not support --format= it doesn't create
+    # ustar tarball either.
+    (tar --version) >/dev/null 2>&1 && continue
+    am__tar='tar chf - "$$tardir"'
+    am__tar_='tar chf - "$tardir"'
+    am__untar='tar xf -'
+    ;;
+  pax)
+    am__tar='pax -L -x $1 -w "$$tardir"'
+    am__tar_='pax -L -x $1 -w "$tardir"'
+    am__untar='pax -r'
+    ;;
+  cpio)
+    am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+    am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+    am__untar='cpio -i -H $1 -d'
+    ;;
+  none)
+    am__tar=false
+    am__tar_=false
+    am__untar=false
+    ;;
+  esac
+
+  # If the value was cached, stop now.  We just wanted to have am__tar
+  # and am__untar set.
+  test -n "${am_cv_prog_tar_$1}" && break
+
+  # tar/untar a dummy directory, and stop if the command works
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  echo GrepMe > conftest.dir/file
+  AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+  rm -rf conftest.dir
+  if test -s conftest.tar; then
+    AM_RUN_LOG([$am__untar <conftest.tar])
+    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+  fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/build-aux/ar-lib b/build-aux/ar-lib
new file mode 100755 (executable)
index 0000000..0f62c6f
--- /dev/null
@@ -0,0 +1,270 @@
+#! /bin/sh
+# Wrapper for Microsoft lib.exe
+
+me=ar-lib
+scriptversion=2012-03-01.08; # UTC
+
+# Copyright (C) 2010, 2012 Free Software Foundation, Inc.
+# Written by Peter Rosin <peda@lysator.liu.se>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+
+# func_error message
+func_error ()
+{
+  echo "$me: $1" 1>&2
+  exit 1
+}
+
+file_conv=
+
+# func_file_conv build_file
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+       # lazily determine how to convert abs files
+       case `uname -s` in
+         MINGW*)
+           file_conv=mingw
+           ;;
+         CYGWIN*)
+           file_conv=cygwin
+           ;;
+         *)
+           file_conv=wine
+           ;;
+       esac
+      fi
+      case $file_conv in
+       mingw)
+         file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+         ;;
+       cygwin)
+         file=`cygpath -m "$file" || echo "$file"`
+         ;;
+       wine)
+         file=`winepath -w "$file" || echo "$file"`
+         ;;
+      esac
+      ;;
+  esac
+}
+
+# func_at_file at_file operation archive
+# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
+# for each of them.
+# When interpreting the content of the @FILE, do NOT use func_file_conv,
+# since the user would need to supply preconverted file names to
+# binutils ar, at least for MinGW.
+func_at_file ()
+{
+  operation=$2
+  archive=$3
+  at_file_contents=`cat "$1"`
+  eval set x "$at_file_contents"
+  shift
+
+  for member
+  do
+    $AR -NOLOGO $operation:"$member" "$archive" || exit $?
+  done
+}
+
+case $1 in
+  '')
+     func_error "no command.  Try '$0 --help' for more information."
+     ;;
+  -h | --h*)
+    cat <<EOF
+Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
+
+Members may be specified in a file named with @FILE.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "$me, version $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test $# -lt 3; then
+  func_error "you must specify a program, an action and an archive"
+fi
+
+AR=$1
+shift
+while :
+do
+  if test $# -lt 2; then
+    func_error "you must specify a program, an action and an archive"
+  fi
+  case $1 in
+    -lib | -LIB \
+    | -ltcg | -LTCG \
+    | -machine* | -MACHINE* \
+    | -subsystem* | -SUBSYSTEM* \
+    | -verbose | -VERBOSE \
+    | -wx* | -WX* )
+      AR="$AR $1"
+      shift
+      ;;
+    *)
+      action=$1
+      shift
+      break
+      ;;
+  esac
+done
+orig_archive=$1
+shift
+func_file_conv "$orig_archive"
+archive=$file
+
+# strip leading dash in $action
+action=${action#-}
+
+delete=
+extract=
+list=
+quick=
+replace=
+index=
+create=
+
+while test -n "$action"
+do
+  case $action in
+    d*) delete=yes  ;;
+    x*) extract=yes ;;
+    t*) list=yes    ;;
+    q*) quick=yes   ;;
+    r*) replace=yes ;;
+    s*) index=yes   ;;
+    S*)             ;; # the index is always updated implicitly
+    c*) create=yes  ;;
+    u*)             ;; # TODO: don't ignore the update modifier
+    v*)             ;; # TODO: don't ignore the verbose modifier
+    *)
+      func_error "unknown action specified"
+      ;;
+  esac
+  action=${action#?}
+done
+
+case $delete$extract$list$quick$replace,$index in
+  yes,* | ,yes)
+    ;;
+  yesyes*)
+    func_error "more than one action specified"
+    ;;
+  *)
+    func_error "no action specified"
+    ;;
+esac
+
+if test -n "$delete"; then
+  if test ! -f "$orig_archive"; then
+    func_error "archive not found"
+  fi
+  for member
+  do
+    case $1 in
+      @*)
+        func_at_file "${1#@}" -REMOVE "$archive"
+        ;;
+      *)
+        func_file_conv "$1"
+        $AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
+        ;;
+    esac
+  done
+
+elif test -n "$extract"; then
+  if test ! -f "$orig_archive"; then
+    func_error "archive not found"
+  fi
+  if test $# -gt 0; then
+    for member
+    do
+      case $1 in
+        @*)
+          func_at_file "${1#@}" -EXTRACT "$archive"
+          ;;
+        *)
+          func_file_conv "$1"
+          $AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
+          ;;
+      esac
+    done
+  else
+    $AR -NOLOGO -LIST "$archive" | sed -e 's/\\/\\\\/g' | while read member
+    do
+      $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
+    done
+  fi
+
+elif test -n "$quick$replace"; then
+  if test ! -f "$orig_archive"; then
+    if test -z "$create"; then
+      echo "$me: creating $orig_archive"
+    fi
+    orig_archive=
+  else
+    orig_archive=$archive
+  fi
+
+  for member
+  do
+    case $1 in
+    @*)
+      func_file_conv "${1#@}"
+      set x "$@" "@$file"
+      ;;
+    *)
+      func_file_conv "$1"
+      set x "$@" "$file"
+      ;;
+    esac
+    shift
+    shift
+  done
+
+  if test -n "$orig_archive"; then
+    $AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
+  else
+    $AR -NOLOGO -OUT:"$archive" "$@" || exit $?
+  fi
+
+elif test -n "$list"; then
+  if test ! -f "$orig_archive"; then
+    func_error "archive not found"
+  fi
+  $AR -NOLOGO -LIST "$archive" || exit $?
+fi
diff --git a/build-aux/compile b/build-aux/compile
new file mode 100755 (executable)
index 0000000..862a14e
--- /dev/null
@@ -0,0 +1,343 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-03-05.13; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free
+# Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""       $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+       # lazily determine how to convert abs files
+       case `uname -s` in
+         MINGW*)
+           file_conv=mingw
+           ;;
+         CYGWIN*)
+           file_conv=cygwin
+           ;;
+         *)
+           file_conv=wine
+           ;;
+       esac
+      fi
+      case $file_conv/,$2, in
+       *,$file_conv,*)
+         ;;
+       mingw/*)
+         file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+         ;;
+       cygwin/*)
+         file=`cygpath -m "$file" || echo "$file"`
+         ;;
+       wine/*)
+         file=`winepath -w "$file" || echo "$file"`
+         ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+       -o)
+         # configure might choose to run compile as 'compile cc -o foo foo.c'.
+         eat=1
+         case $2 in
+           *.o | *.[oO][bB][jJ])
+             func_file_conv "$2"
+             set x "$@" -Fo"$file"
+             shift
+             ;;
+           *)
+             func_file_conv "$2"
+             set x "$@" -Fe"$file"
+             shift
+             ;;
+         esac
+         ;;
+       -I)
+         eat=1
+         func_file_conv "$2" mingw
+         set x "$@" -I"$file"
+         shift
+         ;;
+       -I*)
+         func_file_conv "${1#-I}" mingw
+         set x "$@" -I"$file"
+         shift
+         ;;
+       -l)
+         eat=1
+         func_cl_dashl "$2"
+         set x "$@" "$lib"
+         shift
+         ;;
+       -l*)
+         func_cl_dashl "${1#-l}"
+         set x "$@" "$lib"
+         shift
+         ;;
+       -L)
+         eat=1
+         func_cl_dashL "$2"
+         ;;
+       -L*)
+         func_cl_dashL "${1#-L}"
+         ;;
+       -static)
+         shared=false
+         ;;
+       -Wl,*)
+         arg=${1#-Wl,}
+         save_ifs="$IFS"; IFS=','
+         for flag in $arg; do
+           IFS="$save_ifs"
+           linker_opts="$linker_opts $flag"
+         done
+         IFS="$save_ifs"
+         ;;
+       -Xlinker)
+         eat=1
+         linker_opts="$linker_opts $2"
+         ;;
+       -*)
+         set x "$@" "$1"
+         shift
+         ;;
+       *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+         func_file_conv "$1"
+         set x "$@" -Tp"$file"
+         shift
+         ;;
+       *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+         func_file_conv "$1" mingw
+         set x "$@" "$file"
+         shift
+         ;;
+       *)
+         set x "$@" "$1"
+         shift
+         ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+       # configure might choose to run compile as 'compile cc -o foo foo.c'.
+       # So we strip '-o arg' only if arg is an object.
+       eat=1
+       case $2 in
+         *.o | *.obj)
+           ofile=$2
+           ;;
+         *)
+           set x "$@" -o "$2"
+           shift
+           ;;
+       esac
+       ;;
+      *.c)
+       cfile=$1
+       set x "$@" "$1"
+       shift
+       ;;
+      *)
+       set x "$@" "$1"
+       shift
+       ;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/build-aux/config.guess b/build-aux/config.guess
new file mode 100755 (executable)
index 0000000..d622a44
--- /dev/null
@@ -0,0 +1,1530 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+#   2011, 2012 Free Software Foundation, Inc.
+
+timestamp='2012-02-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           sh5el) machine=sh5le-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep -q __ELF__
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit ;;
+    *:OpenBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+       exit ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit ;;
+    *:SolidBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+       exit ;;
+    macppc:MirBSD:*:*)
+       echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    alpha:OSF1:*:*)
+       case $UNAME_RELEASE in
+       *4.0)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Pn.n version is a patched version.
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+       exitcode=$?
+       trap '' 0
+       exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit ;;
+    *:OS400:*:*)
+       echo powerpc-ibm-os400
+       exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+       echo arm-unknown-riscos
+       exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7; exit ;;
+       esac ;;
+    s390x:SunOS:*:*)
+       echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+       echo i386-pc-auroraux${UNAME_RELEASE}
+       exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+       eval $set_cc_for_build
+       SUN_ARCH="i386"
+       # If there is a compiler, see if it is configured for 64-bit objects.
+       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+       # This test works for both compilers.
+       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+               grep IS_64BIT_ARCH >/dev/null
+           then
+               SUN_ARCH="x86_64"
+           fi
+       fi
+       echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+       echo m68k-milan-mint${UNAME_RELEASE}
+       exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+       echo m68k-hades-mint${UNAME_RELEASE}
+       exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+       echo m68k-unknown-mint${UNAME_RELEASE}
+       exit ;;
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
+       exit ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+       int main (int argc, char *argv[]) {
+#else
+       int main (argc, argv) int argc; char *argv[]; {
+#endif
+       #if defined (host_mips) && defined (MIPSEB)
+       #if defined (SYSTYPE_SYSV)
+         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_SVR4)
+         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+       #endif
+       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+       #endif
+       #endif
+         exit (-1);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c &&
+         dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+         SYSTEM_NAME=`$dummy $dummyarg` &&
+           { echo "$SYSTEM_NAME"; exit; }
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit ;;
+    AViiON:dgux:*:*)
+       # DG/UX returns AViiON for all architectures
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
+               echo m88k-dg-dgux${UNAME_RELEASE}
+           else
+               echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
+       fi
+       exit ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+       exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit ;;
+    ia64:AIX:*:*)
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+               then
+                       echo "$SYSTEM_NAME"
+               else
+                       echo rs6000-ibm-aix3.2.5
+               fi
+       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+               echo rs6000-ibm-aix3.2.4
+       else
+               echo rs6000-ibm-aix3.2
+       fi
+       exit ;;
+    *:AIX:*:[4567])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                   sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                   case "${sc_cpu_version}" in
+                     523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                     528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                     532)                      # CPU_PA_RISC2_0
+                       case "${sc_kernel_bits}" in
+                         32) HP_ARCH="hppa2.0n" ;;
+                         64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                       esac ;;
+                   esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^            //' << EOF >$dummy.c
+
+               #define _HPUX_SOURCE
+               #include <stdlib.h>
+               #include <unistd.h>
+
+               int main ()
+               {
+               #if defined(_SC_KERNEL_BITS)
+                   long bits = sysconf(_SC_KERNEL_BITS);
+               #endif
+                   long cpu  = sysconf (_SC_CPU_VERSION);
+
+                   switch (cpu)
+                       {
+                       case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+                       case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+                       case CPU_PA_RISC2_0:
+               #if defined(_SC_KERNEL_BITS)
+                           switch (bits)
+                               {
+                               case 64: puts ("hppa2.0w"); break;
+                               case 32: puts ("hppa2.0n"); break;
+                               default: puts ("hppa2.0"); break;
+                               } break;
+               #else  /* !defined(_SC_KERNEL_BITS) */
+                           puts ("hppa2.0"); break;
+               #endif
+                       default: puts ("hppa1.0"); break;
+                       }
+                   exit (0);
+               }
+EOF
+                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           eval $set_cc_for_build
+
+           # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+           # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+           # generating 64-bit code.  GNU and HP use different nomenclature:
+           #
+           # $ CC_FOR_BUILD=cc ./config.guess
+           # => hppa2.0w-hp-hpux11.23
+           # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+           # => hppa64-hp-hpux11.23
+
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+               grep -q __LP64__
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <unistd.h>
+       int
+       main ()
+       {
+         long cpu = sysconf (_SC_CPU_VERSION);
+         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+            results, however.  */
+         if (CPU_IS_PA_RISC (cpu))
+           {
+             switch (cpu)
+               {
+                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+                 default: puts ("hppa-hitachi-hiuxwe2"); break;
+               }
+           }
+         else if (CPU_IS_HP_MC68K (cpu))
+           puts ("m68k-hitachi-hiuxwe2");
+         else puts ("unknown-hitachi-hiuxwe2");
+         exit (0);
+       }
+EOF
+       $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+               { echo "$SYSTEM_NAME"; exit; }
+       echo unknown-hitachi-hiuxwe2
+       exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+       exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+       exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+       exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+       exit ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    *:UNICOS/mp:*:*)
+       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+       echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    5000:UNIX_System_V:4.*:*)
+       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+       echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:FreeBSD:*:*)
+       UNAME_PROCESSOR=`/usr/bin/uname -p`
+       case ${UNAME_PROCESSOR} in
+           amd64)
+               echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           *)
+               echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+       esac
+       exit ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit ;;
+    *:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit ;;
+    i*:MSYS*:*)
+       echo ${UNAME_MACHINE}-pc-msys
+       exit ;;
+    i*:windows32*:*)
+       # uname -m includes "-pc" on this system.
+       echo ${UNAME_MACHINE}-mingw32
+       exit ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit ;;
+    *:Interix*:*)
+       case ${UNAME_MACHINE} in
+           x86)
+               echo i586-pc-interix${UNAME_RELEASE}
+               exit ;;
+           authenticamd | genuineintel | EM64T)
+               echo x86_64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+           IA64)
+               echo ia64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+       esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit ;;
+    8664:Windows_NT:*)
+       echo x86_64-pc-mks
+       exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    *:GNU:*:*)
+       # the GNU system
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+       exit ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit ;;
+    aarch64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    aarch64_be:Linux:*:*)
+       UNAME_MACHINE=aarch64_be
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+       esac
+       objdump --private-headers /bin/sh | grep -q ld.so.1
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit ;;
+    arm*:Linux:*:*)
+       eval $set_cc_for_build
+       if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+           | grep -q __ARM_EABI__
+       then
+           echo ${UNAME_MACHINE}-unknown-linux-gnu
+       else
+           if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+               | grep -q __ARM_PCS_VFP
+           then
+               echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+           else
+               echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+           fi
+       fi
+       exit ;;
+    avr32*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    cris:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-gnu
+       exit ;;
+    crisv32:Linux:*:*)
+       echo ${UNAME_MACHINE}-axis-linux-gnu
+       exit ;;
+    frv:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    hexagon:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    i*86:Linux:*:*)
+       LIBC=gnu
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #ifdef __dietlibc__
+       LIBC=dietlibc
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+       echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+       exit ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef ${UNAME_MACHINE}
+       #undef ${UNAME_MACHINE}el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=${UNAME_MACHINE}el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=${UNAME_MACHINE}
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+       ;;
+    or32:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    padre:Linux:*:*)
+       echo sparc-unknown-linux-gnu
+       exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
+       exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    tile*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    vax:Linux:*:*)
+       echo ${UNAME_MACHINE}-dec-linux-gnu
+       exit ;;
+    x86_64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    xtensa*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+       # Unixware is an offshoot of SVR4, but it has its own version
+       # number series starting with 2...
+       # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+       # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit ;;
+    i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit ;;
+    i*86:*:5:[678]*)
+       # UnixWare 7.x, OpenUNIX and OpenServer 6.
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/dev/null >/dev/null ; then
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit ;;
+    pc:*:*:*)
+       # Left here for compatibility:
+       # uname -m prints for DJGPP always 'pc', but it prints nothing about
+       # the processor, so we play safe by assuming i586.
+       # Note: whatever this is, it MUST be the same as what config.sub
+       # prints for the "djgpp" host, or else GDB configury will decide that
+       # this is a cross-build.
+       echo i586-pc-msdosdjgpp
+       exit ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit ;;
+    M68*:*:R3V[5678]*:*)
+       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+       OS_REL='.3'
+       test -r /etc/.relid \
+           && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+           && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit ;;
+    PENTIUM:*:4.0*:*)  # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                       # says <Richard.M.Bartel@ccMail.Census.GOV>
+       echo i586-unisys-sysv4
+       exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit ;;
+    i*86:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo ${UNAME_MACHINE}-stratus-vos
+       exit ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+       if [ -d /usr/nec ]; then
+               echo mips-nec-sysv${UNAME_RELEASE}
+       else
+               echo mips-unknown-sysv${UNAME_RELEASE}
+       fi
+       exit ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit ;;
+    BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
+       echo i586-pc-haiku
+       exit ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-7:SUPER-UX:*:*)
+       echo sx7-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8:SUPER-UX:*:*)
+       echo sx8-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8R:SUPER-UX:*:*)
+       echo sx8r-nec-superux${UNAME_RELEASE}
+       exit ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Darwin:*:*)
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       case $UNAME_PROCESSOR in
+           i386)
+               eval $set_cc_for_build
+               if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+                 if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                     (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                     grep IS_64BIT_ARCH >/dev/null
+                 then
+                     UNAME_PROCESSOR="x86_64"
+                 fi
+               fi ;;
+           unknown) UNAME_PROCESSOR=powerpc ;;
+       esac
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+       echo neo-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit ;;
+    SEI:*:*:SEIUX)
+       echo mips-sei-seiux${UNAME_RELEASE}
+       exit ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms ; exit ;;
+           I*) echo ia64-dec-vms ; exit ;;
+           V*) echo vax-dec-vms ; exit ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit ;;
+    i*86:skyos:*:*)
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+       exit ;;
+    i*86:rdos:*:*)
+       echo ${UNAME_MACHINE}-pc-rdos
+       exit ;;
+    i*86:AROS:*:*)
+       echo ${UNAME_MACHINE}-pc-aros
+       exit ;;
+    x86_64:VMkernel:*:*)
+       echo ${UNAME_MACHINE}-unknown-esx
+       exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+       "4"
+#else
+       ""
+#endif
+       ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+       { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    c34*)
+       echo c34-convex-bsd
+       exit ;;
+    c38*)
+       echo c38-convex-bsd
+       exit ;;
+    c4*)
+       echo c4-convex-bsd
+       exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build-aux/config.sub b/build-aux/config.sub
new file mode 100755 (executable)
index 0000000..c894da4
--- /dev/null
@@ -0,0 +1,1773 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+#   2011, 2012 Free Software Foundation, Inc.
+
+timestamp='2012-02-10'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis | -knuth | -cray | -microblaze)
+               os=
+               basic_machine=$1
+               ;;
+       -bluegene*)
+               os=-cnk
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco6)
+               os=-sco5v6
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5v6*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | aarch64 | aarch64_be \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+        | be32 | be64 \
+       | bfin \
+       | c4x | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | epiphany \
+       | fido | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | hexagon \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | le32 | le64 \
+       | lm32 \
+       | m32c | m32r | m32rle | m68000 | m68k | m88k \
+       | maxq | mb | microblaze | mcore | mep | metag \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64octeon | mips64octeonel \
+       | mips64orion | mips64orionel \
+       | mips64r5900 | mips64r5900el \
+       | mips64vr | mips64vrel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mips64vr5900 | mips64vr5900el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | moxie \
+       | mt \
+       | msp430 \
+       | nds32 | nds32le | nds32be \
+       | nios | nios2 \
+       | ns16k | ns32k \
+       | open8 \
+       | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle \
+       | pyramid \
+       | rl78 | rx \
+       | score \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+       | spu \
+       | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+       | ubicom32 \
+       | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+       | we32k \
+       | x86 | xc16x | xstormy16 | xtensa \
+       | z8k | z80)
+               basic_machine=$basic_machine-unknown
+               ;;
+       c54x)
+               basic_machine=tic54x-unknown
+               ;;
+       c55x)
+               basic_machine=tic55x-unknown
+               ;;
+       c6x)
+               basic_machine=tic6x-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+       ms1)
+               basic_machine=mt-unknown
+               ;;
+
+       strongarm | thumb | xscale)
+               basic_machine=arm-unknown
+               ;;
+       xgate)
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       xscaleeb)
+               basic_machine=armeb-unknown
+               ;;
+
+       xscaleel)
+               basic_machine=armel-unknown
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | aarch64-* | aarch64_be-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* | avr32-* \
+       | be32-* | be64-* \
+       | bfin-* | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* \
+       | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | hexagon-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | le32-* | le64-* \
+       | lm32-* \
+       | m32c-* | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64octeon-* | mips64octeonel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64r5900-* | mips64r5900el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mips64vr5900-* | mips64vr5900el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | mt-* \
+       | msp430-* \
+       | nds32-* | nds32le-* | nds32be-* \
+       | nios-* | nios2-* \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | open8-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+       | pyramid-* \
+       | rl78-* | romp-* | rs6000-* | rx-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+       | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+       | tahoe-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tile*-* \
+       | tron-* \
+       | ubicom32-* \
+       | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+       | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xc16x-* | xps100-* \
+       | xstormy16-* | xtensa*-* \
+       | ymp-* \
+       | z8k-* | z80-*)
+               ;;
+       # Recognize the basic CPU types without company name, with glob match.
+       xtensa*)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amd64-*)
+               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aros)
+               basic_machine=i386-pc
+               os=-aros
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       blackfin)
+               basic_machine=bfin-unknown
+               os=-linux
+               ;;
+       blackfin-*)
+               basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       bluegene*)
+               basic_machine=powerpc-ibm
+               os=-cnk
+               ;;
+       c54x-*)
+               basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c55x-*)
+               basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c6x-*)
+               basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       cegcc)
+               basic_machine=arm-unknown
+               os=-cegcc
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
+               ;;
+       cr16 | cr16-*)
+               basic_machine=cr16-unknown
+               os=-elf
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dicos)
+               basic_machine=i686-pc
+               os=-dicos
+               ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m68knommu)
+               basic_machine=m68k-unknown
+               os=-linux
+               ;;
+       m68knommu-*)
+               basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       microblaze)
+               basic_machine=microblaze-xilinx
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       mingw32ce)
+               basic_machine=arm-unknown
+               os=-mingw32ce
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       ms1-*)
+               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+               ;;
+       msys)
+               basic_machine=i386-pc
+               os=-msys
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       nacl)
+               basic_machine=le32-unknown
+               os=-nacl
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       neo-tandem)
+               basic_machine=neo-tandem
+               ;;
+       nse-tandem)
+               basic_machine=nse-tandem
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       openrisc | openrisc-*)
+               basic_machine=or32-unknown
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       parisc)
+               basic_machine=hppa-unknown
+               os=-linux
+               ;;
+       parisc-*)
+               basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pc98)
+               basic_machine=i386-pc
+               ;;
+       pc98-*)
+               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc | ppcbe)    basic_machine=powerpc-unknown
+               ;;
+       ppc-* | ppcbe-*)
+               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rdos)
+               basic_machine=i386-pc
+               os=-rdos
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sde)
+               basic_machine=mipsisa32-sde
+               os=-elf
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh5el)
+               basic_machine=sh5le-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       strongarm-* | thumb-*)
+               basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tile*)
+               basic_machine=$basic_machine-unknown
+               os=-linux-gnu
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       xscale-* | xscalee[bl]-*)
+               basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       z80-*-coff)
+               basic_machine=z80-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+       # First match some system type aliases
+       # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -auroraux)
+               os=-auroraux
+               ;;
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* | -aros* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+             | -openbsd* | -solidbsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* | -cegcc* \
+             | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -linux-android* \
+             | -linux-newlib* | -linux-uclibc* \
+             | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+       -os400*)
+               os=-os400
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+       -tpf*)
+               os=-tpf
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -kaos*)
+               os=-kaos
+               ;;
+       -zvmoe)
+               os=-zvmoe
+               ;;
+       -dicos*)
+               os=-dicos
+               ;;
+       -nacl*)
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+       score-*)
+               os=-elf
+               ;;
+       spu-*)
+               os=-elf
+               ;;
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+       c4x-* | tic4x-*)
+               os=-coff
+               ;;
+       tic54x-*)
+               os=-coff
+               ;;
+       tic55x-*)
+               os=-coff
+               ;;
+       tic6x-*)
+               os=-coff
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mep-*)
+               os=-elf
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-haiku)
+               os=-haiku
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-knuth)
+               os=-mmixware
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -cnk*|-aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build-aux/depcomp b/build-aux/depcomp
new file mode 100755 (executable)
index 0000000..25a39e6
--- /dev/null
@@ -0,0 +1,708 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2012-03-27.16; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
+# 2011, 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# A tabulation character.
+tab='  '
+# A newline character.
+nl='
+'
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+   # This is just like msvisualcpp but w/o cygpath translation.
+   # Just convert the backslash-escaped backslashes to single forward
+   # slashes to satisfy depend.m4
+   cygpath_u='sed s,\\\\,/,g'
+   depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+   # This is just like msvc7 but w/o cygpath translation.
+   # Just convert the backslash-escaped backslashes to single forward
+   # slashes to satisfy depend.m4
+   cygpath_u='sed s,\\\\,/,g'
+   depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+   # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
+   gccflag=-qmakedep=gcc,-MF
+   depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' "$nl" < "$tmpdepfile" |
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+      | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # '$object: dependent.h' and one to simply 'dependent.h:'.
+    sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+    sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+icc)
+  # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
+  # However on
+  #    $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # ICC 7.0 will fill foo.d with something like
+  #    foo.o: sub/foo.c
+  #    foo.o: sub/foo.h
+  # which is wrong.  We want
+  #    sub/foo.o: sub/foo.c
+  #    sub/foo.o: sub/foo.h
+  #    sub/foo.c:
+  #    sub/foo.h:
+  # ICC 7.1 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\':
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  # tcc 0.9.26 (FIXME still under development at the moment of writing)
+  # will emit a similar output, but also prepend the continuation lines
+  # with horizontal tabulation characters.
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form 'foo.o: dependent.h',
+  # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # '$object: dependent.h' and one to simply 'dependent.h:'.
+  sed -e "s/^[ $tab][ $tab]*/  /" -e "s,^[^:]*:,$object :," \
+    < "$tmpdepfile" > "$depfile"
+  sed '
+    s/[ '"$tab"'][ '"$tab"']*/ /g
+    s/^ *//
+    s/ *\\*$//
+    s/^[^:]*: *//
+    /^$/d
+    /:$/d
+    s/$/ :/
+  ' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+              s/^ *//
+              s/ \\*$//
+              s/$/:/
+              p
+            }' "$tmpdepfile" >> "$depfile"
+  else
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in 'foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      # With Tru64 cc, shared objects can also be used to make a
+      # static library.  This mechanism is used in libtool 1.4 series to
+      # handle both shared and static libraries in a single compilation.
+      # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+      #
+      # With libtool 1.5 this exception was removed, and libtool now
+      # generates 2 separate objects for the 2 libraries.  These two
+      # compilations output dependencies in $dir.libs/$base.o.d and
+      # in $dir$base.o.d.  We have to check for both files, because
+      # one of the two compilations can be disabled.  We should prefer
+      # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+      # automatically cleaned when .libs/ is deleted, while ignoring
+      # the former would cause a distcleancheck panic.
+      tmpdepfile1=$dir.libs/$base.lo.d   # libtool 1.4
+      tmpdepfile2=$dir$base.o.d          # libtool 1.5
+      tmpdepfile3=$dir.libs/$base.o.d    # libtool 1.5
+      tmpdepfile4=$dir.libs/$base.d      # Compaq CCC V6.2-504
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1=$dir$base.o.d
+      tmpdepfile2=$dir$base.d
+      tmpdepfile3=$dir$base.d
+      tmpdepfile4=$dir$base.d
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+      exit $stat
+   fi
+
+   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+   do
+     test -f "$tmpdepfile" && break
+   done
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test "$stat" = 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' "$nl" < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+       -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+       set fnord "$@"
+       shift
+       shift
+       ;;
+    *)
+       set fnord "$@" "$arg"
+       shift
+       shift
+       ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/build-aux/install-sh b/build-aux/install-sh
new file mode 100755 (executable)
index 0000000..a9244eb
--- /dev/null
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-01-19.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""       $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+       shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+       case $mode in
+         *' '* | *'    '* | *'
+'*       | *'*'* | *'?'* | *'['*)
+           echo "$0: invalid mode: $mode" >&2
+           exit 1;;
+       esac
+       shift;;
+
+    -o) chowncmd="$chownprog $2"
+       shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+       # Protect names problematic for `test' and other utilities.
+       case $dst_arg in
+         -* | [=\(\)!]) dst_arg=./$dst_arg;;
+       esac
+       shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)        shift
+       break;;
+
+    -*)        echo "$0: invalid option: $1" >&2
+       exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for `test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call `install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+       u_plus_rw=
+      else
+       u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+       u_plus_rw=
+      else
+       u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for `test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+       echo "$0: $dst_arg: Is a directory" >&2
+       exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+       (dirname "$dst") 2>/dev/null ||
+       expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+            X"$dst" : 'X\(//\)[^/]' \| \
+            X"$dst" : 'X\(//\)$' \| \
+            X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+       echo X"$dst" |
+           sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+                  s//\1/
+                  q
+                }
+                /^X\(\/\/\)[^/].*/{
+                  s//\1/
+                  q
+                }
+                /^X\(\/\/\)$/{
+                  s//\1/
+                  q
+                }
+                /^X\(\/\).*/{
+                  s//\1/
+                  q
+                }
+                s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+       # Create intermediate dirs using mode 755 as modified by the umask.
+       # This is like FreeBSD 'install' as of 1997-10-28.
+       umask=`umask`
+       case $stripcmd.$umask in
+         # Optimize common cases.
+         *[2367][2367]) mkdir_umask=$umask;;
+         .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+         *[0-7])
+           mkdir_umask=`expr $umask + 22 \
+             - $umask % 100 % 40 + $umask % 20 \
+             - $umask % 10 % 4 + $umask % 2
+           `;;
+         *) mkdir_umask=$umask,go-w;;
+       esac
+
+       # With -d, create the new directory with the user-specified mode.
+       # Otherwise, rely on $mkdir_umask.
+       if test -n "$dir_arg"; then
+         mkdir_mode=-m$mode
+       else
+         mkdir_mode=
+       fi
+
+       posix_mkdir=false
+       case $umask in
+         *[123567][0-7][0-7])
+           # POSIX mkdir -p sets u+wx bits regardless of umask, which
+           # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+           ;;
+         *)
+           tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+           trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+           if (umask $mkdir_umask &&
+               exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+           then
+             if test -z "$dir_arg" || {
+                  # Check for POSIX incompatibilities with -m.
+                  # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                  # other-writeable bit of parent directory when it shouldn't.
+                  # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                  ls_ld_tmpdir=`ls -ld "$tmpdir"`
+                  case $ls_ld_tmpdir in
+                    d????-?r-*) different_mode=700;;
+                    d????-?--*) different_mode=755;;
+                    *) false;;
+                  esac &&
+                  $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+                    ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+                    test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                  }
+                }
+             then posix_mkdir=:
+             fi
+             rmdir "$tmpdir/d" "$tmpdir"
+           else
+             # Remove any dirs left behind by ancient mkdir implementations.
+             rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+           fi
+           trap '' 0;;
+       esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+       umask $mkdir_umask &&
+       $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+       /*) prefix='/';;
+       [-=\(\)!]*) prefix='./';;
+       *)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+       test X"$d" = X && continue
+
+       prefix=$prefix$d
+       if test -d "$prefix"; then
+         prefixes=
+       else
+         if $posix_mkdir; then
+           (umask=$mkdir_umask &&
+            $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+           # Don't fail if two instances are running concurrently.
+           test -d "$prefix" || exit 1
+         else
+           case $prefix in
+             *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+             *) qprefix=$prefix;;
+           esac
+           prefixes="$prefixes '$qprefix'"
+         fi
+       fi
+       prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+       # Don't fail if two instances are running concurrently.
+       (umask $mkdir_umask &&
+        eval "\$doit_exec \$mkdirprog $prefixes") ||
+         test -d "$dstdir" || exit 1
+       obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"    2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+       # Now remove or move aside any old file at destination location.
+       # We try this two ways since rm can't unlink itself on some
+       # systems and the destination file might be busy for other
+       # reasons.  In this case, the final cleanup might fail but the new
+       # file should still install successfully.
+       {
+         test ! -f "$dst" ||
+         $doit $rmcmd -f "$dst" 2>/dev/null ||
+         { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+           { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+         } ||
+         { echo "$0: cannot unlink or rename $dst" >&2
+           (exit 1); exit 1
+         }
+       } &&
+
+       # Now rename the file to the real destination.
+       $doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/build-aux/ltmain.sh b/build-aux/ltmain.sh
new file mode 100644 (file)
index 0000000..63ae69d
--- /dev/null
@@ -0,0 +1,9655 @@
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --no-warn            don't display warning messages
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#         host-triplet:        $host
+#         shell:               $SHELL
+#         compiler:            $LTCC
+#         compiler flags:              $LTCFLAGS
+#         linker:              $LD (gnu? $with_gnu_ld)
+#         $progname:   (GNU libtool) 2.4.2
+#         automake:    $automake_version
+#         autoconf:    $autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+# General help using GNU software: <http://www.gnu.org/gethelp/>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.4.2
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+         export $lt_var
+         lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+         lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+       fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77     # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS="  $lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+    func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+    func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+    # Extract subdirectory from the argument.
+    func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+    case ${2} in
+      .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+      *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+    esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+               s@/\./@/@g
+               t dotsl
+               s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+       # list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+       IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+       func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+       my_arg=`$ECHO "$1" | $SED \
+           -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+       eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+           $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+       eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+  case $1 in
+  [0-9]* | *[!a-zA-Z0-9_]*)
+    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+    ;;
+  * )
+    func_tr_sh_result=$1
+    ;;
+  esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $opt_debug
+
+    $SED -n '/(C)/!b go
+       :more
+       /\./!{
+         N
+         s/\n# / /
+         b more
+       }
+       :go
+       /^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+       s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/^#  *.*--help/ {
+        s/^# //
+       s/^# *$//
+       s/\$progname/'$progname'/
+       p
+    }' < "$progpath"
+    echo
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+       :print
+        s/^# //
+       s/^# *$//
+       s*\$progname*'$progname'*
+       s*\$host*'"$host"'*
+       s*\$SHELL*'"$SHELL"'*
+       s*\$LTCC*'"$LTCC"'*
+       s*\$LTCFLAGS*'"$LTCFLAGS"'*
+       s*\$LD*'"$LD"'*
+       s/\$with_gnu_ld/'"$with_gnu_ld"'/
+       s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+       s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+       p
+       d
+     }
+     /^# .* home page:/b print
+     /^# General help using/b print
+     ' < "$progpath"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $opt_debug
+
+    func_error "missing argument for $1."
+    exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+    my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+    my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+    func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+    func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+    my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+    my_sed_long_arg='1s/^--[^=]*=//'
+
+    func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+    func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+    eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+    func_quote_for_eval "${2}"
+    eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+    func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+    func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+    func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+    func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+       taglist="$taglist $tagname"
+
+       # Evaluate the configuration.  Be careful to quote the path
+       # and the sed script, to avoid splitting on whitespace, but
+       # also don't use non-portable quotes within backquotes within
+       # quotes we have to do it in 2 steps:
+       extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+       eval "$extractedcf"
+      else
+       func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+  shift; set dummy --mode clean ${1+"$@"}; shift
+  ;;
+compile|compil|compi|comp|com|co|c)
+  shift; set dummy --mode compile ${1+"$@"}; shift
+  ;;
+execute|execut|execu|exec|exe|ex|e)
+  shift; set dummy --mode execute ${1+"$@"}; shift
+  ;;
+finish|finis|fini|fin|fi|f)
+  shift; set dummy --mode finish ${1+"$@"}; shift
+  ;;
+install|instal|insta|inst|ins|in|i)
+  shift; set dummy --mode install ${1+"$@"}; shift
+  ;;
+link|lin|li|l)
+  shift; set dummy --mode link ${1+"$@"}; shift
+  ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+  shift; set dummy --mode uninstall ${1+"$@"}; shift
+  ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly.  This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+  # this just eases exit handling
+  while test $# -gt 0; do
+    opt="$1"
+    shift
+    case $opt in
+      --debug|-x)      opt_debug='set -x'
+                       func_echo "enabling shell trace mode"
+                       $opt_debug
+                       ;;
+      --dry-run|--dryrun|-n)
+                       opt_dry_run=:
+                       ;;
+      --config)
+                       opt_config=:
+func_config
+                       ;;
+      --dlopen|-dlopen)
+                       optarg="$1"
+                       opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+                       shift
+                       ;;
+      --preserve-dup-deps)
+                       opt_preserve_dup_deps=:
+                       ;;
+      --features)
+                       opt_features=:
+func_features
+                       ;;
+      --finish)
+                       opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+                       ;;
+      --help)
+                       opt_help=:
+                       ;;
+      --help-all)
+                       opt_help_all=:
+opt_help=': help-all'
+                       ;;
+      --mode)
+                       test $# = 0 && func_missing_arg $opt && break
+                       optarg="$1"
+                       opt_mode="$optarg"
+case $optarg in
+  # Valid mode arguments:
+  clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+  # Catch anything else as an error
+  *) func_error "invalid argument for $opt"
+     exit_cmd=exit
+     break
+     ;;
+esac
+                       shift
+                       ;;
+      --no-silent|--no-quiet)
+                       opt_silent=false
+func_append preserve_args " $opt"
+                       ;;
+      --no-warning|--no-warn)
+                       opt_warning=false
+func_append preserve_args " $opt"
+                       ;;
+      --no-verbose)
+                       opt_verbose=false
+func_append preserve_args " $opt"
+                       ;;
+      --silent|--quiet)
+                       opt_silent=:
+func_append preserve_args " $opt"
+        opt_verbose=false
+                       ;;
+      --verbose|-v)
+                       opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+                       ;;
+      --tag)
+                       test $# = 0 && func_missing_arg $opt && break
+                       optarg="$1"
+                       opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+                       shift
+                       ;;
+
+      -\?|-h)          func_usage                              ;;
+      --help)          func_help                               ;;
+      --version)       func_version                            ;;
+
+      # Separate optargs to long options:
+      --*=*)
+                       func_split_long_opt "$opt"
+                       set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+                       shift
+                       ;;
+
+      # Separate non-argument short options:
+      -\?*|-h*|-n*|-v*)
+                       func_split_short_opt "$opt"
+                       set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+                       shift
+                       ;;
+
+      --)              break                                   ;;
+      -*)              func_fatal_help "unrecognized option \`$opt'" ;;
+      *)               set dummy "$opt" ${1+"$@"};     shift; break  ;;
+    esac
+  done
+
+  # Validate options:
+
+  # save first non-option argument
+  if test "$#" -gt 0; then
+    nonopt="$opt"
+    shift
+  fi
+
+  # preserve --debug
+  test "$opt_debug" = : || func_append preserve_args " --debug"
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+      ;;
+  esac
+
+  $opt_help || {
+    # Sanity checks first:
+    func_check_version_match
+
+    if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+      func_fatal_configuration "not configured to build any kind of library"
+    fi
+
+    # Darwin sucks
+    eval std_shrext=\"$shrext_cmds\"
+
+    # Only execute mode is allowed to have -dlopen flags.
+    if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+      func_error "unrecognized option \`-dlopen'"
+      $ECHO "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Change the help message to a mode-specific one.
+    generic_help="$help"
+    help="Try \`$progname --help --mode=$opt_mode' for more information."
+  }
+
+
+  # Bail if the options were screwed
+  $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+       for lalib_p_l in 1 2 3 4
+       do
+           read lalib_p_line
+           case "$lalib_p_line" in
+               \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+           esac
+       done
+       exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)        . "$1" ;;
+    *)         . "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case "$lt_sysroot:$1" in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result="=$func_stripname_result"
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+       func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+       for z in $available_tags; do
+         if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+           # Evaluate the configuration.
+           eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+           CC_quoted=
+           for arg in $CC; do
+             # Double-quote args containing other shell metacharacters.
+             func_append_quoted CC_quoted "$arg"
+           done
+           CC_expanded=`func_echo_all $CC`
+           CC_quoted_expanded=`func_echo_all $CC_quoted`
+           case "$@ " in
+           " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+           " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+             # The compiler in the base compile command matches
+             # the one in the tagged configuration.
+             # Assume this is the tagged configuration we want.
+             tagname=$z
+             break
+             ;;
+           esac
+         fi
+       done
+       # If $tagname still isn't set, then no tagged configuration
+       # was found and let the user know that the "--tag" command
+       # line option must be used.
+       if test -z "$tagname"; then
+         func_echo "unable to infer tagged configuration"
+         func_fatal_error "specify a tag with \`--tag'"
+#      else
+#        func_verbose "using $tagname tagged configuration"
+       fi
+       ;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $opt_debug
+  func_convert_core_file_wine_to_w32_result="$1"
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$lt_sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $opt_debug
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=""
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $opt_debug
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $opt_debug
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $opt_debug
+  if test -z "$2" && test -n "$1" ; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  \`$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result="$1"
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $opt_debug
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  \`$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result="$3"
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $opt_debug
+  case $4 in
+  $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $opt_debug
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $opt_debug
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $opt_debug
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd="func_convert_path_${func_stripname_result}"
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $opt_debug
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+       # do not "continue".  Instead, add this to base_compile
+       lastarg="$arg"
+       arg_mode=normal
+       ;;
+
+      target )
+       libobj="$arg"
+       arg_mode=normal
+       continue
+       ;;
+
+      normal )
+       # Accept any command-line options.
+       case $arg in
+       -o)
+         test -n "$libobj" && \
+           func_fatal_error "you cannot specify \`-o' more than once"
+         arg_mode=target
+         continue
+         ;;
+
+       -pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+         continue
+         ;;
+
+       -shared | -static | -prefer-pic | -prefer-non-pic)
+         func_append later " $arg"
+         continue
+         ;;
+
+       -no-suppress)
+         suppress_opt=no
+         continue
+         ;;
+
+       -Xcompiler)
+         arg_mode=arg  #  the next one goes into the "base_compile" arg list
+         continue      #  The current "srcfile" will either be retained or
+         ;;            #  replaced later.  I would guess that would be a bug.
+
+       -Wc,*)
+         func_stripname '-Wc,' '' "$arg"
+         args=$func_stripname_result
+         lastarg=
+         save_ifs="$IFS"; IFS=','
+         for arg in $args; do
+           IFS="$save_ifs"
+           func_append_quoted lastarg "$arg"
+         done
+         IFS="$save_ifs"
+         func_stripname ' ' '' "$lastarg"
+         lastarg=$func_stripname_result
+
+         # Add the arguments to base_compile.
+         func_append base_compile " $lastarg"
+         continue
+         ;;
+
+       *)
+         # Accept the current argument as the source file.
+         # The previous "srcfile" becomes the current argument.
+         #
+         lastarg="$srcfile"
+         srcfile="$arg"
+         ;;
+       esac  #  case $arg
+       ;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+       func_basename "$srcfile"
+       libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+       test "$build_libtool_libs" != yes && \
+         func_fatal_configuration "can not build a shared library"
+       build_old_libs=no
+       continue
+       ;;
+
+      -static)
+       build_libtool_libs=no
+       build_old_libs=yes
+       continue
+       ;;
+
+      -prefer-pic)
+       pic_mode=yes
+       continue
+       ;;
+
+      -prefer-non-pic)
+       pic_mode=no
+       continue
+       ;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'   &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+       func_echo "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+       $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $opt_dry_run || $RM $removelist
+       exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+       command="$base_compile $qsrcfile $pic_flag"
+      else
+       # Don't build PIC code
+       command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+       # Place PIC objects in $objdir
+       func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command" \
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+       $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $opt_dry_run || $RM $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+       func_show_eval '$MV "$output_obj" "$lobj"' \
+         'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+       suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+       # Don't build PIC code
+       command="$base_compile $qsrcfile$pie_flag"
+      else
+       command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+       func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+       $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+       $opt_dry_run || $RM $removelist
+       exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+       func_show_eval '$MV "$output_obj" "$obj"' \
+         'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+       removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+       func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+       echo
+       func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+       H
+       d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+       || func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+       func_resolve_sysroot "$file"
+       file=$func_resolve_sysroot_result
+
+       # Check to see that this really is a libtool archive.
+       func_lalib_unsafe_p "$file" \
+         || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+       # Read the libtool library.
+       dlname=
+       library_names=
+       func_source "$file"
+
+       # Skip this library if it cannot be dlopened.
+       if test -z "$dlname"; then
+         # Warn if it was a shared library.
+         test -n "$library_names" && \
+           func_warning "\`$file' was not linked with \`-export-dynamic'"
+         continue
+       fi
+
+       func_dirname "$file" "" "."
+       dir="$func_dirname_result"
+
+       if test -f "$dir/$objdir/$dlname"; then
+         func_append dir "/$objdir"
+       else
+         if test ! -f "$dir/$dlname"; then
+           func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+         fi
+       fi
+       ;;
+
+      *.lo)
+       # Just add the directory containing the .lo file.
+       func_dirname "$file" "" "."
+       dir="$func_dirname_result"
+       ;;
+
+      *)
+       func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+       continue
+       ;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+       eval "$shlibpath_var=\"\$dir\""
+      else
+       eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+       # Do a test to see if this is really a libtool program.
+       if func_ltwrapper_script_p "$file"; then
+         func_source "$file"
+         # Transform arg to wrapped name.
+         file="$progdir/$program"
+       elif func_ltwrapper_executable_p "$file"; then
+         func_ltwrapper_scriptname "$file"
+         func_source "$func_ltwrapper_scriptname_result"
+         # Transform arg to wrapped name.
+         file="$progdir/$program"
+       fi
+       ;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+       # Export the shlibpath_var.
+       eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+       eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+             else
+               $lt_unset $lt_var
+             fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+       eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+       echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+       func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+       if func_lalib_unsafe_p "$opt"; then
+         func_append libs " $opt"
+       else
+         func_warning "\`$opt' is not a valid libtool archive"
+       fi
+
+      else
+       func_fatal_error "invalid argument \`$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+         sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+           > $tmpdir/tmp-la
+         mv -f $tmpdir/tmp-la $lib
+       done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+       if test -n "$finish_cmds"; then
+         # Do each command in the finish commands.
+         func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+       fi
+       if test -n "$finish_eval"; then
+         # Do the single finish_eval.
+         eval cmds=\"$finish_eval\"
+         $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+       fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+       $ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+       echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+       echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+       echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+       echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+       libdir=LIBDIR
+       eval flag=\"$hardcode_libdir_flag_spec\"
+
+       $ECHO "   - use the \`$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+       $ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+       echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+       solaris2.[6789]|solaris2.1[0-9])
+         echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+         echo "pages."
+         ;;
+       *)
+         echo "more information, such as the ld(1) and ld.so(8) manual pages."
+         ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+       func_append files " $dest"
+       dest=$arg
+       continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+       if $install_cp; then :; else
+         prev=$arg
+       fi
+       ;;
+      -g | -m | -o)
+       prev=$arg
+       ;;
+      -s)
+       stripme=" -s"
+       continue
+       ;;
+      -*)
+       ;;
+      *)
+       # If the previous option needed an argument, then skip it.
+       if test -n "$prev"; then
+         if test "x$prev" = x-m && test -n "$install_override_mode"; then
+           arg2=$install_override_mode
+           no_mode=false
+         fi
+         prev=
+       else
+         dest=$arg
+         continue
+       fi
+       ;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+       func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+       func_quote_for_eval "$install_override_mode"
+       func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+       func_fatal_help "no file or destination specified"
+      else
+       func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+       func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+       case $file in
+       *.lo) ;;
+       *)
+         func_fatal_help "\`$destdir' must be an absolute directory name"
+         ;;
+       esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+       # Do the static libraries later.
+       func_append staticlibs " $file"
+       ;;
+
+      *.la)
+       func_resolve_sysroot "$file"
+       file=$func_resolve_sysroot_result
+
+       # Check to see that this really is a libtool archive.
+       func_lalib_unsafe_p "$file" \
+         || func_fatal_help "\`$file' is not a valid libtool archive"
+
+       library_names=
+       old_library=
+       relink_command=
+       func_source "$file"
+
+       # Add the libdir to current_libdirs if it is the destination.
+       if test "X$destdir" = "X$libdir"; then
+         case "$current_libdirs " in
+         *" $libdir "*) ;;
+         *) func_append current_libdirs " $libdir" ;;
+         esac
+       else
+         # Note the libdir as a future libdir.
+         case "$future_libdirs " in
+         *" $libdir "*) ;;
+         *) func_append future_libdirs " $libdir" ;;
+         esac
+       fi
+
+       func_dirname "$file" "/" ""
+       dir="$func_dirname_result"
+       func_append dir "$objdir"
+
+       if test -n "$relink_command"; then
+         # Determine the prefix the user has applied to our future dir.
+         inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+         # Don't allow the user to place us outside of our expected
+         # location b/c this prevents finding dependent libraries that
+         # are installed to the same prefix.
+         # At present, this check doesn't affect windows .dll's that
+         # are installed into $libdir/../bin (currently, that works fine)
+         # but it's something to keep an eye on.
+         test "$inst_prefix_dir" = "$destdir" && \
+           func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+         if test -n "$inst_prefix_dir"; then
+           # Stick the inst_prefix_dir data into the link command.
+           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+         else
+           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+         fi
+
+         func_warning "relinking \`$file'"
+         func_show_eval "$relink_command" \
+           'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+       fi
+
+       # See the names of the shared library.
+       set dummy $library_names; shift
+       if test -n "$1"; then
+         realname="$1"
+         shift
+
+         srcname="$realname"
+         test -n "$relink_command" && srcname="$realname"T
+
+         # Install the shared library and build the symlinks.
+         func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+             'exit $?'
+         tstripme="$stripme"
+         case $host_os in
+         cygwin* | mingw* | pw32* | cegcc*)
+           case $realname in
+           *.dll.a)
+             tstripme=""
+             ;;
+           esac
+           ;;
+         esac
+         if test -n "$tstripme" && test -n "$striplib"; then
+           func_show_eval "$striplib $destdir/$realname" 'exit $?'
+         fi
+
+         if test "$#" -gt 0; then
+           # Delete the old symlinks, and create new ones.
+           # Try `ln -sf' first, because the `ln' binary might depend on
+           # the symlink we replace!  Solaris /bin/ln does not understand -f,
+           # so we also need to try rm && ln -s.
+           for linkname
+           do
+             test "$linkname" != "$realname" \
+               && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+           done
+         fi
+
+         # Do each command in the postinstall commands.
+         lib="$destdir/$realname"
+         func_execute_cmds "$postinstall_cmds" 'exit $?'
+       fi
+
+       # Install the pseudo-library for information purposes.
+       func_basename "$file"
+       name="$func_basename_result"
+       instname="$dir/$name"i
+       func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+       # Maybe install the static library, too.
+       test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+       ;;
+
+      *.lo)
+       # Install (i.e. copy) a libtool object.
+
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile="$destdir/$destname"
+       else
+         func_basename "$file"
+         destfile="$func_basename_result"
+         destfile="$destdir/$destfile"
+       fi
+
+       # Deduce the name of the destination old-style object file.
+       case $destfile in
+       *.lo)
+         func_lo2o "$destfile"
+         staticdest=$func_lo2o_result
+         ;;
+       *.$objext)
+         staticdest="$destfile"
+         destfile=
+         ;;
+       *)
+         func_fatal_help "cannot copy a libtool object to \`$destfile'"
+         ;;
+       esac
+
+       # Install the libtool object if requested.
+       test -n "$destfile" && \
+         func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+       # Install the old object if enabled.
+       if test "$build_old_libs" = yes; then
+         # Deduce the name of the old-style object file.
+         func_lo2o "$file"
+         staticobj=$func_lo2o_result
+         func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+       fi
+       exit $EXIT_SUCCESS
+       ;;
+
+      *)
+       # Figure out destination file name, if it wasn't already specified.
+       if test -n "$destname"; then
+         destfile="$destdir/$destname"
+       else
+         func_basename "$file"
+         destfile="$func_basename_result"
+         destfile="$destdir/$destfile"
+       fi
+
+       # If the file is missing, and there is a .exe on the end, strip it
+       # because it is most likely a libtool script we actually want to
+       # install
+       stripped_ext=""
+       case $file in
+         *.exe)
+           if test ! -f "$file"; then
+             func_stripname '' '.exe' "$file"
+             file=$func_stripname_result
+             stripped_ext=".exe"
+           fi
+           ;;
+       esac
+
+       # Do a test to see if this is really a libtool program.
+       case $host in
+       *cygwin* | *mingw*)
+           if func_ltwrapper_executable_p "$file"; then
+             func_ltwrapper_scriptname "$file"
+             wrapper=$func_ltwrapper_scriptname_result
+           else
+             func_stripname '' '.exe' "$file"
+             wrapper=$func_stripname_result
+           fi
+           ;;
+       *)
+           wrapper=$file
+           ;;
+       esac
+       if func_ltwrapper_script_p "$wrapper"; then
+         notinst_deplibs=
+         relink_command=
+
+         func_source "$wrapper"
+
+         # Check the variables that should have been set.
+         test -z "$generated_by_libtool_version" && \
+           func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+         finalize=yes
+         for lib in $notinst_deplibs; do
+           # Check to see that each library is installed.
+           libdir=
+           if test -f "$lib"; then
+             func_source "$lib"
+           fi
+           libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+           if test -n "$libdir" && test ! -f "$libfile"; then
+             func_warning "\`$lib' has not been installed in \`$libdir'"
+             finalize=no
+           fi
+         done
+
+         relink_command=
+         func_source "$wrapper"
+
+         outputname=
+         if test "$fast_install" = no && test -n "$relink_command"; then
+           $opt_dry_run || {
+             if test "$finalize" = yes; then
+               tmpdir=`func_mktempdir`
+               func_basename "$file$stripped_ext"
+               file="$func_basename_result"
+               outputname="$tmpdir/$file"
+               # Replace the output file specification.
+               relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+               $opt_silent || {
+                 func_quote_for_expand "$relink_command"
+                 eval "func_echo $func_quote_for_expand_result"
+               }
+               if eval "$relink_command"; then :
+                 else
+                 func_error "error: relink \`$file' with the above command before installing it"
+                 $opt_dry_run || ${RM}r "$tmpdir"
+                 continue
+               fi
+               file="$outputname"
+             else
+               func_warning "cannot relink \`$file'"
+             fi
+           }
+         else
+           # Install the binary that we compiled earlier.
+           file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+         fi
+       fi
+
+       # remove .exe since cygwin /usr/bin/install will append another
+       # one anyway
+       case $install_prog,$host in
+       */usr/bin/install*,*cygwin*)
+         case $file:$destfile in
+         *.exe:*.exe)
+           # this is ok
+           ;;
+         *.exe:*)
+           destfile=$destfile.exe
+           ;;
+         *:*.exe)
+           func_stripname '' '.exe' "$destfile"
+           destfile=$func_stripname_result
+           ;;
+         esac
+         ;;
+       esac
+       func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+       $opt_dry_run || if test -n "$outputname"; then
+         ${RM}r "$tmpdir"
+       fi
+       ;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+       func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+       my_dlsyms="${my_outputname}S.c"
+      else
+       func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+       # Discover the nlist of each of the dlfiles.
+       nlist="$output_objdir/${my_outputname}.nm"
+
+       func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+       # Parse the name list into a source file.
+       func_verbose "creating $output_objdir/$my_dlsyms"
+
+       $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+       if test "$dlself" = yes; then
+         func_verbose "generating symbol list for \`$output'"
+
+         $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+         # Add our own program objects to the symbol list.
+         progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+         for progfile in $progfiles; do
+           func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+           func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+           $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+         done
+
+         if test -n "$exclude_expsyms"; then
+           $opt_dry_run || {
+             eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+             eval '$MV "$nlist"T "$nlist"'
+           }
+         fi
+
+         if test -n "$export_symbols_regex"; then
+           $opt_dry_run || {
+             eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+             eval '$MV "$nlist"T "$nlist"'
+           }
+         fi
+
+         # Prepare the list of exported symbols
+         if test -z "$export_symbols"; then
+           export_symbols="$output_objdir/$outputname.exp"
+           $opt_dry_run || {
+             $RM $export_symbols
+             eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+             case $host in
+             *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+               ;;
+             esac
+           }
+         else
+           $opt_dry_run || {
+             eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+             eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+             eval '$MV "$nlist"T "$nlist"'
+             case $host in
+               *cygwin* | *mingw* | *cegcc* )
+                 eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                 eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+                 ;;
+             esac
+           }
+         fi
+       fi
+
+       for dlprefile in $dlprefiles; do
+         func_verbose "extracting global C symbols from \`$dlprefile'"
+         func_basename "$dlprefile"
+         name="$func_basename_result"
+          case $host in
+           *cygwin* | *mingw* | *cegcc* )
+             # if an import library, we need to obtain dlname
+             if func_win32_import_lib_p "$dlprefile"; then
+               func_tr_sh "$dlprefile"
+               eval "curr_lafile=\$libfile_$func_tr_sh_result"
+               dlprefile_dlbasename=""
+               if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+                 # Use subshell, to avoid clobbering current variable values
+                 dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+                 if test -n "$dlprefile_dlname" ; then
+                   func_basename "$dlprefile_dlname"
+                   dlprefile_dlbasename="$func_basename_result"
+                 else
+                   # no lafile. user explicitly requested -dlpreopen <import library>.
+                   $sharedlib_from_linklib_cmd "$dlprefile"
+                   dlprefile_dlbasename=$sharedlib_from_linklib_result
+                 fi
+               fi
+               $opt_dry_run || {
+                 if test -n "$dlprefile_dlbasename" ; then
+                   eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+                 else
+                   func_warning "Could not compute DLL name from $name"
+                   eval '$ECHO ": $name " >> "$nlist"'
+                 fi
+                 func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+                 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+                   $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+               }
+             else # not an import lib
+               $opt_dry_run || {
+                 eval '$ECHO ": $name " >> "$nlist"'
+                 func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+                 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+               }
+             fi
+           ;;
+           *)
+             $opt_dry_run || {
+               eval '$ECHO ": $name " >> "$nlist"'
+               func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+               eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+             }
+           ;;
+          esac
+       done
+
+       $opt_dry_run || {
+         # Make sure we have at least an empty file.
+         test -f "$nlist" || : > "$nlist"
+
+         if test -n "$exclude_expsyms"; then
+           $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+           $MV "$nlist"T "$nlist"
+         fi
+
+         # Try sorting and uniquifying the output.
+         if $GREP -v "^: " < "$nlist" |
+             if sort -k 3 </dev/null >/dev/null 2>&1; then
+               sort -k 3
+             else
+               sort +2
+             fi |
+             uniq > "$nlist"S; then
+           :
+         else
+           $GREP -v "^: " < "$nlist" > "$nlist"S
+         fi
+
+         if test -f "$nlist"S; then
+           eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+         else
+           echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+         fi
+
+         echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+         case $need_lib_prefix in
+         no)
+           eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+           ;;
+         *)
+           eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+           ;;
+         esac
+         echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+       } # !$opt_dry_run
+
+       pic_flag_for_symtable=
+       case "$compile_command " in
+       *" -static "*) ;;
+       *)
+         case $host in
+         # compiling the symbol table file with pic_flag works around
+         # a FreeBSD bug that causes programs to crash when -lm is
+         # linked before any other PIC object.  But we must not use
+         # pic_flag when linking with -static.  The problem exists in
+         # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+         *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+           pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+         *-*-hpux*)
+           pic_flag_for_symtable=" $pic_flag"  ;;
+         *)
+           if test "X$my_pic_p" != Xno; then
+             pic_flag_for_symtable=" $pic_flag"
+           fi
+           ;;
+         esac
+         ;;
+       esac
+       symtab_cflags=
+       for arg in $LTCFLAGS; do
+         case $arg in
+         -pie | -fpie | -fPIE) ;;
+         *) func_append symtab_cflags " $arg" ;;
+         esac
+       done
+
+       # Now compile the dynamic symbol file.
+       func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+       # Clean up the generated files.
+       func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+       # Transform the symbol file into the correct name.
+       symfileobj="$output_objdir/${my_outputname}S.$objext"
+       case $host in
+       *cygwin* | *mingw* | *cegcc* )
+         if test -f "$output_objdir/$my_outputname.def"; then
+           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+         else
+           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         fi
+         ;;
+       *)
+         compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+         ;;
+       esac
+       ;;
+      *)
+       func_fatal_error "unknown suffix for \`$my_dlsyms'"
+       ;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      func_to_tool_file "$1" func_convert_file_msys_to_w32
+      win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+       $SED -n -e '
+           1,100{
+               / I /{
+                   s,.*,import,
+                   p
+                   q
+               }
+           }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $opt_debug
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $opt_debug
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[         ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive which possess that section. Heuristic: eliminate
+    # all those which have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $opt_debug
+  if func_cygming_gnu_implib_p "$1" ; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1" ; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=""
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+       func_echo "Waiting for $lockfile to be removed"
+       sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+                  'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+       [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+       *) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+       *" $my_xlib_u "*)
+         func_arith $extracted_serial + 1
+         extracted_serial=$func_arith_result
+         my_xlib_u=lt$extracted_serial-$my_xlib ;;
+       *) break ;;
+       esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+       func_verbose "Extracting $my_xabs"
+       # Do not bother doing anything if just a dry run
+       $opt_dry_run || {
+         darwin_orig_dir=`pwd`
+         cd $my_xdir || exit $?
+         darwin_archive=$my_xabs
+         darwin_curdir=`pwd`
+         darwin_base_archive=`basename "$darwin_archive"`
+         darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+         if test -n "$darwin_arches"; then
+           darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+           darwin_arch=
+           func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+           for darwin_arch in  $darwin_arches ; do
+             func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+             $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+             cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+             func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+             cd "$darwin_curdir"
+             $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+           done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+           darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+           darwin_file=
+           darwin_files=
+           for darwin_file in $darwin_filelist; do
+             darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+             $LIPO -create -output "$darwin_file" $darwin_files
+           done # $darwin_filelist
+           $RM -rf unfat-$$
+           cd "$darwin_orig_dir"
+         else
+           cd $darwin_orig_dir
+           func_extract_an_archive "$my_xdir" "$my_xabs"
+         fi # $darwin_arches
+       } # !$opt_dry_run
+       ;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+       ;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+       func_emit_wrapper_arg1=${1-no}
+
+       $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+       if test "$fast_install" = yes; then
+         $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+         $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+       $ECHO \"\$relink_command_output\" >&2
+       $RM \"\$progdir/\$file\"
+       exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+       else
+         $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+       fi
+
+       $ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+       # fixup the dll searchpath if we need to.
+       #
+       # Fix the DLL searchpath if we need to.  Do this before prepending
+       # to shlibpath, because on Windows, both are PATH and uninstalled
+       # libraries must come first.
+       if test -n "$dllsearchpath"; then
+         $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+       fi
+
+       # Export our shlibpath_var if we have one.
+       if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+         $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+       fi
+
+       $ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+       cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+           cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+       (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+           cat <<EOF
+volatile const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+           if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+             cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+           else
+             cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+           fi
+
+           if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+             cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+           else
+             cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+           fi
+
+           if test "$fast_install" = yes; then
+             cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+           else
+             cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+           fi
+
+
+           cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], dumpscript_opt) == 0)
+       {
+EOF
+           case "$host" in
+             *mingw* | *cygwin* )
+               # make stdout use "unix" line endings
+               echo "          setmode(1,_O_BINARY);"
+               ;;
+             esac
+
+           cat <<"EOF"
+         lt_dump_script (stdout);
+         return 0;
+       }
+      if (strcmp (argv[i], debug_opt) == 0)
+       {
+          lt_debug = 1;
+          continue;
+       }
+      if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+                   "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+           cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+           cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+                 tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+                 actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(main) libtool target name: %s\n",
+                 target_name);
+EOF
+
+           cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+                   strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+           cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+           case $host_os in
+             mingw*)
+           cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+       *p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+       *p = '/';
+      }
+  }
+EOF
+           ;;
+           esac
+
+           cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+                 nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+                     i, nonnull (newargz[i]));
+    }
+
+EOF
+
+           case $host_os in
+             mingw*)
+               cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+                     "(main) failed to launch target \"%s\": %s\n",
+                     lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+               ;;
+             *)
+               cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+               ;;
+           esac
+
+           cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+                         string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+       return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+       {
+         concat_name = xstrdup (wrapper);
+         if (check_executable (concat_name))
+           return concat_name;
+         XFREE (concat_name);
+       }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+       has_slash = 1;
+       break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+       {
+         for (p = path; *p; p = p_next)
+           {
+             const char *q;
+             size_t p_len;
+             for (q = p; *q; q++)
+               if (IS_PATH_SEPARATOR (*q))
+                 break;
+             p_len = q - p;
+             p_next = (*q == '\0' ? q : q + 1);
+             if (p_len == 0)
+               {
+                 /* empty path: current directory */
+                 if (getcwd (tmp, LT_PATHMAX) == NULL)
+                   lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+                 tmp_len = strlen (tmp);
+                 concat_name =
+                   XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+                 memcpy (concat_name, tmp, tmp_len);
+                 concat_name[tmp_len] = '/';
+                 strcpy (concat_name + tmp_len + 1, wrapper);
+               }
+             else
+               {
+                 concat_name =
+                   XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+                 memcpy (concat_name, p, p_len);
+                 concat_name[p_len] = '/';
+                 strcpy (concat_name + p_len + 1, wrapper);
+               }
+             if (check_executable (concat_name))
+               return concat_name;
+             XFREE (concat_name);
+           }
+       }
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+                     "checking path component for symlinks: %s\n",
+                     tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+       {
+         if (S_ISLNK (s.st_mode) != 0)
+           {
+             has_symlinks = 1;
+             break;
+           }
+
+         /* search backwards for last DIR_SEPARATOR */
+         p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+         while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+           p--;
+         if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+           {
+             /* no more DIR_SEPARATORS left */
+             break;
+           }
+         *p = '\0';
+       }
+      else
+       {
+         lt_fatal (__FILE__, __LINE__,
+                   "error accessing file \"%s\": %s",
+                   tmp_pathspec, nonnull (strerror (errno)));
+       }
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+               "could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+       *str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+              int line, const char *mode,
+              const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+                 "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+           case $host_os in
+             mingw*)
+               cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+       new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+       {
+         int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+         size_t length;
+         unsigned int backslashes;
+         const char *s;
+         char *quoted_string;
+         char *p;
+
+         length = 0;
+         backslashes = 0;
+         if (quote_around)
+           length++;
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               length += backslashes + 1;
+             length++;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           length += backslashes + 1;
+
+         quoted_string = XMALLOC (char, length + 1);
+
+         p = quoted_string;
+         backslashes = 0;
+         if (quote_around)
+           *p++ = '"';
+         for (s = string; *s != '\0'; s++)
+           {
+             char c = *s;
+             if (c == '"')
+               {
+                 unsigned int j;
+                 for (j = backslashes + 1; j > 0; j--)
+                   *p++ = '\\';
+               }
+             *p++ = c;
+             if (c == '\\')
+               backslashes++;
+             else
+               backslashes = 0;
+           }
+         if (quote_around)
+           {
+             unsigned int j;
+             for (j = backslashes; j > 0; j--)
+               *p++ = '\\';
+             *p++ = '"';
+           }
+         *p = '\0';
+
+         new_argv[i] = quoted_string;
+       }
+      else
+       new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+               ;;
+           esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+           func_emit_wrapper yes |
+             $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+       test "$build_libtool_libs" != yes && \
+         func_fatal_configuration "can not build a shared library"
+       build_old_libs=no
+       break
+       ;;
+      -all-static | -static | -static-libtool-libs)
+       case $arg in
+       -all-static)
+         if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+           func_warning "complete static linking is impossible in this configuration"
+         fi
+         if test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+         prefer_static_libs=yes
+         ;;
+       -static)
+         if test -z "$pic_flag" && test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+         prefer_static_libs=built
+         ;;
+       -static-libtool-libs)
+         if test -z "$pic_flag" && test -n "$link_static_flag"; then
+           dlopen_self=$dlopen_self_static
+         fi
+         prefer_static_libs=yes
+         ;;
+       esac
+       build_libtool_libs=no
+       build_old_libs=yes
+       break
+       ;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+       case $prev in
+       output)
+         func_append compile_command " @OUTPUT@"
+         func_append finalize_command " @OUTPUT@"
+         ;;
+       esac
+
+       case $prev in
+       bindir)
+         bindir="$arg"
+         prev=
+         continue
+         ;;
+       dlfiles|dlprefiles)
+         if test "$preload" = no; then
+           # Add the symbol object into the linking commands.
+           func_append compile_command " @SYMFILE@"
+           func_append finalize_command " @SYMFILE@"
+           preload=yes
+         fi
+         case $arg in
+         *.la | *.lo) ;;  # We handle these cases below.
+         force)
+           if test "$dlself" = no; then
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         self)
+           if test "$prev" = dlprefiles; then
+             dlself=yes
+           elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+             dlself=yes
+           else
+             dlself=needless
+             export_dynamic=yes
+           fi
+           prev=
+           continue
+           ;;
+         *)
+           if test "$prev" = dlfiles; then
+             func_append dlfiles " $arg"
+           else
+             func_append dlprefiles " $arg"
+           fi
+           prev=
+           continue
+           ;;
+         esac
+         ;;
+       expsyms)
+         export_symbols="$arg"
+         test -f "$arg" \
+           || func_fatal_error "symbol file \`$arg' does not exist"
+         prev=
+         continue
+         ;;
+       expsyms_regex)
+         export_symbols_regex="$arg"
+         prev=
+         continue
+         ;;
+       framework)
+         case $host in
+           *-*-darwin*)
+             case "$deplibs " in
+               *" $qarg.ltframework "*) ;;
+               *) func_append deplibs " $qarg.ltframework" # this is fixed later
+                  ;;
+             esac
+             ;;
+         esac
+         prev=
+         continue
+         ;;
+       inst_prefix)
+         inst_prefix_dir="$arg"
+         prev=
+         continue
+         ;;
+       objectlist)
+         if test -f "$arg"; then
+           save_arg=$arg
+           moreargs=
+           for fil in `cat "$save_arg"`
+           do
+#            func_append moreargs " $fil"
+             arg=$fil
+             # A libtool-controlled object.
+
+             # Check to see that this really is a libtool object.
+             if func_lalib_unsafe_p "$arg"; then
+               pic_object=
+               non_pic_object=
+
+               # Read the .lo file
+               func_source "$arg"
+
+               if test -z "$pic_object" ||
+                  test -z "$non_pic_object" ||
+                  test "$pic_object" = none &&
+                  test "$non_pic_object" = none; then
+                 func_fatal_error "cannot find name of object for \`$arg'"
+               fi
+
+               # Extract subdirectory from the argument.
+               func_dirname "$arg" "/" ""
+               xdir="$func_dirname_result"
+
+               if test "$pic_object" != none; then
+                 # Prepend the subdirectory the object is found in.
+                 pic_object="$xdir$pic_object"
+
+                 if test "$prev" = dlfiles; then
+                   if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+                     func_append dlfiles " $pic_object"
+                     prev=
+                     continue
+                   else
+                     # If libtool objects are unsupported, then we need to preload.
+                     prev=dlprefiles
+                   fi
+                 fi
+
+                 # CHECK ME:  I think I busted this.  -Ossama
+                 if test "$prev" = dlprefiles; then
+                   # Preload the old-style object.
+                   func_append dlprefiles " $pic_object"
+                   prev=
+                 fi
+
+                 # A PIC object.
+                 func_append libobjs " $pic_object"
+                 arg="$pic_object"
+               fi
+
+               # Non-PIC object.
+               if test "$non_pic_object" != none; then
+                 # Prepend the subdirectory the object is found in.
+                 non_pic_object="$xdir$non_pic_object"
+
+                 # A standard non-PIC object
+                 func_append non_pic_objects " $non_pic_object"
+                 if test -z "$pic_object" || test "$pic_object" = none ; then
+                   arg="$non_pic_object"
+                 fi
+               else
+                 # If the PIC object exists, use it instead.
+                 # $xdir was prepended to $pic_object above.
+                 non_pic_object="$pic_object"
+                 func_append non_pic_objects " $non_pic_object"
+               fi
+             else
+               # Only an error if not doing a dry-run.
+               if $opt_dry_run; then
+                 # Extract subdirectory from the argument.
+                 func_dirname "$arg" "/" ""
+                 xdir="$func_dirname_result"
+
+                 func_lo2o "$arg"
+                 pic_object=$xdir$objdir/$func_lo2o_result
+                 non_pic_object=$xdir$func_lo2o_result
+                 func_append libobjs " $pic_object"
+                 func_append non_pic_objects " $non_pic_object"
+               else
+                 func_fatal_error "\`$arg' is not a valid libtool object"
+               fi
+             fi
+           done
+         else
+           func_fatal_error "link input file \`$arg' does not exist"
+         fi
+         arg=$save_arg
+         prev=
+         continue
+         ;;
+       precious_regex)
+         precious_files_regex="$arg"
+         prev=
+         continue
+         ;;
+       release)
+         release="-$arg"
+         prev=
+         continue
+         ;;
+       rpath | xrpath)
+         # We need an absolute path.
+         case $arg in
+         [\\/]* | [A-Za-z]:[\\/]*) ;;
+         *)
+           func_fatal_error "only absolute run-paths are allowed"
+           ;;
+         esac
+         if test "$prev" = rpath; then
+           case "$rpath " in
+           *" $arg "*) ;;
+           *) func_append rpath " $arg" ;;
+           esac
+         else
+           case "$xrpath " in
+           *" $arg "*) ;;
+           *) func_append xrpath " $arg" ;;
+           esac
+         fi
+         prev=
+         continue
+         ;;
+       shrext)
+         shrext_cmds="$arg"
+         prev=
+         continue
+         ;;
+       weak)
+         func_append weak_libs " $arg"
+         prev=
+         continue
+         ;;
+       xcclinker)
+         func_append linker_flags " $qarg"
+         func_append compiler_flags " $qarg"
+         prev=
+         func_append compile_command " $qarg"
+         func_append finalize_command " $qarg"
+         continue
+         ;;
+       xcompiler)
+         func_append compiler_flags " $qarg"
+         prev=
+         func_append compile_command " $qarg"
+         func_append finalize_command " $qarg"
+         continue
+         ;;
+       xlinker)
+         func_append linker_flags " $qarg"
+         func_append compiler_flags " $wl$qarg"
+         prev=
+         func_append compile_command " $wl$qarg"
+         func_append finalize_command " $wl$qarg"
+         continue
+         ;;
+       *)
+         eval "$prev=\"\$arg\""
+         prev=
+         continue
+         ;;
+       esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+       if test -n "$link_static_flag"; then
+         # See comment for -static flag below, for more details.
+         func_append compile_command " $link_static_flag"
+         func_append finalize_command " $link_static_flag"
+       fi
+       continue
+       ;;
+
+      -allow-undefined)
+       # FIXME: remove this flag sometime in the future.
+       func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+       ;;
+
+      -avoid-version)
+       avoid_version=yes
+       continue
+       ;;
+
+      -bindir)
+       prev=bindir
+       continue
+       ;;
+
+      -dlopen)
+       prev=dlfiles
+       continue
+       ;;
+
+      -dlpreopen)
+       prev=dlprefiles
+       continue
+       ;;
+
+      -export-dynamic)
+       export_dynamic=yes
+       continue
+       ;;
+
+      -export-symbols | -export-symbols-regex)
+       if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+         func_fatal_error "more than one -exported-symbols argument is not allowed"
+       fi
+       if test "X$arg" = "X-export-symbols"; then
+         prev=expsyms
+       else
+         prev=expsyms_regex
+       fi
+       continue
+       ;;
+
+      -framework)
+       prev=framework
+       continue
+       ;;
+
+      -inst-prefix-dir)
+       prev=inst_prefix
+       continue
+       ;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+       case $with_gcc/$host in
+       no/*-*-irix* | /*-*-irix*)
+         func_append compile_command " $arg"
+         func_append finalize_command " $arg"
+         ;;
+       esac
+       continue
+       ;;
+
+      -L*)
+       func_stripname "-L" '' "$arg"
+       if test -z "$func_stripname_result"; then
+         if test "$#" -gt 0; then
+           func_fatal_error "require no space between \`-L' and \`$1'"
+         else
+           func_fatal_error "need path for \`-L' option"
+         fi
+       fi
+       func_resolve_sysroot "$func_stripname_result"
+       dir=$func_resolve_sysroot_result
+       # We need an absolute path.
+       case $dir in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       *)
+         absdir=`cd "$dir" && pwd`
+         test -z "$absdir" && \
+           func_fatal_error "cannot determine absolute directory name of \`$dir'"
+         dir="$absdir"
+         ;;
+       esac
+       case "$deplibs " in
+       *" -L$dir "* | *" $arg "*)
+         # Will only happen for absolute or sysroot arguments
+         ;;
+       *)
+         # Preserve sysroot, but never include relative directories
+         case $dir in
+           [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+           *) func_append deplibs " -L$dir" ;;
+         esac
+         func_append lib_search_path " $dir"
+         ;;
+       esac
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+         testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+         case :$dllsearchpath: in
+         *":$dir:"*) ;;
+         ::) dllsearchpath=$dir;;
+         *) func_append dllsearchpath ":$dir";;
+         esac
+         case :$dllsearchpath: in
+         *":$testbindir:"*) ;;
+         ::) dllsearchpath=$testbindir;;
+         *) func_append dllsearchpath ":$testbindir";;
+         esac
+         ;;
+       esac
+       continue
+       ;;
+
+      -l*)
+       if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+         case $host in
+         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+           # These systems don't actually have a C or math library (as such)
+           continue
+           ;;
+         *-*-os2*)
+           # These systems don't actually have a C library (as such)
+           test "X$arg" = "X-lc" && continue
+           ;;
+         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+           # Do not include libc due to us having libc/libc_r.
+           test "X$arg" = "X-lc" && continue
+           ;;
+         *-*-rhapsody* | *-*-darwin1.[012])
+           # Rhapsody C and math libraries are in the System framework
+           func_append deplibs " System.ltframework"
+           continue
+           ;;
+         *-*-sco3.2v5* | *-*-sco5v6*)
+           # Causes problems with __ctype
+           test "X$arg" = "X-lc" && continue
+           ;;
+         *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+           # Compiler inserts libc in the correct place for threads to work
+           test "X$arg" = "X-lc" && continue
+           ;;
+         esac
+       elif test "X$arg" = "X-lc_r"; then
+        case $host in
+        *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+          # Do not include libc_r directly, use -pthread flag.
+          continue
+          ;;
+        esac
+       fi
+       func_append deplibs " $arg"
+       continue
+       ;;
+
+      -module)
+       module=yes
+       continue
+       ;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+       func_append compiler_flags " $arg"
+       func_append compile_command " $arg"
+       func_append finalize_command " $arg"
+       prev=xcompiler
+       continue
+       ;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+       func_append compiler_flags " $arg"
+       func_append compile_command " $arg"
+       func_append finalize_command " $arg"
+       case "$new_inherited_linker_flags " in
+           *" $arg "*) ;;
+           * ) func_append new_inherited_linker_flags " $arg" ;;
+       esac
+       continue
+       ;;
+
+      -multi_module)
+       single_module="${wl}-multi_module"
+       continue
+       ;;
+
+      -no-fast-install)
+       fast_install=no
+       continue
+       ;;
+
+      -no-install)
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+         # The PATH hackery in wrapper scripts is required on Windows
+         # and Darwin in order for the loader to find any dlls it needs.
+         func_warning "\`-no-install' is ignored for $host"
+         func_warning "assuming \`-no-fast-install' instead"
+         fast_install=no
+         ;;
+       *) no_install=yes ;;
+       esac
+       continue
+       ;;
+
+      -no-undefined)
+       allow_undefined=no
+       continue
+       ;;
+
+      -objectlist)
+       prev=objectlist
+       continue
+       ;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+       prev=precious_regex
+       continue
+       ;;
+
+      -release)
+       prev=release
+       continue
+       ;;
+
+      -rpath)
+       prev=rpath
+       continue
+       ;;
+
+      -R)
+       prev=xrpath
+       continue
+       ;;
+
+      -R*)
+       func_stripname '-R' '' "$arg"
+       dir=$func_stripname_result
+       # We need an absolute path.
+       case $dir in
+       [\\/]* | [A-Za-z]:[\\/]*) ;;
+       =*)
+         func_stripname '=' '' "$dir"
+         dir=$lt_sysroot$func_stripname_result
+         ;;
+       *)
+         func_fatal_error "only absolute run-paths are allowed"
+         ;;
+       esac
+       case "$xrpath " in
+       *" $dir "*) ;;
+       *) func_append xrpath " $dir" ;;
+       esac
+       continue
+       ;;
+
+      -shared)
+       # The effects of -shared are defined in a previous loop.
+       continue
+       ;;
+
+      -shrext)
+       prev=shrext
+       continue
+       ;;
+
+      -static | -static-libtool-libs)
+       # The effects of -static are defined in a previous loop.
+       # We used to do the same as -all-static on platforms that
+       # didn't have a PIC flag, but the assumption that the effects
+       # would be equivalent was wrong.  It would break on at least
+       # Digital Unix and AIX.
+       continue
+       ;;
+
+      -thread-safe)
+       thread_safe=yes
+       continue
+       ;;
+
+      -version-info)
+       prev=vinfo
+       continue
+       ;;
+
+      -version-number)
+       prev=vinfo
+       vinfo_number=yes
+       continue
+       ;;
+
+      -weak)
+        prev=weak
+       continue
+       ;;
+
+      -Wc,*)
+       func_stripname '-Wc,' '' "$arg"
+       args=$func_stripname_result
+       arg=
+       save_ifs="$IFS"; IFS=','
+       for flag in $args; do
+         IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+         func_append arg " $func_quote_for_eval_result"
+         func_append compiler_flags " $func_quote_for_eval_result"
+       done
+       IFS="$save_ifs"
+       func_stripname ' ' '' "$arg"
+       arg=$func_stripname_result
+       ;;
+
+      -Wl,*)
+       func_stripname '-Wl,' '' "$arg"
+       args=$func_stripname_result
+       arg=
+       save_ifs="$IFS"; IFS=','
+       for flag in $args; do
+         IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+         func_append arg " $wl$func_quote_for_eval_result"
+         func_append compiler_flags " $wl$func_quote_for_eval_result"
+         func_append linker_flags " $func_quote_for_eval_result"
+       done
+       IFS="$save_ifs"
+       func_stripname ' ' '' "$arg"
+       arg=$func_stripname_result
+       ;;
+
+      -Xcompiler)
+       prev=xcompiler
+       continue
+       ;;
+
+      -Xlinker)
+       prev=xlinker
+       continue
+       ;;
+
+      -XCClinker)
+       prev=xcclinker
+       continue
+       ;;
+
+      # -msg_* for osf cc
+      -msg_*)
+       func_quote_for_eval "$arg"
+       arg="$func_quote_for_eval_result"
+       ;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+        func_quote_for_eval "$arg"
+       arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+       arg="$func_quote_for_eval_result"
+       ;;
+
+      *.$objext)
+       # A standard object.
+       func_append objs " $arg"
+       ;;
+
+      *.lo)
+       # A libtool-controlled object.
+
+       # Check to see that this really is a libtool object.
+       if func_lalib_unsafe_p "$arg"; then
+         pic_object=
+         non_pic_object=
+
+         # Read the .lo file
+         func_source "$arg"
+
+         if test -z "$pic_object" ||
+            test -z "$non_pic_object" ||
+            test "$pic_object" = none &&
+            test "$non_pic_object" = none; then
+           func_fatal_error "cannot find name of object for \`$arg'"
+         fi
+
+         # Extract subdirectory from the argument.
+         func_dirname "$arg" "/" ""
+         xdir="$func_dirname_result"
+
+         if test "$pic_object" != none; then
+           # Prepend the subdirectory the object is found in.
+           pic_object="$xdir$pic_object"
+
+           if test "$prev" = dlfiles; then
+             if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+               func_append dlfiles " $pic_object"
+               prev=
+               continue
+             else
+               # If libtool objects are unsupported, then we need to preload.
+               prev=dlprefiles
+             fi
+           fi
+
+           # CHECK ME:  I think I busted this.  -Ossama
+           if test "$prev" = dlprefiles; then
+             # Preload the old-style object.
+             func_append dlprefiles " $pic_object"
+             prev=
+           fi
+
+           # A PIC object.
+           func_append libobjs " $pic_object"
+           arg="$pic_object"
+         fi
+
+         # Non-PIC object.
+         if test "$non_pic_object" != none; then
+           # Prepend the subdirectory the object is found in.
+           non_pic_object="$xdir$non_pic_object"
+
+           # A standard non-PIC object
+           func_append non_pic_objects " $non_pic_object"
+           if test -z "$pic_object" || test "$pic_object" = none ; then
+             arg="$non_pic_object"
+           fi
+         else
+           # If the PIC object exists, use it instead.
+           # $xdir was prepended to $pic_object above.
+           non_pic_object="$pic_object"
+           func_append non_pic_objects " $non_pic_object"
+         fi
+       else
+         # Only an error if not doing a dry-run.
+         if $opt_dry_run; then
+           # Extract subdirectory from the argument.
+           func_dirname "$arg" "/" ""
+           xdir="$func_dirname_result"
+
+           func_lo2o "$arg"
+           pic_object=$xdir$objdir/$func_lo2o_result
+           non_pic_object=$xdir$func_lo2o_result
+           func_append libobjs " $pic_object"
+           func_append non_pic_objects " $non_pic_object"
+         else
+           func_fatal_error "\`$arg' is not a valid libtool object"
+         fi
+       fi
+       ;;
+
+      *.$libext)
+       # An archive.
+       func_append deplibs " $arg"
+       func_append old_deplibs " $arg"
+       continue
+       ;;
+
+      *.la)
+       # A libtool-controlled library.
+
+       func_resolve_sysroot "$arg"
+       if test "$prev" = dlfiles; then
+         # This library was specified with -dlopen.
+         func_append dlfiles " $func_resolve_sysroot_result"
+         prev=
+       elif test "$prev" = dlprefiles; then
+         # The library was specified with -dlpreopen.
+         func_append dlprefiles " $func_resolve_sysroot_result"
+         prev=
+       else
+         func_append deplibs " $func_resolve_sysroot_result"
+       fi
+       continue
+       ;;
+
+      # Some other compiler argument.
+      *)
+       # Unknown arguments in both finalize_command and compile_command need
+       # to be aesthetically quoted because they are evaled later.
+       func_quote_for_eval "$arg"
+       arg="$func_quote_for_eval_result"
+       ;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+       func_append compile_command " $arg"
+       func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps ; then
+       case "$libs " in
+       *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+       esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+       for pre_post_dep in $predeps $postdeps; do
+         case "$pre_post_deps " in
+         *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+         esac
+         func_append pre_post_deps " $pre_post_dep"
+       done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+       passes="conv dlpreopen link"
+       for file in $dlfiles $dlprefiles; do
+         case $file in
+         *.la) ;;
+         *)
+           func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+           ;;
+         esac
+       done
+       ;;
+    prog)
+       compile_deplibs=
+       finalize_deplibs=
+       alldeplibs=no
+       newdlfiles=
+       newdlprefiles=
+       passes="conv scan dlopen dlpreopen link"
+       ;;
+    *)  passes="conv"
+       ;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+       ## FIXME: Find the place where the list is rebuilt in the wrong
+       ##        order, and fix it there properly
+        tmp_deplibs=
+       for deplib in $deplibs; do
+         tmp_deplibs="$deplib $tmp_deplibs"
+       done
+       deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+        test "$linkmode,$pass" = "prog,scan"; then
+       libs="$deplibs"
+       deplibs=
+      fi
+      if test "$linkmode" = prog; then
+       case $pass in
+       dlopen) libs="$dlfiles" ;;
+       dlpreopen) libs="$dlprefiles" ;;
+       link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+       esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+       # Collect and forward deplibs of preopened libtool libs
+       for lib in $dlprefiles; do
+         # Ignore non-libtool-libs
+         dependency_libs=
+         func_resolve_sysroot "$lib"
+         case $lib in
+         *.la) func_source "$func_resolve_sysroot_result" ;;
+         esac
+
+         # Collect preopened libtool deplibs, except any this library
+         # has declared as weak libs
+         for deplib in $dependency_libs; do
+           func_basename "$deplib"
+            deplib_base=$func_basename_result
+           case " $weak_libs " in
+           *" $deplib_base "*) ;;
+           *) func_append deplibs " $deplib" ;;
+           esac
+         done
+       done
+       libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+       # Collect dlpreopened libraries
+       save_deplibs="$deplibs"
+       deplibs=
+      fi
+
+      for deplib in $libs; do
+       lib=
+       found=no
+       case $deplib in
+       -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+         if test "$linkmode,$pass" = "prog,link"; then
+           compile_deplibs="$deplib $compile_deplibs"
+           finalize_deplibs="$deplib $finalize_deplibs"
+         else
+           func_append compiler_flags " $deplib"
+           if test "$linkmode" = lib ; then
+               case "$new_inherited_linker_flags " in
+                   *" $deplib "*) ;;
+                   * ) func_append new_inherited_linker_flags " $deplib" ;;
+               esac
+           fi
+         fi
+         continue
+         ;;
+       -l*)
+         if test "$linkmode" != lib && test "$linkmode" != prog; then
+           func_warning "\`-l' is ignored for archives/objects"
+           continue
+         fi
+         func_stripname '-l' '' "$deplib"
+         name=$func_stripname_result
+         if test "$linkmode" = lib; then
+           searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+         else
+           searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+         fi
+         for searchdir in $searchdirs; do
+           for search_ext in .la $std_shrext .so .a; do
+             # Search the libtool library
+             lib="$searchdir/lib${name}${search_ext}"
+             if test -f "$lib"; then
+               if test "$search_ext" = ".la"; then
+                 found=yes
+               else
+                 found=no
+               fi
+               break 2
+             fi
+           done
+         done
+         if test "$found" != yes; then
+           # deplib doesn't seem to be a libtool library
+           if test "$linkmode,$pass" = "prog,link"; then
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           else
+             deplibs="$deplib $deplibs"
+             test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+           fi
+           continue
+         else # deplib is a libtool library
+           # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+           # We need to do some special things here, and not later.
+           if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+             case " $predeps $postdeps " in
+             *" $deplib "*)
+               if func_lalib_p "$lib"; then
+                 library_names=
+                 old_library=
+                 func_source "$lib"
+                 for l in $old_library $library_names; do
+                   ll="$l"
+                 done
+                 if test "X$ll" = "X$old_library" ; then # only static version available
+                   found=no
+                   func_dirname "$lib" "" "."
+                   ladir="$func_dirname_result"
+                   lib=$ladir/$old_library
+                   if test "$linkmode,$pass" = "prog,link"; then
+                     compile_deplibs="$deplib $compile_deplibs"
+                     finalize_deplibs="$deplib $finalize_deplibs"
+                   else
+                     deplibs="$deplib $deplibs"
+                     test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+                   fi
+                   continue
+                 fi
+               fi
+               ;;
+             *) ;;
+             esac
+           fi
+         fi
+         ;; # -l
+       *.ltframework)
+         if test "$linkmode,$pass" = "prog,link"; then
+           compile_deplibs="$deplib $compile_deplibs"
+           finalize_deplibs="$deplib $finalize_deplibs"
+         else
+           deplibs="$deplib $deplibs"
+           if test "$linkmode" = lib ; then
+               case "$new_inherited_linker_flags " in
+                   *" $deplib "*) ;;
+                   * ) func_append new_inherited_linker_flags " $deplib" ;;
+               esac
+           fi
+         fi
+         continue
+         ;;
+       -L*)
+         case $linkmode in
+         lib)
+           deplibs="$deplib $deplibs"
+           test "$pass" = conv && continue
+           newdependency_libs="$deplib $newdependency_libs"
+           func_stripname '-L' '' "$deplib"
+           func_resolve_sysroot "$func_stripname_result"
+           func_append newlib_search_path " $func_resolve_sysroot_result"
+           ;;
+         prog)
+           if test "$pass" = conv; then
+             deplibs="$deplib $deplibs"
+             continue
+           fi
+           if test "$pass" = scan; then
+             deplibs="$deplib $deplibs"
+           else
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           fi
+           func_stripname '-L' '' "$deplib"
+           func_resolve_sysroot "$func_stripname_result"
+           func_append newlib_search_path " $func_resolve_sysroot_result"
+           ;;
+         *)
+           func_warning "\`-L' is ignored for archives/objects"
+           ;;
+         esac # linkmode
+         continue
+         ;; # -L
+       -R*)
+         if test "$pass" = link; then
+           func_stripname '-R' '' "$deplib"
+           func_resolve_sysroot "$func_stripname_result"
+           dir=$func_resolve_sysroot_result
+           # Make sure the xrpath contains only unique directories.
+           case "$xrpath " in
+           *" $dir "*) ;;
+           *) func_append xrpath " $dir" ;;
+           esac
+         fi
+         deplibs="$deplib $deplibs"
+         continue
+         ;;
+       *.la)
+         func_resolve_sysroot "$deplib"
+         lib=$func_resolve_sysroot_result
+         ;;
+       *.$libext)
+         if test "$pass" = conv; then
+           deplibs="$deplib $deplibs"
+           continue
+         fi
+         case $linkmode in
+         lib)
+           # Linking convenience modules into shared libraries is allowed,
+           # but linking other static libraries is non-portable.
+           case " $dlpreconveniencelibs " in
+           *" $deplib "*) ;;
+           *)
+             valid_a_lib=no
+             case $deplibs_check_method in
+               match_pattern*)
+                 set dummy $deplibs_check_method; shift
+                 match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+                 if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+                   | $EGREP "$match_pattern_regex" > /dev/null; then
+                   valid_a_lib=yes
+                 fi
+               ;;
+               pass_all)
+                 valid_a_lib=yes
+               ;;
+             esac
+             if test "$valid_a_lib" != yes; then
+               echo
+               $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because the file extensions .$libext of this argument makes me believe"
+               echo "*** that it is just a static archive that I should not use here."
+             else
+               echo
+               $ECHO "*** Warning: Linking the shared library $output against the"
+               $ECHO "*** static library $deplib is not portable!"
+               deplibs="$deplib $deplibs"
+             fi
+             ;;
+           esac
+           continue
+           ;;
+         prog)
+           if test "$pass" != link; then
+             deplibs="$deplib $deplibs"
+           else
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           fi
+           continue
+           ;;
+         esac # linkmode
+         ;; # *.$libext
+       *.lo | *.$objext)
+         if test "$pass" = conv; then
+           deplibs="$deplib $deplibs"
+         elif test "$linkmode" = prog; then
+           if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+             # If there is no dlopen support or we're linking statically,
+             # we need to preload.
+             func_append newdlprefiles " $deplib"
+             compile_deplibs="$deplib $compile_deplibs"
+             finalize_deplibs="$deplib $finalize_deplibs"
+           else
+             func_append newdlfiles " $deplib"
+           fi
+         fi
+         continue
+         ;;
+       %DEPLIBS%)
+         alldeplibs=yes
+         continue
+         ;;
+       esac # case $deplib
+
+       if test "$found" = yes || test -f "$lib"; then :
+       else
+         func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+       fi
+
+       # Check to see that this really is a libtool archive.
+       func_lalib_unsafe_p "$lib" \
+         || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+       func_dirname "$lib" "" "."
+       ladir="$func_dirname_result"
+
+       dlname=
+       dlopen=
+       dlpreopen=
+       libdir=
+       library_names=
+       old_library=
+       inherited_linker_flags=
+       # If the library was installed with an old release of libtool,
+       # it will not redefine variables installed, or shouldnotlink
+       installed=yes
+       shouldnotlink=no
+       avoidtemprpath=
+
+
+       # Read the .la file
+       func_source "$lib"
+
+       # Convert "-framework foo" to "foo.ltframework"
+       if test -n "$inherited_linker_flags"; then
+         tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+         for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+           case " $new_inherited_linker_flags " in
+             *" $tmp_inherited_linker_flag "*) ;;
+             *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+           esac
+         done
+       fi
+       dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       if test "$linkmode,$pass" = "lib,link" ||
+          test "$linkmode,$pass" = "prog,scan" ||
+          { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+         test -n "$dlopen" && func_append dlfiles " $dlopen"
+         test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+       fi
+
+       if test "$pass" = conv; then
+         # Only check for convenience libraries
+         deplibs="$lib $deplibs"
+         if test -z "$libdir"; then
+           if test -z "$old_library"; then
+             func_fatal_error "cannot find name of link library for \`$lib'"
+           fi
+           # It is a libtool convenience library, so add in its objects.
+           func_append convenience " $ladir/$objdir/$old_library"
+           func_append old_convenience " $ladir/$objdir/$old_library"
+         elif test "$linkmode" != prog && test "$linkmode" != lib; then
+           func_fatal_error "\`$lib' is not a convenience library"
+         fi
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           deplibs="$deplib $deplibs"
+           if $opt_preserve_dup_deps ; then
+             case "$tmp_libs " in
+             *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+             esac
+           fi
+           func_append tmp_libs " $deplib"
+         done
+         continue
+       fi # $pass = conv
+
+
+       # Get the name of the library we link against.
+       linklib=
+       if test -n "$old_library" &&
+          { test "$prefer_static_libs" = yes ||
+            test "$prefer_static_libs,$installed" = "built,no"; }; then
+         linklib=$old_library
+       else
+         for l in $old_library $library_names; do
+           linklib="$l"
+         done
+       fi
+       if test -z "$linklib"; then
+         func_fatal_error "cannot find name of link library for \`$lib'"
+       fi
+
+       # This library was specified with -dlopen.
+       if test "$pass" = dlopen; then
+         if test -z "$libdir"; then
+           func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+         fi
+         if test -z "$dlname" ||
+            test "$dlopen_support" != yes ||
+            test "$build_libtool_libs" = no; then
+           # If there is no dlname, no dlopen support or we're linking
+           # statically, we need to preload.  We also need to preload any
+           # dependent libraries so libltdl's deplib preloader doesn't
+           # bomb out in the load deplibs phase.
+           func_append dlprefiles " $lib $dependency_libs"
+         else
+           func_append newdlfiles " $lib"
+         fi
+         continue
+       fi # $pass = dlopen
+
+       # We need an absolute path.
+       case $ladir in
+       [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+       *)
+         abs_ladir=`cd "$ladir" && pwd`
+         if test -z "$abs_ladir"; then
+           func_warning "cannot determine absolute directory name of \`$ladir'"
+           func_warning "passing it literally to the linker, although it might fail"
+           abs_ladir="$ladir"
+         fi
+         ;;
+       esac
+       func_basename "$lib"
+       laname="$func_basename_result"
+
+       # Find the relevant object directory and library name.
+       if test "X$installed" = Xyes; then
+         if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+           func_warning "library \`$lib' was moved."
+           dir="$ladir"
+           absdir="$abs_ladir"
+           libdir="$abs_ladir"
+         else
+           dir="$lt_sysroot$libdir"
+           absdir="$lt_sysroot$libdir"
+         fi
+         test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+       else
+         if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+           dir="$ladir"
+           absdir="$abs_ladir"
+           # Remove this search path later
+           func_append notinst_path " $abs_ladir"
+         else
+           dir="$ladir/$objdir"
+           absdir="$abs_ladir/$objdir"
+           # Remove this search path later
+           func_append notinst_path " $abs_ladir"
+         fi
+       fi # $installed = yes
+       func_stripname 'lib' '.la' "$laname"
+       name=$func_stripname_result
+
+       # This library was specified with -dlpreopen.
+       if test "$pass" = dlpreopen; then
+         if test -z "$libdir" && test "$linkmode" = prog; then
+           func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+         fi
+         case "$host" in
+           # special handling for platforms with PE-DLLs.
+           *cygwin* | *mingw* | *cegcc* )
+             # Linker will automatically link against shared library if both
+             # static and shared are present.  Therefore, ensure we extract
+             # symbols from the import library if a shared library is present
+             # (otherwise, the dlopen module name will be incorrect).  We do
+             # this by putting the import library name into $newdlprefiles.
+             # We recover the dlopen module name by 'saving' the la file
+             # name in a special purpose variable, and (later) extracting the
+             # dlname from the la file.
+             if test -n "$dlname"; then
+               func_tr_sh "$dir/$linklib"
+               eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+               func_append newdlprefiles " $dir/$linklib"
+             else
+               func_append newdlprefiles " $dir/$old_library"
+               # Keep a list of preopened convenience libraries to check
+               # that they are being used correctly in the link pass.
+               test -z "$libdir" && \
+                 func_append dlpreconveniencelibs " $dir/$old_library"
+             fi
+           ;;
+           * )
+             # Prefer using a static library (so that no silly _DYNAMIC symbols
+             # are required to link).
+             if test -n "$old_library"; then
+               func_append newdlprefiles " $dir/$old_library"
+               # Keep a list of preopened convenience libraries to check
+               # that they are being used correctly in the link pass.
+               test -z "$libdir" && \
+                 func_append dlpreconveniencelibs " $dir/$old_library"
+             # Otherwise, use the dlname, so that lt_dlopen finds it.
+             elif test -n "$dlname"; then
+               func_append newdlprefiles " $dir/$dlname"
+             else
+               func_append newdlprefiles " $dir/$linklib"
+             fi
+           ;;
+         esac
+       fi # $pass = dlpreopen
+
+       if test -z "$libdir"; then
+         # Link the convenience library
+         if test "$linkmode" = lib; then
+           deplibs="$dir/$old_library $deplibs"
+         elif test "$linkmode,$pass" = "prog,link"; then
+           compile_deplibs="$dir/$old_library $compile_deplibs"
+           finalize_deplibs="$dir/$old_library $finalize_deplibs"
+         else
+           deplibs="$lib $deplibs" # used for prog,scan pass
+         fi
+         continue
+       fi
+
+
+       if test "$linkmode" = prog && test "$pass" != link; then
+         func_append newlib_search_path " $ladir"
+         deplibs="$lib $deplibs"
+
+         linkalldeplibs=no
+         if test "$link_all_deplibs" != no || test -z "$library_names" ||
+            test "$build_libtool_libs" = no; then
+           linkalldeplibs=yes
+         fi
+
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           case $deplib in
+           -L*) func_stripname '-L' '' "$deplib"
+                func_resolve_sysroot "$func_stripname_result"
+                func_append newlib_search_path " $func_resolve_sysroot_result"
+                ;;
+           esac
+           # Need to link against all dependency_libs?
+           if test "$linkalldeplibs" = yes; then
+             deplibs="$deplib $deplibs"
+           else
+             # Need to hardcode shared library paths
+             # or/and link against static libraries
+             newdependency_libs="$deplib $newdependency_libs"
+           fi
+           if $opt_preserve_dup_deps ; then
+             case "$tmp_libs " in
+             *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+             esac
+           fi
+           func_append tmp_libs " $deplib"
+         done # for deplib
+         continue
+       fi # $linkmode = prog...
+
+       if test "$linkmode,$pass" = "prog,link"; then
+         if test -n "$library_names" &&
+            { { test "$prefer_static_libs" = no ||
+                test "$prefer_static_libs,$installed" = "built,yes"; } ||
+              test -z "$old_library"; }; then
+           # We need to hardcode the library path
+           if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+             # Make sure the rpath contains only unique directories.
+             case "$temp_rpath:" in
+             *"$absdir:"*) ;;
+             *) func_append temp_rpath "$absdir:" ;;
+             esac
+           fi
+
+           # Hardcode the library path.
+           # Skip directories that are in the system default run-time
+           # search path.
+           case " $sys_lib_dlsearch_path " in
+           *" $absdir "*) ;;
+           *)
+             case "$compile_rpath " in
+             *" $absdir "*) ;;
+             *) func_append compile_rpath " $absdir" ;;
+             esac
+             ;;
+           esac
+           case " $sys_lib_dlsearch_path " in
+           *" $libdir "*) ;;
+           *)
+             case "$finalize_rpath " in
+             *" $libdir "*) ;;
+             *) func_append finalize_rpath " $libdir" ;;
+             esac
+             ;;
+           esac
+         fi # $linkmode,$pass = prog,link...
+
+         if test "$alldeplibs" = yes &&
+            { test "$deplibs_check_method" = pass_all ||
+              { test "$build_libtool_libs" = yes &&
+                test -n "$library_names"; }; }; then
+           # We only need to search for static libraries
+           continue
+         fi
+       fi
+
+       link_static=no # Whether the deplib will be linked statically
+       use_static_libs=$prefer_static_libs
+       if test "$use_static_libs" = built && test "$installed" = yes; then
+         use_static_libs=no
+       fi
+       if test -n "$library_names" &&
+          { test "$use_static_libs" = no || test -z "$old_library"; }; then
+         case $host in
+         *cygwin* | *mingw* | *cegcc*)
+             # No point in relinking DLLs because paths are not encoded
+             func_append notinst_deplibs " $lib"
+             need_relink=no
+           ;;
+         *)
+           if test "$installed" = no; then
+             func_append notinst_deplibs " $lib"
+             need_relink=yes
+           fi
+           ;;
+         esac
+         # This is a shared library
+
+         # Warn about portability, can't link against -module's on some
+         # systems (darwin).  Don't bleat about dlopened modules though!
+         dlopenmodule=""
+         for dlpremoduletest in $dlprefiles; do
+           if test "X$dlpremoduletest" = "X$lib"; then
+             dlopenmodule="$dlpremoduletest"
+             break
+           fi
+         done
+         if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+           echo
+           if test "$linkmode" = prog; then
+             $ECHO "*** Warning: Linking the executable $output against the loadable module"
+           else
+             $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+           fi
+           $ECHO "*** $linklib is not portable!"
+         fi
+         if test "$linkmode" = lib &&
+            test "$hardcode_into_libs" = yes; then
+           # Hardcode the library path.
+           # Skip directories that are in the system default run-time
+           # search path.
+           case " $sys_lib_dlsearch_path " in
+           *" $absdir "*) ;;
+           *)
+             case "$compile_rpath " in
+             *" $absdir "*) ;;
+             *) func_append compile_rpath " $absdir" ;;
+             esac
+             ;;
+           esac
+           case " $sys_lib_dlsearch_path " in
+           *" $libdir "*) ;;
+           *)
+             case "$finalize_rpath " in
+             *" $libdir "*) ;;
+             *) func_append finalize_rpath " $libdir" ;;
+             esac
+             ;;
+           esac
+         fi
+
+         if test -n "$old_archive_from_expsyms_cmds"; then
+           # figure out the soname
+           set dummy $library_names
+           shift
+           realname="$1"
+           shift
+           libname=`eval "\\$ECHO \"$libname_spec\""`
+           # use dlname if we got it. it's perfectly good, no?
+           if test -n "$dlname"; then
+             soname="$dlname"
+           elif test -n "$soname_spec"; then
+             # bleh windows
+             case $host in
+             *cygwin* | mingw* | *cegcc*)
+               func_arith $current - $age
+               major=$func_arith_result
+               versuffix="-$major"
+               ;;
+             esac
+             eval soname=\"$soname_spec\"
+           else
+             soname="$realname"
+           fi
+
+           # Make a new name for the extract_expsyms_cmds to use
+           soroot="$soname"
+           func_basename "$soroot"
+           soname="$func_basename_result"
+           func_stripname 'lib' '.dll' "$soname"
+           newlib=libimp-$func_stripname_result.a
+
+           # If the library has no export list, then create one now
+           if test -f "$output_objdir/$soname-def"; then :
+           else
+             func_verbose "extracting exported symbol list from \`$soname'"
+             func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+           fi
+
+           # Create $newlib
+           if test -f "$output_objdir/$newlib"; then :; else
+             func_verbose "generating import library for \`$soname'"
+             func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+           fi
+           # make sure the library variables are pointing to the new library
+           dir=$output_objdir
+           linklib=$newlib
+         fi # test -n "$old_archive_from_expsyms_cmds"
+
+         if test "$linkmode" = prog || test "$opt_mode" != relink; then
+           add_shlibpath=
+           add_dir=
+           add=
+           lib_linked=yes
+           case $hardcode_action in
+           immediate | unsupported)
+             if test "$hardcode_direct" = no; then
+               add="$dir/$linklib"
+               case $host in
+                 *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+                 *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+                 *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+                   *-*-unixware7*) add_dir="-L$dir" ;;
+                 *-*-darwin* )
+                   # if the lib is a (non-dlopened) module then we can not
+                   # link against it, someone is ignoring the earlier warnings
+                   if /usr/bin/file -L $add 2> /dev/null |
+                        $GREP ": [^:]* bundle" >/dev/null ; then
+                     if test "X$dlopenmodule" != "X$lib"; then
+                       $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+                       if test -z "$old_library" ; then
+                         echo
+                         echo "*** And there doesn't seem to be a static archive available"
+                         echo "*** The link will probably fail, sorry"
+                       else
+                         add="$dir/$old_library"
+                       fi
+                     elif test -n "$old_library"; then
+                       add="$dir/$old_library"
+                     fi
+                   fi
+               esac
+             elif test "$hardcode_minus_L" = no; then
+               case $host in
+               *-*-sunos*) add_shlibpath="$dir" ;;
+               esac
+               add_dir="-L$dir"
+               add="-l$name"
+             elif test "$hardcode_shlibpath_var" = no; then
+               add_shlibpath="$dir"
+               add="-l$name"
+             else
+               lib_linked=no
+             fi
+             ;;
+           relink)
+             if test "$hardcode_direct" = yes &&
+                test "$hardcode_direct_absolute" = no; then
+               add="$dir/$linklib"
+             elif test "$hardcode_minus_L" = yes; then
+               add_dir="-L$absdir"
+               # Try looking first in the location we're being installed to.
+               if test -n "$inst_prefix_dir"; then
+                 case $libdir in
+                   [\\/]*)
+                     func_append add_dir " -L$inst_prefix_dir$libdir"
+                     ;;
+                 esac
+               fi
+               add="-l$name"
+             elif test "$hardcode_shlibpath_var" = yes; then
+               add_shlibpath="$dir"
+               add="-l$name"
+             else
+               lib_linked=no
+             fi
+             ;;
+           *) lib_linked=no ;;
+           esac
+
+           if test "$lib_linked" != yes; then
+             func_fatal_configuration "unsupported hardcode properties"
+           fi
+
+           if test -n "$add_shlibpath"; then
+             case :$compile_shlibpath: in
+             *":$add_shlibpath:"*) ;;
+             *) func_append compile_shlibpath "$add_shlibpath:" ;;
+             esac
+           fi
+           if test "$linkmode" = prog; then
+             test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+             test -n "$add" && compile_deplibs="$add $compile_deplibs"
+           else
+             test -n "$add_dir" && deplibs="$add_dir $deplibs"
+             test -n "$add" && deplibs="$add $deplibs"
+             if test "$hardcode_direct" != yes &&
+                test "$hardcode_minus_L" != yes &&
+                test "$hardcode_shlibpath_var" = yes; then
+               case :$finalize_shlibpath: in
+               *":$libdir:"*) ;;
+               *) func_append finalize_shlibpath "$libdir:" ;;
+               esac
+             fi
+           fi
+         fi
+
+         if test "$linkmode" = prog || test "$opt_mode" = relink; then
+           add_shlibpath=
+           add_dir=
+           add=
+           # Finalize command for both is simple: just hardcode it.
+           if test "$hardcode_direct" = yes &&
+              test "$hardcode_direct_absolute" = no; then
+             add="$libdir/$linklib"
+           elif test "$hardcode_minus_L" = yes; then
+             add_dir="-L$libdir"
+             add="-l$name"
+           elif test "$hardcode_shlibpath_var" = yes; then
+             case :$finalize_shlibpath: in
+             *":$libdir:"*) ;;
+             *) func_append finalize_shlibpath "$libdir:" ;;
+             esac
+             add="-l$name"
+           elif test "$hardcode_automatic" = yes; then
+             if test -n "$inst_prefix_dir" &&
+                test -f "$inst_prefix_dir$libdir/$linklib" ; then
+               add="$inst_prefix_dir$libdir/$linklib"
+             else
+               add="$libdir/$linklib"
+             fi
+           else
+             # We cannot seem to hardcode it, guess we'll fake it.
+             add_dir="-L$libdir"
+             # Try looking first in the location we're being installed to.
+             if test -n "$inst_prefix_dir"; then
+               case $libdir in
+                 [\\/]*)
+                   func_append add_dir " -L$inst_prefix_dir$libdir"
+                   ;;
+               esac
+             fi
+             add="-l$name"
+           fi
+
+           if test "$linkmode" = prog; then
+             test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+             test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+           else
+             test -n "$add_dir" && deplibs="$add_dir $deplibs"
+             test -n "$add" && deplibs="$add $deplibs"
+           fi
+         fi
+       elif test "$linkmode" = prog; then
+         # Here we assume that one of hardcode_direct or hardcode_minus_L
+         # is not unsupported.  This is valid on all known static and
+         # shared platforms.
+         if test "$hardcode_direct" != unsupported; then
+           test -n "$old_library" && linklib="$old_library"
+           compile_deplibs="$dir/$linklib $compile_deplibs"
+           finalize_deplibs="$dir/$linklib $finalize_deplibs"
+         else
+           compile_deplibs="-l$name -L$dir $compile_deplibs"
+           finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+         fi
+       elif test "$build_libtool_libs" = yes; then
+         # Not a shared library
+         if test "$deplibs_check_method" != pass_all; then
+           # We're trying link a shared library against a static one
+           # but the system doesn't support it.
+
+           # Just print a warning and add the library to dependency_libs so
+           # that the program can be linked against the static library.
+           echo
+           $ECHO "*** Warning: This system can not link to static lib archive $lib."
+           echo "*** I have the capability to make that library automatically link in when"
+           echo "*** you link to this library.  But I can only do this if you have a"
+           echo "*** shared version of the library, which you do not appear to have."
+           if test "$module" = yes; then
+             echo "*** But as you try to build a module library, libtool will still create "
+             echo "*** a static module, that should work as long as the dlopening application"
+             echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+             if test -z "$global_symbol_pipe"; then
+               echo
+               echo "*** However, this would only work if libtool was able to extract symbol"
+               echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+               echo "*** not find such a program.  So, this module is probably useless."
+               echo "*** \`nm' from GNU binutils and a full rebuild may help."
+             fi
+             if test "$build_old_libs" = no; then
+               build_libtool_libs=module
+               build_old_libs=yes
+             else
+               build_libtool_libs=no
+             fi
+           fi
+         else
+           deplibs="$dir/$old_library $deplibs"
+           link_static=yes
+         fi
+       fi # link shared/static library?
+
+       if test "$linkmode" = lib; then
+         if test -n "$dependency_libs" &&
+            { test "$hardcode_into_libs" != yes ||
+              test "$build_old_libs" = yes ||
+              test "$link_static" = yes; }; then
+           # Extract -R from dependency_libs
+           temp_deplibs=
+           for libdir in $dependency_libs; do
+             case $libdir in
+             -R*) func_stripname '-R' '' "$libdir"
+                  temp_xrpath=$func_stripname_result
+                  case " $xrpath " in
+                  *" $temp_xrpath "*) ;;
+                  *) func_append xrpath " $temp_xrpath";;
+                  esac;;
+             *) func_append temp_deplibs " $libdir";;
+             esac
+           done
+           dependency_libs="$temp_deplibs"
+         fi
+
+         func_append newlib_search_path " $absdir"
+         # Link against this library
+         test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+         # ... and its dependency_libs
+         tmp_libs=
+         for deplib in $dependency_libs; do
+           newdependency_libs="$deplib $newdependency_libs"
+           case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+           if $opt_preserve_dup_deps ; then
+             case "$tmp_libs " in
+             *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+             esac
+           fi
+           func_append tmp_libs " $func_resolve_sysroot_result"
+         done
+
+         if test "$link_all_deplibs" != no; then
+           # Add the search paths of all dependency libraries
+           for deplib in $dependency_libs; do
+             path=
+             case $deplib in
+             -L*) path="$deplib" ;;
+             *.la)
+               func_resolve_sysroot "$deplib"
+               deplib=$func_resolve_sysroot_result
+               func_dirname "$deplib" "" "."
+               dir=$func_dirname_result
+               # We need an absolute path.
+               case $dir in
+               [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+               *)
+                 absdir=`cd "$dir" && pwd`
+                 if test -z "$absdir"; then
+                   func_warning "cannot determine absolute directory name of \`$dir'"
+                   absdir="$dir"
+                 fi
+                 ;;
+               esac
+               if $GREP "^installed=no" $deplib > /dev/null; then
+               case $host in
+               *-*-darwin*)
+                 depdepl=
+                 eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+                 if test -n "$deplibrary_names" ; then
+                   for tmp in $deplibrary_names ; do
+                     depdepl=$tmp
+                   done
+                   if test -f "$absdir/$objdir/$depdepl" ; then
+                     depdepl="$absdir/$objdir/$depdepl"
+                     darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+                     func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+                     func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+                     path=
+                   fi
+                 fi
+                 ;;
+               *)
+                 path="-L$absdir/$objdir"
+                 ;;
+               esac
+               else
+                 eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+                 test -z "$libdir" && \
+                   func_fatal_error "\`$deplib' is not a valid libtool archive"
+                 test "$absdir" != "$libdir" && \
+                   func_warning "\`$deplib' seems to be moved"
+
+                 path="-L$absdir"
+               fi
+               ;;
+             esac
+             case " $deplibs " in
+             *" $path "*) ;;
+             *) deplibs="$path $deplibs" ;;
+             esac
+           done
+         fi # link_all_deplibs != no
+       fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+       if test "$linkmode" = "prog"; then
+         compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+         finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+       else
+         compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+       # Link the dlpreopened libraries before other libraries
+       for deplib in $save_deplibs; do
+         deplibs="$deplib $deplibs"
+       done
+      fi
+      if test "$pass" != dlopen; then
+       if test "$pass" != conv; then
+         # Make sure lib_search_path contains only unique directories.
+         lib_search_path=
+         for dir in $newlib_search_path; do
+           case "$lib_search_path " in
+           *" $dir "*) ;;
+           *) func_append lib_search_path " $dir" ;;
+           esac
+         done
+         newlib_search_path=
+       fi
+
+       if test "$linkmode,$pass" != "prog,link"; then
+         vars="deplibs"
+       else
+         vars="compile_deplibs finalize_deplibs"
+       fi
+       for var in $vars dependency_libs; do
+         # Add libraries to $var in reverse order
+         eval tmp_libs=\"\$$var\"
+         new_libs=
+         for deplib in $tmp_libs; do
+           # FIXME: Pedantically, this is the right thing to do, so
+           #        that some nasty dependency loop isn't accidentally
+           #        broken:
+           #new_libs="$deplib $new_libs"
+           # Pragmatically, this seems to cause very few problems in
+           # practice:
+           case $deplib in
+           -L*) new_libs="$deplib $new_libs" ;;
+           -R*) ;;
+           *)
+             # And here is the reason: when a library appears more
+             # than once as an explicit dependence of a library, or
+             # is implicitly linked in more than once by the
+             # compiler, it is considered special, and multiple
+             # occurrences thereof are not removed.  Compare this
+             # with having the same library being listed as a
+             # dependency of multiple other libraries: in this case,
+             # we know (pedantically, we assume) the library does not
+             # need to be listed more than once, so we keep only the
+             # last copy.  This is not always right, but it is rare
+             # enough that we require users that really mean to play
+             # such unportable linking tricks to link the library
+             # using -Wl,-lname, so that libtool does not consider it
+             # for duplicate removal.
+             case " $specialdeplibs " in
+             *" $deplib "*) new_libs="$deplib $new_libs" ;;
+             *)
+               case " $new_libs " in
+               *" $deplib "*) ;;
+               *) new_libs="$deplib $new_libs" ;;
+               esac
+               ;;
+             esac
+             ;;
+           esac
+         done
+         tmp_libs=
+         for deplib in $new_libs; do
+           case $deplib in
+           -L*)
+             case " $tmp_libs " in
+             *" $deplib "*) ;;
+             *) func_append tmp_libs " $deplib" ;;
+             esac
+             ;;
+           *) func_append tmp_libs " $deplib" ;;
+           esac
+         done
+         eval $var=\"$tmp_libs\"
+       done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+       case " $predeps $postdeps $compiler_lib_search_path " in
+       *" $i "*)
+         i=""
+         ;;
+       esac
+       if test -n "$i" ; then
+         func_append tmp_libs " $i"
+       fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+       func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+       func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+       func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+       func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+       func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+       func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+       func_stripname 'lib' '.la' "$outputname"
+       name=$func_stripname_result
+       eval shared_ext=\"$shrext_cmds\"
+       eval libname=\"$libname_spec\"
+       ;;
+      *)
+       test "$module" = no && \
+         func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+       if test "$need_lib_prefix" != no; then
+         # Add the "lib" prefix for modules if required
+         func_stripname '' '.la' "$outputname"
+         name=$func_stripname_result
+         eval shared_ext=\"$shrext_cmds\"
+         eval libname=\"$libname_spec\"
+       else
+         func_stripname '' '.la' "$outputname"
+         libname=$func_stripname_result
+       fi
+       ;;
+      esac
+
+      if test -n "$objs"; then
+       if test "$deplibs_check_method" != pass_all; then
+         func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+       else
+         echo
+         $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+         $ECHO "*** objects $objs is not portable!"
+         func_append libobjs " $objs"
+       fi
+      fi
+
+      test "$dlself" != no && \
+       func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+       func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+       if test "$build_libtool_libs" = yes; then
+         # Building a libtool convenience library.
+         # Some compilers have problems with a `.al' extension so
+         # convenience libraries should have the same extension an
+         # archive normally would.
+         oldlibs="$output_objdir/$libname.$libext $oldlibs"
+         build_libtool_libs=convenience
+         build_old_libs=yes
+       fi
+
+       test -n "$vinfo" && \
+         func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+       test -n "$release" && \
+         func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+       # Parse the version information argument.
+       save_ifs="$IFS"; IFS=':'
+       set dummy $vinfo 0 0 0
+       shift
+       IFS="$save_ifs"
+
+       test -n "$7" && \
+         func_fatal_help "too many parameters to \`-version-info'"
+
+       # convert absolute version numbers to libtool ages
+       # this retains compatibility with .la files and attempts
+       # to make the code below a bit more comprehensible
+
+       case $vinfo_number in
+       yes)
+         number_major="$1"
+         number_minor="$2"
+         number_revision="$3"
+         #
+         # There are really only two kinds -- those that
+         # use the current revision as the major version
+         # and those that subtract age and use age as
+         # a minor version.  But, then there is irix
+         # which has an extra 1 added just for fun
+         #
+         case $version_type in
+         # correct linux to gnu/linux during the next big refactor
+         darwin|linux|osf|windows|none)
+           func_arith $number_major + $number_minor
+           current=$func_arith_result
+           age="$number_minor"
+           revision="$number_revision"
+           ;;
+         freebsd-aout|freebsd-elf|qnx|sunos)
+           current="$number_major"
+           revision="$number_minor"
+           age="0"
+           ;;
+         irix|nonstopux)
+           func_arith $number_major + $number_minor
+           current=$func_arith_result
+           age="$number_minor"
+           revision="$number_minor"
+           lt_irix_increment=no
+           ;;
+         esac
+         ;;
+       no)
+         current="$1"
+         revision="$2"
+         age="$3"
+         ;;
+       esac
+
+       # Check that each of the things are valid numbers.
+       case $current in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         func_error "CURRENT \`$current' must be a nonnegative integer"
+         func_fatal_error "\`$vinfo' is not valid version information"
+         ;;
+       esac
+
+       case $revision in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         func_error "REVISION \`$revision' must be a nonnegative integer"
+         func_fatal_error "\`$vinfo' is not valid version information"
+         ;;
+       esac
+
+       case $age in
+       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+       *)
+         func_error "AGE \`$age' must be a nonnegative integer"
+         func_fatal_error "\`$vinfo' is not valid version information"
+         ;;
+       esac
+
+       if test "$age" -gt "$current"; then
+         func_error "AGE \`$age' is greater than the current interface number \`$current'"
+         func_fatal_error "\`$vinfo' is not valid version information"
+       fi
+
+       # Calculate the version variables.
+       major=
+       versuffix=
+       verstring=
+       case $version_type in
+       none) ;;
+
+       darwin)
+         # Like Linux, but with the current version available in
+         # verstring for coding it into the library header
+         func_arith $current - $age
+         major=.$func_arith_result
+         versuffix="$major.$age.$revision"
+         # Darwin ld doesn't like 0 for these options...
+         func_arith $current + 1
+         minor_current=$func_arith_result
+         xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+         verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+         ;;
+
+       freebsd-aout)
+         major=".$current"
+         versuffix=".$current.$revision";
+         ;;
+
+       freebsd-elf)
+         major=".$current"
+         versuffix=".$current"
+         ;;
+
+       irix | nonstopux)
+         if test "X$lt_irix_increment" = "Xno"; then
+           func_arith $current - $age
+         else
+           func_arith $current - $age + 1
+         fi
+         major=$func_arith_result
+
+         case $version_type in
+           nonstopux) verstring_prefix=nonstopux ;;
+           *)         verstring_prefix=sgi ;;
+         esac
+         verstring="$verstring_prefix$major.$revision"
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$revision
+         while test "$loop" -ne 0; do
+           func_arith $revision - $loop
+           iface=$func_arith_result
+           func_arith $loop - 1
+           loop=$func_arith_result
+           verstring="$verstring_prefix$major.$iface:$verstring"
+         done
+
+         # Before this point, $major must not contain `.'.
+         major=.$major
+         versuffix="$major.$revision"
+         ;;
+
+       linux) # correct to gnu/linux during the next big refactor
+         func_arith $current - $age
+         major=.$func_arith_result
+         versuffix="$major.$age.$revision"
+         ;;
+
+       osf)
+         func_arith $current - $age
+         major=.$func_arith_result
+         versuffix=".$current.$age.$revision"
+         verstring="$current.$age.$revision"
+
+         # Add in all the interfaces that we are compatible with.
+         loop=$age
+         while test "$loop" -ne 0; do
+           func_arith $current - $loop
+           iface=$func_arith_result
+           func_arith $loop - 1
+           loop=$func_arith_result
+           verstring="$verstring:${iface}.0"
+         done
+
+         # Make executables depend on our current version.
+         func_append verstring ":${current}.0"
+         ;;
+
+       qnx)
+         major=".$current"
+         versuffix=".$current"
+         ;;
+
+       sunos)
+         major=".$current"
+         versuffix=".$current.$revision"
+         ;;
+
+       windows)
+         # Use '-' rather than '.', since we only want one
+         # extension on DOS 8.3 filesystems.
+         func_arith $current - $age
+         major=$func_arith_result
+         versuffix="-$major"
+         ;;
+
+       *)
+         func_fatal_configuration "unknown library version type \`$version_type'"
+         ;;
+       esac
+
+       # Clear the version info if we defaulted, and they specified a release.
+       if test -z "$vinfo" && test -n "$release"; then
+         major=
+         case $version_type in
+         darwin)
+           # we can't check for "0.0" in archive_cmds due to quoting
+           # problems, so we reset it completely
+           verstring=
+           ;;
+         *)
+           verstring="0.0"
+           ;;
+         esac
+         if test "$need_version" = no; then
+           versuffix=
+         else
+           versuffix=".0.0"
+         fi
+       fi
+
+       # Remove version info from name if versioning should be avoided
+       if test "$avoid_version" = yes && test "$need_version" = no; then
+         major=
+         versuffix=
+         verstring=""
+       fi
+
+       # Check to see if the archive will have undefined symbols.
+       if test "$allow_undefined" = yes; then
+         if test "$allow_undefined_flag" = unsupported; then
+           func_warning "undefined symbols not allowed in $host shared libraries"
+           build_libtool_libs=no
+           build_old_libs=yes
+         fi
+       else
+         # Don't allow undefined symbols.
+         allow_undefined_flag="$no_undefined_flag"
+       fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      func_append libobjs " $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$opt_mode" != relink; then
+       # Remove our outputs, but don't remove object files since they
+       # may have been created when compiling PIC objects.
+       removelist=
+       tempremovelist=`$ECHO "$output_objdir/*"`
+       for p in $tempremovelist; do
+         case $p in
+           *.$objext | *.gcno)
+              ;;
+           $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+              if test "X$precious_files_regex" != "X"; then
+                if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+                then
+                  continue
+                fi
+              fi
+              func_append removelist " $p"
+              ;;
+           *) ;;
+         esac
+       done
+       test -n "$removelist" && \
+         func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+       func_append oldlibs " $output_objdir/$libname.$libext"
+
+       # Transform .lo files to .o files.
+       oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #        lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #        deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #        dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+       # If the user specified any rpath flags, then add them.
+       temp_xrpath=
+       for libdir in $xrpath; do
+         func_replace_sysroot "$libdir"
+         func_append temp_xrpath " -R$func_replace_sysroot_result"
+         case "$finalize_rpath " in
+         *" $libdir "*) ;;
+         *) func_append finalize_rpath " $libdir" ;;
+         esac
+       done
+       if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+         dependency_libs="$temp_xrpath $dependency_libs"
+       fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+       case " $dlprefiles $dlfiles " in
+       *" $lib "*) ;;
+       *) func_append dlfiles " $lib" ;;
+       esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+       case "$dlprefiles " in
+       *" $lib "*) ;;
+       *) func_append dlprefiles " $lib" ;;
+       esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+       if test -n "$rpath"; then
+         case $host in
+         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+           # these systems don't actually have a c library (as such)!
+           ;;
+         *-*-rhapsody* | *-*-darwin1.[012])
+           # Rhapsody C library is in the System framework
+           func_append deplibs " System.ltframework"
+           ;;
+         *-*-netbsd*)
+           # Don't link with libc until the a.out ld.so is fixed.
+           ;;
+         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+           # Do not include libc due to us having libc/libc_r.
+           ;;
+         *-*-sco3.2v5* | *-*-sco5v6*)
+           # Causes problems with __ctype
+           ;;
+         *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+           # Compiler inserts libc in the correct place for threads to work
+           ;;
+         *)
+           # Add libc to deplibs on all other systems if necessary.
+           if test "$build_libtool_need_lc" = "yes"; then
+             func_append deplibs " -lc"
+           fi
+           ;;
+         esac
+       fi
+
+       # Transform deplibs into only deplibs that can be linked in shared.
+       name_save=$name
+       libname_save=$libname
+       release_save=$release
+       versuffix_save=$versuffix
+       major_save=$major
+       # I'm not sure if I'm treating the release correctly.  I think
+       # release should show up in the -l (ie -lgmp5) so we don't want to
+       # add it in twice.  Is that correct?
+       release=""
+       versuffix=""
+       major=""
+       newdeplibs=
+       droppeddeps=no
+       case $deplibs_check_method in
+       pass_all)
+         # Don't check for shared/static.  Everything works.
+         # This might be a little naive.  We might want to check
+         # whether the library exists or not.  But this is on
+         # osf3 & osf4 and I'm not really sure... Just
+         # implementing what was already the behavior.
+         newdeplibs=$deplibs
+         ;;
+       test_compile)
+         # This code stresses the "libraries are programs" paradigm to its
+         # limits. Maybe even breaks it.  We compile a program, linking it
+         # against the deplibs as a proxy for the library.  Then we can check
+         # whether they linked in statically or dynamically with ldd.
+         $opt_dry_run || $RM conftest.c
+         cat > conftest.c <<EOF
+         int main() { return 0; }
+EOF
+         $opt_dry_run || $RM conftest
+         if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+           ldd_output=`ldd conftest`
+           for i in $deplibs; do
+             case $i in
+             -l*)
+               func_stripname -l '' "$i"
+               name=$func_stripname_result
+               if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+                 case " $predeps $postdeps " in
+                 *" $i "*)
+                   func_append newdeplibs " $i"
+                   i=""
+                   ;;
+                 esac
+               fi
+               if test -n "$i" ; then
+                 libname=`eval "\\$ECHO \"$libname_spec\""`
+                 deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+                 set dummy $deplib_matches; shift
+                 deplib_match=$1
+                 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                   func_append newdeplibs " $i"
+                 else
+                   droppeddeps=yes
+                   echo
+                   $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+                   echo "*** I have the capability to make that library automatically link in when"
+                   echo "*** you link to this library.  But I can only do this if you have a"
+                   echo "*** shared version of the library, which I believe you do not have"
+                   echo "*** because a test_compile did reveal that the linker did not use it for"
+                   echo "*** its dynamic dependency list that programs get resolved with at runtime."
+                 fi
+               fi
+               ;;
+             *)
+               func_append newdeplibs " $i"
+               ;;
+             esac
+           done
+         else
+           # Error occurred in the first compile.  Let's try to salvage
+           # the situation: Compile a separate program for each library.
+           for i in $deplibs; do
+             case $i in
+             -l*)
+               func_stripname -l '' "$i"
+               name=$func_stripname_result
+               $opt_dry_run || $RM conftest
+               if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+                 ldd_output=`ldd conftest`
+                 if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+                   case " $predeps $postdeps " in
+                   *" $i "*)
+                     func_append newdeplibs " $i"
+                     i=""
+                     ;;
+                   esac
+                 fi
+                 if test -n "$i" ; then
+                   libname=`eval "\\$ECHO \"$libname_spec\""`
+                   deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+                   set dummy $deplib_matches; shift
+                   deplib_match=$1
+                   if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+                     func_append newdeplibs " $i"
+                   else
+                     droppeddeps=yes
+                     echo
+                     $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+                     echo "*** I have the capability to make that library automatically link in when"
+                     echo "*** you link to this library.  But I can only do this if you have a"
+                     echo "*** shared version of the library, which you do not appear to have"
+                     echo "*** because a test_compile did reveal that the linker did not use this one"
+                     echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+                   fi
+                 fi
+               else
+                 droppeddeps=yes
+                 echo
+                 $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+                 echo "*** make it link in!  You will probably need to install it or some"
+                 echo "*** library that it depends on before this library will be fully"
+                 echo "*** functional.  Installing it before continuing would be even better."
+               fi
+               ;;
+             *)
+               func_append newdeplibs " $i"
+               ;;
+             esac
+           done
+         fi
+         ;;
+       file_magic*)
+         set dummy $deplibs_check_method; shift
+         file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+         for a_deplib in $deplibs; do
+           case $a_deplib in
+           -l*)
+             func_stripname -l '' "$a_deplib"
+             name=$func_stripname_result
+             if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+               case " $predeps $postdeps " in
+               *" $a_deplib "*)
+                 func_append newdeplibs " $a_deplib"
+                 a_deplib=""
+                 ;;
+               esac
+             fi
+             if test -n "$a_deplib" ; then
+               libname=`eval "\\$ECHO \"$libname_spec\""`
+               if test -n "$file_magic_glob"; then
+                 libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+               else
+                 libnameglob=$libname
+               fi
+               test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+                 if test "$want_nocaseglob" = yes; then
+                   shopt -s nocaseglob
+                   potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+                   $nocaseglob
+                 else
+                   potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+                 fi
+                 for potent_lib in $potential_libs; do
+                     # Follow soft links.
+                     if ls -lLd "$potent_lib" 2>/dev/null |
+                        $GREP " -> " >/dev/null; then
+                       continue
+                     fi
+                     # The statement above tries to avoid entering an
+                     # endless loop below, in case of cyclic links.
+                     # We might still enter an endless loop, since a link
+                     # loop can be closed while we follow links,
+                     # but so what?
+                     potlib="$potent_lib"
+                     while test -h "$potlib" 2>/dev/null; do
+                       potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+                       case $potliblink in
+                       [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+                       *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+                       esac
+                     done
+                     if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+                        $SED -e 10q |
+                        $EGREP "$file_magic_regex" > /dev/null; then
+                       func_append newdeplibs " $a_deplib"
+                       a_deplib=""
+                       break 2
+                     fi
+                 done
+               done
+             fi
+             if test -n "$a_deplib" ; then
+               droppeddeps=yes
+               echo
+               $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because I did check the linker path looking for a file starting"
+               if test -z "$potlib" ; then
+                 $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+               else
+                 $ECHO "*** with $libname and none of the candidates passed a file format test"
+                 $ECHO "*** using a file magic. Last file checked: $potlib"
+               fi
+             fi
+             ;;
+           *)
+             # Add a -L argument.
+             func_append newdeplibs " $a_deplib"
+             ;;
+           esac
+         done # Gone through all deplibs.
+         ;;
+       match_pattern*)
+         set dummy $deplibs_check_method; shift
+         match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+         for a_deplib in $deplibs; do
+           case $a_deplib in
+           -l*)
+             func_stripname -l '' "$a_deplib"
+             name=$func_stripname_result
+             if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+               case " $predeps $postdeps " in
+               *" $a_deplib "*)
+                 func_append newdeplibs " $a_deplib"
+                 a_deplib=""
+                 ;;
+               esac
+             fi
+             if test -n "$a_deplib" ; then
+               libname=`eval "\\$ECHO \"$libname_spec\""`
+               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+                 potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+                 for potent_lib in $potential_libs; do
+                   potlib="$potent_lib" # see symlink-check above in file_magic test
+                   if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+                      $EGREP "$match_pattern_regex" > /dev/null; then
+                     func_append newdeplibs " $a_deplib"
+                     a_deplib=""
+                     break 2
+                   fi
+                 done
+               done
+             fi
+             if test -n "$a_deplib" ; then
+               droppeddeps=yes
+               echo
+               $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+               echo "*** I have the capability to make that library automatically link in when"
+               echo "*** you link to this library.  But I can only do this if you have a"
+               echo "*** shared version of the library, which you do not appear to have"
+               echo "*** because I did check the linker path looking for a file starting"
+               if test -z "$potlib" ; then
+                 $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+               else
+                 $ECHO "*** with $libname and none of the candidates passed a file format test"
+                 $ECHO "*** using a regex pattern. Last file checked: $potlib"
+               fi
+             fi
+             ;;
+           *)
+             # Add a -L argument.
+             func_append newdeplibs " $a_deplib"
+             ;;
+           esac
+         done # Gone through all deplibs.
+         ;;
+       none | unknown | *)
+         newdeplibs=""
+         tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+         if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+           for i in $predeps $postdeps ; do
+             # can't use Xsed below, because $i might contain '/'
+             tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+           done
+         fi
+         case $tmp_deplibs in
+         *[!\  \ ]*)
+           echo
+           if test "X$deplibs_check_method" = "Xnone"; then
+             echo "*** Warning: inter-library dependencies are not supported in this platform."
+           else
+             echo "*** Warning: inter-library dependencies are not known to be supported."
+           fi
+           echo "*** All declared inter-library dependencies are being dropped."
+           droppeddeps=yes
+           ;;
+         esac
+         ;;
+       esac
+       versuffix=$versuffix_save
+       major=$major_save
+       release=$release_save
+       libname=$libname_save
+       name=$name_save
+
+       case $host in
+       *-*-rhapsody* | *-*-darwin1.[012])
+         # On Rhapsody replace the C library with the System framework
+         newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+         ;;
+       esac
+
+       if test "$droppeddeps" = yes; then
+         if test "$module" = yes; then
+           echo
+           echo "*** Warning: libtool could not satisfy all declared inter-library"
+           $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+           echo "*** a static module, that should work as long as the dlopening"
+           echo "*** application is linked with the -dlopen flag."
+           if test -z "$global_symbol_pipe"; then
+             echo
+             echo "*** However, this would only work if libtool was able to extract symbol"
+             echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+             echo "*** not find such a program.  So, this module is probably useless."
+             echo "*** \`nm' from GNU binutils and a full rebuild may help."
+           fi
+           if test "$build_old_libs" = no; then
+             oldlibs="$output_objdir/$libname.$libext"
+             build_libtool_libs=module
+             build_old_libs=yes
+           else
+             build_libtool_libs=no
+           fi
+         else
+           echo "*** The inter-library dependencies that have been dropped here will be"
+           echo "*** automatically added whenever a program is linked with this library"
+           echo "*** or is declared to -dlopen it."
+
+           if test "$allow_undefined" = no; then
+             echo
+             echo "*** Since this library must not contain undefined symbols,"
+             echo "*** because either the platform does not support them or"
+             echo "*** it was explicitly requested with -no-undefined,"
+             echo "*** libtool will only create a static version of it."
+             if test "$build_old_libs" = no; then
+               oldlibs="$output_objdir/$libname.$libext"
+               build_libtool_libs=module
+               build_old_libs=yes
+             else
+               build_libtool_libs=no
+             fi
+           fi
+         fi
+       fi
+       # Done checking deplibs!
+       deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+       *-*-darwin*)
+         newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+         ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+       case " $new_libs " in
+       *" -L$path/$objdir "*) ;;
+       *)
+         case " $deplibs " in
+         *" -L$path/$objdir "*)
+           func_append new_libs " -L$path/$objdir" ;;
+         esac
+         ;;
+       esac
+      done
+      for deplib in $deplibs; do
+       case $deplib in
+       -L*)
+         case " $new_libs " in
+         *" $deplib "*) ;;
+         *) func_append new_libs " $deplib" ;;
+         esac
+         ;;
+       *) func_append new_libs " $deplib" ;;
+       esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+       # Remove ${wl} instances when linking with ld.
+       # FIXME: should test the right _cmds variable.
+       case $archive_cmds in
+         *\$LD\ *) wl= ;;
+        esac
+       if test "$hardcode_into_libs" = yes; then
+         # Hardcode the library paths
+         hardcode_libdirs=
+         dep_rpath=
+         rpath="$finalize_rpath"
+         test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+         for libdir in $rpath; do
+           if test -n "$hardcode_libdir_flag_spec"; then
+             if test -n "$hardcode_libdir_separator"; then
+               func_replace_sysroot "$libdir"
+               libdir=$func_replace_sysroot_result
+               if test -z "$hardcode_libdirs"; then
+                 hardcode_libdirs="$libdir"
+               else
+                 # Just accumulate the unique libdirs.
+                 case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+                 *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+                   ;;
+                 *)
+                   func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+                   ;;
+                 esac
+               fi
+             else
+               eval flag=\"$hardcode_libdir_flag_spec\"
+               func_append dep_rpath " $flag"
+             fi
+           elif test -n "$runpath_var"; then
+             case "$perm_rpath " in
+             *" $libdir "*) ;;
+             *) func_append perm_rpath " $libdir" ;;
+             esac
+           fi
+         done
+         # Substitute the hardcoded libdirs into the rpath.
+         if test -n "$hardcode_libdir_separator" &&
+            test -n "$hardcode_libdirs"; then
+           libdir="$hardcode_libdirs"
+           eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+         fi
+         if test -n "$runpath_var" && test -n "$perm_rpath"; then
+           # We should set the runpath_var.
+           rpath=
+           for dir in $perm_rpath; do
+             func_append rpath "$dir:"
+           done
+           eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+         fi
+         test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+       fi
+
+       shlibpath="$finalize_shlibpath"
+       test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+       if test -n "$shlibpath"; then
+         eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+       fi
+
+       # Get the real and link names of the library.
+       eval shared_ext=\"$shrext_cmds\"
+       eval library_names=\"$library_names_spec\"
+       set dummy $library_names
+       shift
+       realname="$1"
+       shift
+
+       if test -n "$soname_spec"; then
+         eval soname=\"$soname_spec\"
+       else
+         soname="$realname"
+       fi
+       if test -z "$dlname"; then
+         dlname=$soname
+       fi
+
+       lib="$output_objdir/$realname"
+       linknames=
+       for link
+       do
+         func_append linknames " $link"
+       done
+
+       # Use standard objects if they are pic
+       test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+       test "X$libobjs" = "X " && libobjs=
+
+       delfiles=
+       if test -n "$export_symbols" && test -n "$include_expsyms"; then
+         $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+         export_symbols="$output_objdir/$libname.uexp"
+         func_append delfiles " $export_symbols"
+       fi
+
+       orig_export_symbols=
+       case $host_os in
+       cygwin* | mingw* | cegcc*)
+         if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+           # exporting using user supplied symfile
+           if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+             # and it's NOT already a .def file. Must figure out
+             # which of the given symbols are data symbols and tag
+             # them as such. So, trigger use of export_symbols_cmds.
+             # export_symbols gets reassigned inside the "prepare
+             # the list of exported symbols" if statement, so the
+             # include_expsyms logic still works.
+             orig_export_symbols="$export_symbols"
+             export_symbols=
+             always_export_symbols=yes
+           fi
+         fi
+         ;;
+       esac
+
+       # Prepare the list of exported symbols
+       if test -z "$export_symbols"; then
+         if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+           func_verbose "generating symbol list for \`$libname.la'"
+           export_symbols="$output_objdir/$libname.exp"
+           $opt_dry_run || $RM $export_symbols
+           cmds=$export_symbols_cmds
+           save_ifs="$IFS"; IFS='~'
+           for cmd1 in $cmds; do
+             IFS="$save_ifs"
+             # Take the normal branch if the nm_file_list_spec branch
+             # doesn't work or if tool conversion is not needed.
+             case $nm_file_list_spec~$to_tool_file_cmd in
+               *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+                 try_normal_branch=yes
+                 eval cmd=\"$cmd1\"
+                 func_len " $cmd"
+                 len=$func_len_result
+                 ;;
+               *)
+                 try_normal_branch=no
+                 ;;
+             esac
+             if test "$try_normal_branch" = yes \
+                && { test "$len" -lt "$max_cmd_len" \
+                     || test "$max_cmd_len" -le -1; }
+             then
+               func_show_eval "$cmd" 'exit $?'
+               skipped_export=false
+             elif test -n "$nm_file_list_spec"; then
+               func_basename "$output"
+               output_la=$func_basename_result
+               save_libobjs=$libobjs
+               save_output=$output
+               output=${output_objdir}/${output_la}.nm
+               func_to_tool_file "$output"
+               libobjs=$nm_file_list_spec$func_to_tool_file_result
+               func_append delfiles " $output"
+               func_verbose "creating $NM input file list: $output"
+               for obj in $save_libobjs; do
+                 func_to_tool_file "$obj"
+                 $ECHO "$func_to_tool_file_result"
+               done > "$output"
+               eval cmd=\"$cmd1\"
+               func_show_eval "$cmd" 'exit $?'
+               output=$save_output
+               libobjs=$save_libobjs
+               skipped_export=false
+             else
+               # The command line is too long to execute in one step.
+               func_verbose "using reloadable object file for export list..."
+               skipped_export=:
+               # Break out early, otherwise skipped_export may be
+               # set to false by a later but shorter cmd.
+               break
+             fi
+           done
+           IFS="$save_ifs"
+           if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+             func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+             func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+           fi
+         fi
+       fi
+
+       if test -n "$export_symbols" && test -n "$include_expsyms"; then
+         tmp_export_symbols="$export_symbols"
+         test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+         $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+       fi
+
+       if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+         # The given exports_symbols file has to be filtered, so filter it.
+         func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+         # FIXME: $output_objdir/$libname.filter potentially contains lots of
+         # 's' commands which not all seds can handle. GNU sed should be fine
+         # though. Also, the filter scales superlinearly with the number of
+         # global variables. join(1) would be nice here, but unfortunately
+         # isn't a blessed tool.
+         $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+         func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+         export_symbols=$output_objdir/$libname.def
+         $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+       fi
+
+       tmp_deplibs=
+       for test_deplib in $deplibs; do
+         case " $convenience " in
+         *" $test_deplib "*) ;;
+         *)
+           func_append tmp_deplibs " $test_deplib"
+           ;;
+         esac
+       done
+       deplibs="$tmp_deplibs"
+
+       if test -n "$convenience"; then
+         if test -n "$whole_archive_flag_spec" &&
+           test "$compiler_needs_object" = yes &&
+           test -z "$libobjs"; then
+           # extract the archives, so we have objects to list.
+           # TODO: could optimize this to just extract one archive.
+           whole_archive_flag_spec=
+         fi
+         if test -n "$whole_archive_flag_spec"; then
+           save_libobjs=$libobjs
+           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+           test "X$libobjs" = "X " && libobjs=
+         else
+           gentop="$output_objdir/${outputname}x"
+           func_append generated " $gentop"
+
+           func_extract_archives $gentop $convenience
+           func_append libobjs " $func_extract_archives_result"
+           test "X$libobjs" = "X " && libobjs=
+         fi
+       fi
+
+       if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+         eval flag=\"$thread_safe_flag_spec\"
+         func_append linker_flags " $flag"
+       fi
+
+       # Make a backup of the uninstalled library when relinking
+       if test "$opt_mode" = relink; then
+         $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+       fi
+
+       # Do each of the archive commands.
+       if test "$module" = yes && test -n "$module_cmds" ; then
+         if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+           eval test_cmds=\"$module_expsym_cmds\"
+           cmds=$module_expsym_cmds
+         else
+           eval test_cmds=\"$module_cmds\"
+           cmds=$module_cmds
+         fi
+       else
+         if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+           eval test_cmds=\"$archive_expsym_cmds\"
+           cmds=$archive_expsym_cmds
+         else
+           eval test_cmds=\"$archive_cmds\"
+           cmds=$archive_cmds
+         fi
+       fi
+
+       if test "X$skipped_export" != "X:" &&
+          func_len " $test_cmds" &&
+          len=$func_len_result &&
+          test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+         :
+       else
+         # The command line is too long to link in one step, link piecewise
+         # or, if using GNU ld and skipped_export is not :, use a linker
+         # script.
+
+         # Save the value of $output and $libobjs because we want to
+         # use them later.  If we have whole_archive_flag_spec, we
+         # want to use save_libobjs as it was before
+         # whole_archive_flag_spec was expanded, because we can't
+         # assume the linker understands whole_archive_flag_spec.
+         # This may have to be revisited, in case too many
+         # convenience libraries get linked in and end up exceeding
+         # the spec.
+         if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+           save_libobjs=$libobjs
+         fi
+         save_output=$output
+         func_basename "$output"
+         output_la=$func_basename_result
+
+         # Clear the reloadable object creation command queue and
+         # initialize k to one.
+         test_cmds=
+         concat_cmds=
+         objlist=
+         last_robj=
+         k=1
+
+         if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+           output=${output_objdir}/${output_la}.lnkscript
+           func_verbose "creating GNU ld script: $output"
+           echo 'INPUT (' > $output
+           for obj in $save_libobjs
+           do
+             func_to_tool_file "$obj"
+             $ECHO "$func_to_tool_file_result" >> $output
+           done
+           echo ')' >> $output
+           func_append delfiles " $output"
+           func_to_tool_file "$output"
+           output=$func_to_tool_file_result
+         elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+           output=${output_objdir}/${output_la}.lnk
+           func_verbose "creating linker input file list: $output"
+           : > $output
+           set x $save_libobjs
+           shift
+           firstobj=
+           if test "$compiler_needs_object" = yes; then
+             firstobj="$1 "
+             shift
+           fi
+           for obj
+           do
+             func_to_tool_file "$obj"
+             $ECHO "$func_to_tool_file_result" >> $output
+           done
+           func_append delfiles " $output"
+           func_to_tool_file "$output"
+           output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+         else
+           if test -n "$save_libobjs"; then
+             func_verbose "creating reloadable object files..."
+             output=$output_objdir/$output_la-${k}.$objext
+             eval test_cmds=\"$reload_cmds\"
+             func_len " $test_cmds"
+             len0=$func_len_result
+             len=$len0
+
+             # Loop over the list of objects to be linked.
+             for obj in $save_libobjs
+             do
+               func_len " $obj"
+               func_arith $len + $func_len_result
+               len=$func_arith_result
+               if test "X$objlist" = X ||
+                  test "$len" -lt "$max_cmd_len"; then
+                 func_append objlist " $obj"
+               else
+                 # The command $test_cmds is almost too long, add a
+                 # command to the queue.
+                 if test "$k" -eq 1 ; then
+                   # The first file doesn't have a previous command to add.
+                   reload_objs=$objlist
+                   eval concat_cmds=\"$reload_cmds\"
+                 else
+                   # All subsequent reloadable object files will link in
+                   # the last one created.
+                   reload_objs="$objlist $last_robj"
+                   eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+                 fi
+                 last_robj=$output_objdir/$output_la-${k}.$objext
+                 func_arith $k + 1
+                 k=$func_arith_result
+                 output=$output_objdir/$output_la-${k}.$objext
+                 objlist=" $obj"
+                 func_len " $last_robj"
+                 func_arith $len0 + $func_len_result
+                 len=$func_arith_result
+               fi
+             done
+             # Handle the remaining objects by creating one last
+             # reloadable object file.  All subsequent reloadable object
+             # files will link in the last one created.
+             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+             reload_objs="$objlist $last_robj"
+             eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+             if test -n "$last_robj"; then
+               eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+             fi
+             func_append delfiles " $output"
+
+           else
+             output=
+           fi
+
+           if ${skipped_export-false}; then
+             func_verbose "generating symbol list for \`$libname.la'"
+             export_symbols="$output_objdir/$libname.exp"
+             $opt_dry_run || $RM $export_symbols
+             libobjs=$output
+             # Append the command to create the export file.
+             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+             eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+             if test -n "$last_robj"; then
+               eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+             fi
+           fi
+
+           test -n "$save_libobjs" &&
+             func_verbose "creating a temporary reloadable object file: $output"
+
+           # Loop through the commands generated above and execute them.
+           save_ifs="$IFS"; IFS='~'
+           for cmd in $concat_cmds; do
+             IFS="$save_ifs"
+             $opt_silent || {
+                 func_quote_for_expand "$cmd"
+                 eval "func_echo $func_quote_for_expand_result"
+             }
+             $opt_dry_run || eval "$cmd" || {
+               lt_exit=$?
+
+               # Restore the uninstalled library and exit
+               if test "$opt_mode" = relink; then
+                 ( cd "$output_objdir" && \
+                   $RM "${realname}T" && \
+                   $MV "${realname}U" "$realname" )
+               fi
+
+               exit $lt_exit
+             }
+           done
+           IFS="$save_ifs"
+
+           if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+             func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+             func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+           fi
+         fi
+
+          if ${skipped_export-false}; then
+           if test -n "$export_symbols" && test -n "$include_expsyms"; then
+             tmp_export_symbols="$export_symbols"
+             test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+             $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+           fi
+
+           if test -n "$orig_export_symbols"; then
+             # The given exports_symbols file has to be filtered, so filter it.
+             func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+             # FIXME: $output_objdir/$libname.filter potentially contains lots of
+             # 's' commands which not all seds can handle. GNU sed should be fine
+             # though. Also, the filter scales superlinearly with the number of
+             # global variables. join(1) would be nice here, but unfortunately
+             # isn't a blessed tool.
+             $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+             func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+             export_symbols=$output_objdir/$libname.def
+             $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+           fi
+         fi
+
+         libobjs=$output
+         # Restore the value of output.
+         output=$save_output
+
+         if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+           test "X$libobjs" = "X " && libobjs=
+         fi
+         # Expand the library linking commands again to reset the
+         # value of $libobjs for piecewise linking.
+
+         # Do each of the archive commands.
+         if test "$module" = yes && test -n "$module_cmds" ; then
+           if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+             cmds=$module_expsym_cmds
+           else
+             cmds=$module_cmds
+           fi
+         else
+           if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+             cmds=$archive_expsym_cmds
+           else
+             cmds=$archive_cmds
+           fi
+         fi
+       fi
+
+       if test -n "$delfiles"; then
+         # Append the command to remove temporary files to $cmds.
+         eval cmds=\"\$cmds~\$RM $delfiles\"
+       fi
+
+       # Add any objects from preloaded convenience libraries
+       if test -n "$dlprefiles"; then
+         gentop="$output_objdir/${outputname}x"
+         func_append generated " $gentop"
+
+         func_extract_archives $gentop $dlprefiles
+         func_append libobjs " $func_extract_archives_result"
+         test "X$libobjs" = "X " && libobjs=
+       fi
+
+       save_ifs="$IFS"; IFS='~'
+       for cmd in $cmds; do
+         IFS="$save_ifs"
+         eval cmd=\"$cmd\"
+         $opt_silent || {
+           func_quote_for_expand "$cmd"
+           eval "func_echo $func_quote_for_expand_result"
+         }
+         $opt_dry_run || eval "$cmd" || {
+           lt_exit=$?
+
+           # Restore the uninstalled library and exit
+           if test "$opt_mode" = relink; then
+             ( cd "$output_objdir" && \
+               $RM "${realname}T" && \
+               $MV "${realname}U" "$realname" )
+           fi
+
+           exit $lt_exit
+         }
+       done
+       IFS="$save_ifs"
+
+       # Restore the uninstalled library and exit
+       if test "$opt_mode" = relink; then
+         $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+         if test -n "$convenience"; then
+           if test -z "$whole_archive_flag_spec"; then
+             func_show_eval '${RM}r "$gentop"'
+           fi
+         fi
+
+         exit $EXIT_SUCCESS
+       fi
+
+       # Create links to the real library.
+       for linkname in $linknames; do
+         if test "$realname" != "$linkname"; then
+           func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+         fi
+       done
+
+       # If -module or -export-dynamic was specified, set the dlname.
+       if test "$module" = yes || test "$export_dynamic" = yes; then
+         # On all known operating systems, these are identical.
+         dlname="$soname"
+       fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+       func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+       func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+       func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+       func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+       func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+       func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+       test -n "$objs$old_deplibs" && \
+         func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+       libobj=$output
+       func_lo2o "$libobj"
+       obj=$func_lo2o_result
+       ;;
+      *)
+       libobj=
+       obj="$output"
+       ;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+       if test -n "$whole_archive_flag_spec"; then
+         eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+         reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+       else
+         gentop="$output_objdir/${obj}x"
+         func_append generated " $gentop"
+
+         func_extract_archives $gentop $convenience
+         reload_conv_objs="$reload_objs $func_extract_archives_result"
+       fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+       if test -n "$gentop"; then
+         func_show_eval '${RM}r "$gentop"'
+       fi
+
+       exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+       if test -n "$gentop"; then
+         func_show_eval '${RM}r "$gentop"'
+       fi
+
+       # Create an invalid libtool object if no PIC, so that we don't
+       # accidentally link it into a program.
+       # $show "echo timestamp > $libobj"
+       # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+       exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+       # Only do commands if we really have different PIC objects.
+       reload_objs="$libobjs $reload_conv_objs"
+       output="$libobj"
+       func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+       func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+       *cygwin*) func_stripname '' '.exe' "$output"
+                 output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+       func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+       func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+       && test "$dlopen_self" = unknown \
+       && test "$dlopen_self_static" = unknown && \
+         func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+       # On Rhapsody replace the C library is the System framework
+       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+       ;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+       # Don't allow lazy linking, it breaks C++ global constructors
+       # But is supposedly fixed on 10.4 or later (yay!).
+       if test "$tagname" = CXX ; then
+         case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+           10.[0123])
+             func_append compile_command " ${wl}-bind_at_load"
+             func_append finalize_command " ${wl}-bind_at_load"
+           ;;
+         esac
+       fi
+       # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+       ;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+       case " $new_libs " in
+       *" -L$path/$objdir "*) ;;
+       *)
+         case " $compile_deplibs " in
+         *" -L$path/$objdir "*)
+           func_append new_libs " -L$path/$objdir" ;;
+         esac
+         ;;
+       esac
+      done
+      for deplib in $compile_deplibs; do
+       case $deplib in
+       -L*)
+         case " $new_libs " in
+         *" $deplib "*) ;;
+         *) func_append new_libs " $deplib" ;;
+         esac
+         ;;
+       *) func_append new_libs " $deplib" ;;
+       esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+       # If the user specified any rpath flags, then add them.
+       for libdir in $rpath $xrpath; do
+         # This is the magic to use -rpath.
+         case "$finalize_rpath " in
+         *" $libdir "*) ;;
+         *) func_append finalize_rpath " $libdir" ;;
+         esac
+       done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs="$libdir"
+           else
+             # Just accumulate the unique libdirs.
+             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           func_append rpath " $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$perm_rpath " in
+         *" $libdir "*) ;;
+         *) func_append perm_rpath " $libdir" ;;
+         esac
+       fi
+       case $host in
+       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+         testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+         case :$dllsearchpath: in
+         *":$libdir:"*) ;;
+         ::) dllsearchpath=$libdir;;
+         *) func_append dllsearchpath ":$libdir";;
+         esac
+         case :$dllsearchpath: in
+         *":$testbindir:"*) ;;
+         ::) dllsearchpath=$testbindir;;
+         *) func_append dllsearchpath ":$testbindir";;
+         esac
+         ;;
+       esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir="$hardcode_libdirs"
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+       if test -n "$hardcode_libdir_flag_spec"; then
+         if test -n "$hardcode_libdir_separator"; then
+           if test -z "$hardcode_libdirs"; then
+             hardcode_libdirs="$libdir"
+           else
+             # Just accumulate the unique libdirs.
+             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+               ;;
+             *)
+               func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+               ;;
+             esac
+           fi
+         else
+           eval flag=\"$hardcode_libdir_flag_spec\"
+           func_append rpath " $flag"
+         fi
+       elif test -n "$runpath_var"; then
+         case "$finalize_perm_rpath " in
+         *" $libdir "*) ;;
+         *) func_append finalize_perm_rpath " $libdir" ;;
+         esac
+       fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+        test -n "$hardcode_libdirs"; then
+       libdir="$hardcode_libdirs"
+       eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+       # Transform all the library objects into standard objects.
+       compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+       finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+       func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+       # Replace the output file specification.
+       compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+       link_command="$compile_command$compile_rpath"
+
+       # We have no uninstalled library dependencies, so finalize right now.
+       exit_status=0
+       func_show_eval "$link_command" 'exit_status=$?'
+
+       if test -n "$postlink_cmds"; then
+         func_to_tool_file "$output"
+         postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+         func_execute_cmds "$postlink_cmds" 'exit $?'
+       fi
+
+       # Delete the generated files.
+       if test -f "$output_objdir/${outputname}S.${objext}"; then
+         func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+       fi
+
+       exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+       compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+       finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+       if test -n "$perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $perm_rpath; do
+           func_append rpath "$dir:"
+         done
+         compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+       if test -n "$finalize_perm_rpath"; then
+         # We should set the runpath_var.
+         rpath=
+         for dir in $finalize_perm_rpath; do
+           func_append rpath "$dir:"
+         done
+         finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+       fi
+      fi
+
+      if test "$no_install" = yes; then
+       # We don't need to create a wrapper script.
+       link_command="$compile_var$compile_command$compile_rpath"
+       # Replace the output file specification.
+       link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+       # Delete the old output file.
+       $opt_dry_run || $RM $output
+       # Link the executable and exit
+       func_show_eval "$link_command" 'exit $?'
+
+       if test -n "$postlink_cmds"; then
+         func_to_tool_file "$output"
+         postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+         func_execute_cmds "$postlink_cmds" 'exit $?'
+       fi
+
+       exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+       # Fast installation is not supported
+       link_command="$compile_var$compile_command$compile_rpath"
+       relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+       func_warning "this platform does not like uninstalled shared libraries"
+       func_warning "\`$output' will be relinked during installation"
+      else
+       if test "$fast_install" != no; then
+         link_command="$finalize_var$compile_command$finalize_rpath"
+         if test "$fast_install" = yes; then
+           relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+         else
+           # fast_install is set to needless
+           relink_command=
+         fi
+       else
+         link_command="$compile_var$compile_command$compile_rpath"
+         relink_command="$finalize_var$finalize_command$finalize_rpath"
+       fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+       func_to_tool_file "$output_objdir/$outputname"
+       postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+       func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+       # Preserve any variables that may affect compiler behavior
+       for var in $variables_saved_for_relink; do
+         if eval test -z \"\${$var+set}\"; then
+           relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+         elif eval var_value=\$$var; test -z "$var_value"; then
+           relink_command="$var=; export $var; $relink_command"
+         else
+           func_quote_for_eval "$var_value"
+           relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+         fi
+       done
+       relink_command="(cd `pwd`; $relink_command)"
+       relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+       # win32 will think the script is a binary if it has
+       # a .exe suffix, so we strip it off here.
+       case $output in
+         *.exe) func_stripname '' '.exe' "$output"
+                output=$func_stripname_result ;;
+       esac
+       # test for cygwin because mv fails w/o .exe extensions
+       case $host in
+         *cygwin*)
+           exeext=.exe
+           func_stripname '' '.exe' "$outputname"
+           outputname=$func_stripname_result ;;
+         *) exeext= ;;
+       esac
+       case $host in
+         *cygwin* | *mingw* )
+           func_dirname_and_basename "$output" "" "."
+           output_name=$func_basename_result
+           output_path=$func_dirname_result
+           cwrappersource="$output_path/$objdir/lt-$output_name.c"
+           cwrapper="$output_path/$output_name.exe"
+           $RM $cwrappersource $cwrapper
+           trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+           func_emit_cwrapperexe_src > $cwrappersource
+
+           # The wrapper executable is built using the $host compiler,
+           # because it contains $host paths and files. If cross-
+           # compiling, it, like the target executable, must be
+           # executed on the $host or under an emulation environment.
+           $opt_dry_run || {
+             $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+             $STRIP $cwrapper
+           }
+
+           # Now, create the wrapper script for func_source use:
+           func_ltwrapper_scriptname $cwrapper
+           $RM $func_ltwrapper_scriptname_result
+           trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+           $opt_dry_run || {
+             # note: this script will not be executed, so do not chmod.
+             if test "x$build" = "x$host" ; then
+               $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+             else
+               func_emit_wrapper no > $func_ltwrapper_scriptname_result
+             fi
+           }
+         ;;
+         * )
+           $RM $output
+           trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+           func_emit_wrapper no > $output
+           chmod +x $output
+         ;;
+       esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+       oldobjs="$libobjs_save $symfileobj"
+       addlibs="$convenience"
+       build_libtool_libs=no
+      else
+       if test "$build_libtool_libs" = module; then
+         oldobjs="$libobjs_save"
+         build_libtool_libs=no
+       else
+         oldobjs="$old_deplibs $non_pic_objects"
+         if test "$preload" = yes && test -f "$symfileobj"; then
+           func_append oldobjs " $symfileobj"
+         fi
+       fi
+       addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+       gentop="$output_objdir/${outputname}x"
+       func_append generated " $gentop"
+
+       func_extract_archives $gentop $addlibs
+       func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+       cmds=$old_archive_from_new_cmds
+      else
+
+       # Add any objects from preloaded convenience libraries
+       if test -n "$dlprefiles"; then
+         gentop="$output_objdir/${outputname}x"
+         func_append generated " $gentop"
+
+         func_extract_archives $gentop $dlprefiles
+         func_append oldobjs " $func_extract_archives_result"
+       fi
+
+       # POSIX demands no paths to be encoded in archives.  We have
+       # to avoid creating archives with duplicate basenames if we
+       # might have to extract them afterwards, e.g., when creating a
+       # static archive out of a convenience library, or when linking
+       # the entirety of a libtool archive into another (currently
+       # not supported by libtool).
+       if (for obj in $oldobjs
+           do
+             func_basename "$obj"
+             $ECHO "$func_basename_result"
+           done | sort | sort -uc >/dev/null 2>&1); then
+         :
+       else
+         echo "copying selected object files to avoid basename conflicts..."
+         gentop="$output_objdir/${outputname}x"
+         func_append generated " $gentop"
+         func_mkdir_p "$gentop"
+         save_oldobjs=$oldobjs
+         oldobjs=
+         counter=1
+         for obj in $save_oldobjs
+         do
+           func_basename "$obj"
+           objbase="$func_basename_result"
+           case " $oldobjs " in
+           " ") oldobjs=$obj ;;
+           *[\ /]"$objbase "*)
+             while :; do
+               # Make sure we don't pick an alternate name that also
+               # overlaps.
+               newobj=lt$counter-$objbase
+               func_arith $counter + 1
+               counter=$func_arith_result
+               case " $oldobjs " in
+               *[\ /]"$newobj "*) ;;
+               *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+               esac
+             done
+             func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+             func_append oldobjs " $gentop/$newobj"
+             ;;
+           *) func_append oldobjs " $obj" ;;
+           esac
+         done
+       fi
+       func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+       tool_oldlib=$func_to_tool_file_result
+       eval cmds=\"$old_archive_cmds\"
+
+       func_len " $cmds"
+       len=$func_len_result
+       if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+         cmds=$old_archive_cmds
+       elif test -n "$archiver_list_spec"; then
+         func_verbose "using command file archive linking..."
+         for obj in $oldobjs
+         do
+           func_to_tool_file "$obj"
+           $ECHO "$func_to_tool_file_result"
+         done > $output_objdir/$libname.libcmd
+         func_to_tool_file "$output_objdir/$libname.libcmd"
+         oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+         cmds=$old_archive_cmds
+       else
+         # the command line is too long to link in one step, link in parts
+         func_verbose "using piecewise archive linking..."
+         save_RANLIB=$RANLIB
+         RANLIB=:
+         objlist=
+         concat_cmds=
+         save_oldobjs=$oldobjs
+         oldobjs=
+         # Is there a better way of finding the last object in the list?
+         for obj in $save_oldobjs
+         do
+           last_oldobj=$obj
+         done
+         eval test_cmds=\"$old_archive_cmds\"
+         func_len " $test_cmds"
+         len0=$func_len_result
+         len=$len0
+         for obj in $save_oldobjs
+         do
+           func_len " $obj"
+           func_arith $len + $func_len_result
+           len=$func_arith_result
+           func_append objlist " $obj"
+           if test "$len" -lt "$max_cmd_len"; then
+             :
+           else
+             # the above command should be used before it gets too long
+             oldobjs=$objlist
+             if test "$obj" = "$last_oldobj" ; then
+               RANLIB=$save_RANLIB
+             fi
+             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+             eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+             objlist=
+             len=$len0
+           fi
+         done
+         RANLIB=$save_RANLIB
+         oldobjs=$objlist
+         if test "X$oldobjs" = "X" ; then
+           eval cmds=\"\$concat_cmds\"
+         else
+           eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+         fi
+       fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+       if eval test -z \"\${$var+set}\"; then
+         relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+       elif eval var_value=\$$var; test -z "$var_value"; then
+         relink_command="$var=; export $var; $relink_command"
+       else
+         func_quote_for_eval "$var_value"
+         relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+       fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+       relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+       for installed in no yes; do
+         if test "$installed" = yes; then
+           if test -z "$install_libdir"; then
+             break
+           fi
+           output="$output_objdir/$outputname"i
+           # Replace all uninstalled libtool libraries with the installed ones
+           newdependency_libs=
+           for deplib in $dependency_libs; do
+             case $deplib in
+             *.la)
+               func_basename "$deplib"
+               name="$func_basename_result"
+               func_resolve_sysroot "$deplib"
+               eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+               test -z "$libdir" && \
+                 func_fatal_error "\`$deplib' is not a valid libtool archive"
+               func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+               ;;
+             -L*)
+               func_stripname -L '' "$deplib"
+               func_replace_sysroot "$func_stripname_result"
+               func_append newdependency_libs " -L$func_replace_sysroot_result"
+               ;;
+             -R*)
+               func_stripname -R '' "$deplib"
+               func_replace_sysroot "$func_stripname_result"
+               func_append newdependency_libs " -R$func_replace_sysroot_result"
+               ;;
+             *) func_append newdependency_libs " $deplib" ;;
+             esac
+           done
+           dependency_libs="$newdependency_libs"
+           newdlfiles=
+
+           for lib in $dlfiles; do
+             case $lib in
+             *.la)
+               func_basename "$lib"
+               name="$func_basename_result"
+               eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+               test -z "$libdir" && \
+                 func_fatal_error "\`$lib' is not a valid libtool archive"
+               func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+               ;;
+             *) func_append newdlfiles " $lib" ;;
+             esac
+           done
+           dlfiles="$newdlfiles"
+           newdlprefiles=
+           for lib in $dlprefiles; do
+             case $lib in
+             *.la)
+               # Only pass preopened files to the pseudo-archive (for
+               # eventual linking with the app. that links it) if we
+               # didn't already link the preopened objects directly into
+               # the library:
+               func_basename "$lib"
+               name="$func_basename_result"
+               eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+               test -z "$libdir" && \
+                 func_fatal_error "\`$lib' is not a valid libtool archive"
+               func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+               ;;
+             esac
+           done
+           dlprefiles="$newdlprefiles"
+         else
+           newdlfiles=
+           for lib in $dlfiles; do
+             case $lib in
+               [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+               *) abs=`pwd`"/$lib" ;;
+             esac
+             func_append newdlfiles " $abs"
+           done
+           dlfiles="$newdlfiles"
+           newdlprefiles=
+           for lib in $dlprefiles; do
+             case $lib in
+               [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+               *) abs=`pwd`"/$lib" ;;
+             esac
+             func_append newdlprefiles " $abs"
+           done
+           dlprefiles="$newdlprefiles"
+         fi
+         $RM $output
+         # place dlname in correct position for cygwin
+         # In fact, it would be nice if we could use this code for all target
+         # systems that can't hard-code library paths into their executables
+         # and that have no shared library path variable independent of PATH,
+         # but it turns out we can't easily determine that from inspecting
+         # libtool variables, so we have to hard-code the OSs to which it
+         # applies here; at the moment, that means platforms that use the PE
+         # object format with DLL files.  See the long comment at the top of
+         # tests/bindir.at for full details.
+         tdlname=$dlname
+         case $host,$output,$installed,$module,$dlname in
+           *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+             # If a -bindir argument was supplied, place the dll there.
+             if test "x$bindir" != x ;
+             then
+               func_relative_path "$install_libdir" "$bindir"
+               tdlname=$func_relative_path_result$dlname
+             else
+               # Otherwise fall back on heuristic.
+               tdlname=../bin/$dlname
+             fi
+             ;;
+         esac
+         $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+         if test "$installed" = no && test "$need_relink" = yes; then
+           $ECHO >> $output "\
+relink_command=\"$relink_command\""
+         fi
+       done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=yes ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+       odir="$objdir"
+      else
+       odir="$dir/$objdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$opt_mode" = uninstall && odir="$dir"
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test "$opt_mode" = clean; then
+       case " $rmdirs " in
+         *" $odir "*) ;;
+         *) func_append rmdirs " $odir" ;;
+       esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+        { test -h "$file"; } >/dev/null 2>&1 ||
+        test -f "$file"; then
+       :
+      elif test -d "$file"; then
+       exit_status=1
+       continue
+      elif test "$rmforce" = yes; then
+       continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+       # Possibly a libtool archive, so verify it.
+       if func_lalib_p "$file"; then
+         func_source $dir/$name
+
+         # Delete the libtool libraries and symlinks.
+         for n in $library_names; do
+           func_append rmfiles " $odir/$n"
+         done
+         test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+         case "$opt_mode" in
+         clean)
+           case " $library_names " in
+           *" $dlname "*) ;;
+           *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+           esac
+           test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+           ;;
+         uninstall)
+           if test -n "$library_names"; then
+             # Do each command in the postuninstall commands.
+             func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+           fi
+
+           if test -n "$old_library"; then
+             # Do each command in the old_postuninstall commands.
+             func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+           fi
+           # FIXME: should reinstall the best remaining shared library.
+           ;;
+         esac
+       fi
+       ;;
+
+      *.lo)
+       # Possibly a libtool object, so verify it.
+       if func_lalib_p "$file"; then
+
+         # Read the .lo file
+         func_source $dir/$name
+
+         # Add PIC object to the list of files to remove.
+         if test -n "$pic_object" &&
+            test "$pic_object" != none; then
+           func_append rmfiles " $dir/$pic_object"
+         fi
+
+         # Add non-PIC object to the list of files to remove.
+         if test -n "$non_pic_object" &&
+            test "$non_pic_object" != none; then
+           func_append rmfiles " $dir/$non_pic_object"
+         fi
+       fi
+       ;;
+
+      *)
+       if test "$opt_mode" = clean ; then
+         noexename=$name
+         case $file in
+         *.exe)
+           func_stripname '' '.exe' "$file"
+           file=$func_stripname_result
+           func_stripname '' '.exe' "$name"
+           noexename=$func_stripname_result
+           # $file with .exe has already been added to rmfiles,
+           # add $file without .exe
+           func_append rmfiles " $file"
+           ;;
+         esac
+         # Do a test to see if this is a libtool program.
+         if func_ltwrapper_p "$file"; then
+           if func_ltwrapper_executable_p "$file"; then
+             func_ltwrapper_scriptname "$file"
+             relink_command=
+             func_source $func_ltwrapper_scriptname_result
+             func_append rmfiles " $func_ltwrapper_scriptname_result"
+           else
+             relink_command=
+             func_source $dir/$noexename
+           fi
+
+           # note $name still contains .exe if it was in $file originally
+           # as does the version of $file that was added into $rmfiles
+           func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+           if test "$fast_install" = yes && test -n "$relink_command"; then
+             func_append rmfiles " $odir/lt-$name"
+           fi
+           if test "X$noexename" != "X$name" ; then
+             func_append rmfiles " $odir/lt-${noexename}.c"
+           fi
+         fi
+       fi
+       ;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+       func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/build-aux/missing b/build-aux/missing
new file mode 100755 (executable)
index 0000000..86a8fc3
--- /dev/null
@@ -0,0 +1,331 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2012-01-06.13; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  # Exit code 63 means version mismatch.  This often happens
+  # when the user try to use an ancient version of a tool on
+  # a file that requires a minimum version.  In this case we
+  # we should proceed has if the program had been absent, or
+  # if --run hadn't been passed.
+  if test $? = 63; then
+    run=:
+    msg="probably too old"
+  fi
+  ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  autom4te     touch the output file, or create a stub one
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+  s/^gnu-//; t
+  s/^gnu//; t
+  s/^g//; t'`
+
+# Now exit if we have it, but it failed.  Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).  This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+  lex*|yacc*)
+    # Not GNU programs, they don't have --version.
+    ;;
+
+  *)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       # Could not run --version or --help.  This is probably someone
+       # running `$TOOL --version' or `$TOOL --help' to check whether
+       # $TOOL exists and not knowing $TOOL uses missing.
+       exit 1
+    fi
+    ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+  aclocal*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case $f in
+      *:*) touch_files="$touch_files "`echo "$f" |
+                                      sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+          sed 's/\.am$/.in/' |
+          while read f; do touch "$f"; done
+    ;;
+
+  autom4te*)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo "#! /bin/sh"
+       echo "# Created by GNU Automake missing as a replacement of"
+       echo "#  $ $@"
+       echo "exit 0"
+       chmod +x $file
+       exit 1
+    fi
+    ;;
+
+  bison*|yacc*)
+    echo 1>&2 "\
+WARNING: \`$1' $msg.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if test $# -ne 1; then
+        eval LASTARG=\${$#}
+       case $LASTARG in
+       *.y)
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+           if test -f "$SRCFILE"; then
+                cp "$SRCFILE" y.tab.c
+           fi
+           SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+           if test -f "$SRCFILE"; then
+                cp "$SRCFILE" y.tab.h
+           fi
+         ;;
+       esac
+    fi
+    if test ! -f y.tab.h; then
+       echo >y.tab.h
+    fi
+    if test ! -f y.tab.c; then
+       echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex*|flex*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if test $# -ne 1; then
+        eval LASTARG=\${$#}
+       case $LASTARG in
+       *.l)
+           SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+           if test -f "$SRCFILE"; then
+                cp "$SRCFILE" lex.yy.c
+           fi
+         ;;
+       esac
+    fi
+    if test ! -f lex.yy.c; then
+       echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+        you modified a dependency of a manual page.  You may need the
+        \`Help2man' package in order for those modifications to take
+        effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+       touch $file
+    else
+       test -z "$file" || exec >$file
+       echo ".ab help2man is required to generate this page"
+       exit $?
+    fi
+    ;;
+
+  makeinfo*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    # The file to touch is that specified with -o ...
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -z "$file"; then
+      # ... or it is the one specified with @setfilename ...
+      infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '
+       /^@setfilename/{
+         s/.* \([^ ]*\) *$/\1/
+         p
+         q
+       }' $infile`
+      # ... or it is derived from the source name (dir/f.texi becomes f.info)
+      test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+    fi
+    # If the file does not exist, the user really needs makeinfo;
+    # let's fail without touching anything.
+    test -f $file || exit 1
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..701bd27
--- /dev/null
+++ b/configure
@@ -0,0 +1,15398 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.68 for libnl 3.2.22.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+        /*)
+          for as_base in sh bash ksh sh5; do
+            # Try only shells that exist, to save several forks.
+            as_shell=$as_dir/$as_base
+            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+          done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  # We cannot yet assume a decent shell, so we have to provide a
+       # neutralization value for shells without unset; and this also
+       # works around shells that cannot unset nonexistent variables.
+       # Preserve -v and -x to the replacement shell.
+       BASH_ENV=/dev/null
+       ENV=/dev/null
+       (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+       export CONFIG_SHELL
+       case $- in # ((((
+         *v*x* | *x*v* ) as_opts=-vx ;;
+         *v* ) as_opts=-v ;;
+         *x* ) as_opts=-x ;;
+         * ) as_opts= ;;
+       esac
+       exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in #(
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='libnl'
+PACKAGE_TARNAME='libnl'
+PACKAGE_VERSION='3.2.22'
+PACKAGE_STRING='libnl 3.2.22'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL='http://www.infradead.org/~tgr/libnl/'
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+enable_option_checking=no
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+subdirs
+ENABLE_DEBUG_FALSE
+ENABLE_DEBUG_TRUE
+DISABLE_PTHREADS_FALSE
+DISABLE_PTHREADS_TRUE
+ENABLE_CLI_FALSE
+ENABLE_CLI_TRUE
+pkgconfigdir
+ENABLE_UNIT_TESTS_FALSE
+ENABLE_UNIT_TESTS_TRUE
+CHECK_LIBS
+CHECK_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
+YACC
+FLEX
+CPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+DLLTOOL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+GREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+LT_AGE
+LT_REVISION
+LT_CURRENT
+LIBNL_VERSION
+MIC_VERSION
+MIN_VERSION
+MAJ_VERSION
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+ac_ct_AR
+AR
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+with_pkgconfigdir
+enable_cli
+enable_pthreads
+enable_debug
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+CHECK_CFLAGS
+CHECK_LIBS'
+ac_subdirs_all='doc'
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used" >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_myself" : 'X\(//\)[^/]' \| \
+        X"$as_myself" : 'X\(//\)$' \| \
+        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures libnl 3.2.22 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/libnl]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of libnl 3.2.22:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-silent-rules          less verbose build output (undo: `make V=1')
+  --disable-silent-rules         verbose build output (undo: `make V=0')
+  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+  --disable-cli           Do not build command line interface utils
+  --disable-pthreads      Disable pthreads support
+  --disable-debug         Do not include debugging statements
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-sysroot=DIR Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).
+  --with-pkgconfigdir=PATH
+                          Path to the pkgconfig directory [[LIBDIR/pkgconfig]]
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  CHECK_CFLAGS
+              C compiler flags for CHECK, overriding pkg-config
+  CHECK_LIBS  linker flags for CHECK, overriding pkg-config
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+libnl home page: <http://www.infradead.org/~tgr/libnl/>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+libnl configure 3.2.22
+generated by GNU Autoconf 2.68
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by libnl $as_me 3.2.22, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_config_headers="$ac_config_headers lib/defs.h"
+
+ac_aux_dir=
+for ac_dir in build-aux "$srcdir"/build-aux; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+
+am__api_version='1.11'
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           rm -rf conftest.one conftest.two conftest.dir
+           echo one > conftest.one
+           echo two > conftest.two
+           mkdir conftest.dir
+           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+             test -s conftest.one && test -s conftest.two &&
+             test -s conftest.dir/conftest.one &&
+             test -s conftest.dir/conftest.two
+           then
+             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+             break 3
+           fi
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \    ]*)
+    as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t "$srcdir/configure" conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$*" != "X $srcdir/configure conftest.file" \
+      && test "$*" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+   fi
+
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\    *)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\    *)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+        for ac_exec_ext in '' $ac_executable_extensions; do
+          { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+          case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+            'mkdir (GNU coreutils) '* | \
+            'mkdir (coreutils) '* | \
+            'mkdir (fileutils) '4.1*)
+              ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+              break 3;;
+          esac
+        done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+  [\\/$]* | ?:[\\/]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+       @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='libnl'
+ VERSION='3.2.22'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no)  AM_DEFAULT_VERBOSITY=1;;
+*)   AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+       @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+       @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+       continue
+      else
+       break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar lib "link -lib"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar lib "link -lib"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5
+$as_echo_n "checking the archiver ($AR) interface... " >&6; }
+if ${am_cv_ar_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  am_cv_ar_interface=ar
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int some_variable = 0;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5'
+        { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5
+$as_echo "$am_cv_ar_interface" >&6; }
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  as_fn_error $? "could not determine $AR interface" "$LINENO" 5
+  ;;
+esac
+
+
+MAJ_VERSION=3
+
+MIN_VERSION=2
+
+MIC_VERSION=22
+
+LIBNL_VERSION=3.2.22
+
+
+LT_CURRENT=217
+
+LT_REVISION=0
+
+LT_AGE=17
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+       continue
+      else
+       break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+if test "x$CC" != xcc; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5
+$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5
+$as_echo_n "checking whether cc understands -c and -o together... " >&6; }
+fi
+set dummy $CC; ac_cc=`$as_echo "$2" |
+                     sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+rm -f conftest2.*
+if { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } &&
+   test -f conftest2.$ac_objext && { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; };
+then
+  eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+  if test "x$CC" != xcc; then
+    # Test first that cc exists at all.
+    if { ac_try='cc -c conftest.$ac_ext >&5'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+      ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+      rm -f conftest2.*
+      if { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } &&
+        test -f conftest2.$ac_objext && { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; };
+      then
+       # cc works too.
+       :
+      else
+       # cc exists but doesn't like -o.
+       eval ac_cv_prog_cc_${ac_cc}_c_o=no
+      fi
+    fi
+  fi
+else
+  eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f core conftest*
+
+fi
+if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h
+
+fi
+
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
+if test "$am_t" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+
+
+
+case `pwd` in
+  *\ * | *\    *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+       # Check to see if the nm accepts a BSD-compat flag.
+       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+       #   nm: unknown option "B" ignored
+       # Tru64's nm complains that /dev/null is an invalid object file
+       case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+       */dev/null* | *'Invalid file or object type'*)
+         lt_cv_path_NM="$tmp_nm -B"
+         break
+         ;;
+       *)
+         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+         */dev/null*)
+           lt_cv_path_NM="$tmp_nm -p"
+           break
+           ;;
+         *)
+           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+           continue # so that we can try to find one that supports BSD flags
+           ;;
+         esac
+         ;;
+       esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[         ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+             test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ar_at_file=no
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+       # Ensure the archiver fails upon bogus file names.
+       rm -f conftest.$ac_objext libconftest.a
+       { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+       if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[     ]\($symcode$symcode*\)[         ][      ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+       mv -f "$nlist"T "$nlist"
+      else
+       rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+       if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+         cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+         # Now generate the symbol file.
+         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+         cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+         $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+         cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+         # Now try linking the two files.
+         mv conftest.$ac_objext conftstm.$ac_objext
+         lt_globsym_save_LIBS=$LIBS
+         lt_globsym_save_CFLAGS=$CFLAGS
+         LIBS="conftstm.$ac_objext"
+         CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+         if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+           pipe_works=yes
+         fi
+         LIBS=$lt_globsym_save_LIBS
+         CFLAGS=$lt_globsym_save_CFLAGS
+       else
+         echo "cannot find nm_test_func in $nlist" >&5
+       fi
+      else
+       echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+  withval=$with_sysroot;
+else
+  with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+   ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+       HPUX_IA64_MODE="32"
+       ;;
+      *ELF-64*)
+       HPUX_IA64_MODE="64"
+       ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+       *32-bit*)
+         LD="${LD-ld} -melf32bsmip"
+         ;;
+       *N32*)
+         LD="${LD-ld} -melf32bmipn32"
+         ;;
+       *64-bit*)
+         LD="${LD-ld} -melf64bmip"
+       ;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+       *32-bit*)
+         LD="${LD-ld} -32"
+         ;;
+       *N32*)
+         LD="${LD-ld} -n32"
+         ;;
+       *64-bit*)
+         LD="${LD-ld} -64"
+         ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+       case $host in
+         x86_64-*kfreebsd*-gnu)
+           LD="${LD-ld} -m elf_i386_fbsd"
+           ;;
+         x86_64-*linux*)
+           LD="${LD-ld} -m elf_i386"
+           ;;
+         ppc64-*linux*|powerpc64-*linux*)
+           LD="${LD-ld} -m elf32ppclinux"
+           ;;
+         s390x-*linux*)
+           LD="${LD-ld} -m elf_s390"
+           ;;
+         sparc64-*linux*)
+           LD="${LD-ld} -m elf32_sparc"
+           ;;
+       esac
+       ;;
+      *64-bit*)
+       case $host in
+         x86_64-*kfreebsd*-gnu)
+           LD="${LD-ld} -m elf_x86_64_fbsd"
+           ;;
+         x86_64-*linux*)
+           LD="${LD-ld} -m elf_x86_64"
+           ;;
+         ppc*-*linux*|powerpc*-*linux*)
+           LD="${LD-ld} -m elf64ppc"
+           ;;
+         s390*-*linux*|s390*-*tpf*)
+           LD="${LD-ld} -m elf64_s390"
+           ;;
+         sparc*-*linux*)
+           LD="${LD-ld} -m elf64_sparc"
+           ;;
+       esac
+       ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+       if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+         LD="${LD-ld} -64"
+       fi
+       ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MANIFEST_TOOL"; then
+  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+  # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_MANIFEST_TOOL"; then
+  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_MANIFEST_TOOL" = x; then
+    MANIFEST_TOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+  fi
+else
+  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&5
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+       # By default we will add the -single_module flag. You can override
+       # by either setting the environment variable LT_MULTI_MODULE
+       # non-empty at configure time, or by adding -multi_module to the
+       # link flags.
+       rm -rf libconftest.dylib*
+       echo "int foo(void){return 1;}" > conftest.c
+       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+       # If there is a non-empty error log, and "single_module"
+       # appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+         cat conftest.err >&5
+       # Otherwise, if the output was created with a 0 exit code from
+       # the compiler, it worked.
+       elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+         lt_cv_apple_cc_single_mod=yes
+       else
+         cat conftest.err >&5
+       fi
+       rm -rf libconftest.dylib*
+       rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+       LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+       cat conftest.err >&5
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+       10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+       10.[012]*)
+         _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+       10.*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+  enable_win32_dll=no
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_shared=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_static=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+       IFS="$lt_save_ifs"
+       if test "X$lt_pkg" = "X$lt_p"; then
+         pic_mode=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_fast_install=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+           :
+         else
+           cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+         fi ;;
+       esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+           :
+         else
+           cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+         fi ;;
+       esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+       # +Z the default
+       ;;
+      *)
+       lt_prog_compiler_pic='-fPIC'
+       ;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      if test -n "$lt_prog_compiler_pic"; then
+        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       lt_prog_compiler_static='-Bstatic'
+      else
+       lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       lt_prog_compiler_pic='+Z'
+       ;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+       lt_prog_compiler_wl='-Wl,'
+       lt_prog_compiler_pic='-KPIC'
+       lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+       lt_prog_compiler_wl='-Wl,'
+       lt_prog_compiler_pic='-fPIC'
+       lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+       lt_prog_compiler_wl='-Wl,'
+       lt_prog_compiler_pic='--shared'
+       lt_prog_compiler_static='--static'
+       ;;
+      nagfor*)
+       # NAG Fortran compiler
+       lt_prog_compiler_wl='-Wl,-Wl,,'
+       lt_prog_compiler_pic='-PIC'
+       lt_prog_compiler_static='-Bstatic'
+       ;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       lt_prog_compiler_wl='-Wl,'
+       lt_prog_compiler_pic='-fpic'
+       lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+       lt_prog_compiler_wl='-Wl,'
+       lt_prog_compiler_pic='-qpic'
+       lt_prog_compiler_static='-qstaticlink'
+       ;;
+      *)
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+         # Sun Fortran 8.3 passes all unrecognized flags to the linker
+         lt_prog_compiler_pic='-KPIC'
+         lt_prog_compiler_static='-Bstatic'
+         lt_prog_compiler_wl=''
+         ;;
+       *Sun\ F* | *Sun*Fortran*)
+         lt_prog_compiler_pic='-KPIC'
+         lt_prog_compiler_static='-Bstatic'
+         lt_prog_compiler_wl='-Qoption ld '
+         ;;
+       *Sun\ C*)
+         # Sun C 5.9
+         lt_prog_compiler_pic='-KPIC'
+         lt_prog_compiler_static='-Bstatic'
+         lt_prog_compiler_wl='-Wl,'
+         ;;
+        *Intel*\ [CF]*Compiler*)
+         lt_prog_compiler_wl='-Wl,'
+         lt_prog_compiler_pic='-fPIC'
+         lt_prog_compiler_static='-static'
+         ;;
+       *Portland\ Group*)
+         lt_prog_compiler_wl='-Wl,'
+         lt_prog_compiler_pic='-fpic'
+         lt_prog_compiler_static='-Bstatic'
+         ;;
+       esac
+       ;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+       lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+       lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+       lt_prog_compiler_pic='-Kconform_pic'
+       lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+         *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+       ld_shlibs=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       allow_undefined_flag=unsupported
+       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+       # support --undefined.  This deserves some investigation.  FIXME
+       archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+       ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+         cp $export_symbols $output_objdir/$soname.def;
+       else
+         echo EXPORTS > $output_objdir/$soname.def;
+         cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+       $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+       ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+       case $cc_basename in
+         diet\ *) tmp_diet=yes;;       # linux-dietlibc with static linking (!diet-dyn)
+       esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+        && test "$tmp_diet" = no
+      then
+       tmp_addflag=' $pic_flag'
+       tmp_sharedflag='-shared'
+       case $cc_basename,$host_cpu in
+        pgcc*)                         # Portland Group C compiler
+         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # Portland Group f77 and f90 compilers
+         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag -Mnomain' ;;
+       ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
+         tmp_addflag=' -i_dynamic' ;;
+       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
+         tmp_addflag=' -i_dynamic -nofor_main' ;;
+       ifc* | ifort*)                  # Intel Fortran compiler
+         tmp_addflag=' -nofor_main' ;;
+       lf95*)                          # Lahey Fortran 8.1
+         whole_archive_flag_spec=
+         tmp_sharedflag='--shared' ;;
+       xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+         tmp_sharedflag='-qmkshrobj'
+         tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         compiler_needs_object=yes
+         ;;
+       esac
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ C*)                       # Sun C 5.9
+         whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         compiler_needs_object=yes
+         tmp_sharedflag='-G' ;;
+       *Sun\ F*)                       # Sun Fortran 8.3
+         tmp_sharedflag='-G' ;;
+       esac
+       archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+           cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+           echo "local: *; };" >> $output_objdir/$libname.ver~
+           $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+       case $cc_basename in
+       xlf* | bgf* | bgxlf* | mpixlf*)
+         # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+         whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+         hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+         archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+         if test "x$supports_anon_versioning" = xyes; then
+           archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+             cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+             echo "local: *; };" >> $output_objdir/$libname.ver~
+             $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+         fi
+         ;;
+       esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+      else
+       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+       ld_shlibs=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+       ld_shlibs=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+       ;;
+       *)
+         # For security reasons, it is highly recommended that you always
+         # use absolute paths for naming shared libraries, and exclude the
+         # DT_RUNPATH tag from executables and libraries.  But doing so
+         # requires that you compile everything twice, which is a pain.
+         if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+           hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+           archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         else
+           ld_shlibs=no
+         fi
+       ;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+       # Neither direct hardcoding nor static linking is supported with a
+       # broken collect2.
+       hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+       # On IA64, the linker does run time linking by default, so we don't
+       # have to do anything special.
+       aix_use_runtimelinking=no
+       exp_sym_flag='-Bexport'
+       no_entry_flag=""
+      else
+       # If we're using GNU nm, then we don't want the "-C" option.
+       # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
+       if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+         export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+       else
+         export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+       fi
+       aix_use_runtimelinking=no
+
+       # Test if we are trying to use run time linking or normal
+       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+       # need to do runtime linking.
+       case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+         for ld_flag in $LDFLAGS; do
+         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+           aix_use_runtimelinking=yes
+           break
+         fi
+         done
+         ;;
+       esac
+
+       exp_sym_flag='-bexport'
+       no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='${wl}-f,'
+
+      if test "$GCC" = yes; then
+       case $host_os in aix4.[012]|aix4.[012].*)
+       # We only want to do this on AIX 4.2 and lower, the check
+       # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" &&
+          strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+         then
+         # We have reworked collect2
+         :
+         else
+         # We have old collect2
+         hardcode_direct=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         hardcode_minus_L=yes
+         hardcode_libdir_flag_spec='-L$libdir'
+         hardcode_libdir_separator=
+         fi
+         ;;
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag="$shared_flag "'${wl}-G'
+       fi
+      else
+       # not using gcc
+       if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+       else
+         if test "$aix_use_runtimelinking" = yes; then
+           shared_flag='${wl}-G'
+         else
+           shared_flag='${wl}-bM:SRE'
+         fi
+       fi
+      fi
+
+      export_dynamic_flag_spec='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+       # Warning - without using the other runtime loading flags (-brtl),
+       # -berok will link without error, but may produce a broken library.
+       allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+         /^0/ {
+             s/^0  *\([^ ]*\) *$/\1/
+             p
+         }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+       if test "$host_cpu" = ia64; then
+         hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+         allow_undefined_flag="-z nodefs"
+         archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+       else
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+         /^0/ {
+             s/^0  *\([^ ]*\) *$/\1/
+             p
+         }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+         # Warning - without using the other run time loading flags,
+         # -berok will link without error, but may produce a broken library.
+         no_undefined_flag=' ${wl}-bernotok'
+         allow_undefined_flag=' ${wl}-berok'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           whole_archive_flag_spec='$convenience'
+         fi
+         archive_cmds_need_lc=yes
+         # This is similar to how AIX traditionally builds its shared libraries.
+         archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+       # Native MSVC
+       hardcode_libdir_flag_spec=' '
+       allow_undefined_flag=unsupported
+       always_export_symbols=yes
+       file_list_spec='@'
+       # Tell ltmain to make .lib files, not .a files.
+       libext=lib
+       # Tell ltmain to make .dll files, not .so files.
+       shrext_cmds=".dll"
+       # FIXME: Setting linknames here is a bad hack.
+       archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+       archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+           sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+         else
+           sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+         fi~
+         $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+         linknames='
+       # The linker will not automatically build a static lib if we build a DLL.
+       # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+       enable_shared_with_static_runtimes=yes
+       exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+       export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+       # Don't use ranlib
+       old_postinstall_cmds='chmod 644 $oldlib'
+       postlink_cmds='lt_outputfile="@OUTPUT@"~
+         lt_tool_outputfile="@TOOL_OUTPUT@"~
+         case $lt_outputfile in
+           *.exe|*.EXE) ;;
+           *)
+             lt_outputfile="$lt_outputfile.exe"
+             lt_tool_outputfile="$lt_tool_outputfile.exe"
+             ;;
+         esac~
+         if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+           $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+           $RM "$lt_outputfile.manifest";
+         fi'
+       ;;
+      *)
+       # Assume MSVC wrapper
+       hardcode_libdir_flag_spec=' '
+       allow_undefined_flag=unsupported
+       # Tell ltmain to make .lib files, not .a files.
+       libext=lib
+       # Tell ltmain to make .dll files, not .so files.
+       shrext_cmds=".dll"
+       # FIXME: Setting linknames here is a bad hack.
+       archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+       # The linker will automatically build a .lib file if we build a DLL.
+       old_archive_from_new_cmds='true'
+       # FIXME: Should let the user specify the lib program.
+       old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+       enable_shared_with_static_runtimes=yes
+       ;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+       archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+       archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+       hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+       hardcode_libdir_separator=:
+       hardcode_direct=yes
+       hardcode_direct_absolute=yes
+       export_dynamic_flag_spec='${wl}-E'
+       # hardcode_minus_L: Not really in the search PATH,
+       # but as the default location of the library.
+       hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       case $host_cpu in
+       hppa*64*)
+         archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+      else
+       case $host_cpu in
+       hppa*64*)
+         archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+
+         # Older versions of the 11.00 compiler do not understand -b yet
+         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+         { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+         ;;
+       esac
+      fi
+      if test "$with_gnu_ld" = no; then
+       hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+       hardcode_libdir_separator=:
+
+       case $host_cpu in
+       hppa*64*|ia64*)
+         hardcode_direct=no
+         hardcode_shlibpath_var=no
+         ;;
+       *)
+         hardcode_direct=yes
+         hardcode_direct_absolute=yes
+         export_dynamic_flag_spec='${wl}-E'
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         hardcode_minus_L=yes
+         ;;
+       esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       # Try to use the -exported_symbol ld option, if it does not
+       # work, assume that -exports_file does not work either and
+       # implicitly export all symbols.
+       # This should be the same for all languages, so no per-tag cache variable.
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS="$LDFLAGS"
+          LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+          cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+       if test "$lt_cv_irix_exported_symbol" = yes; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+       fi
+      else
+       archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+       archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+       hardcode_direct=yes
+       hardcode_shlibpath_var=no
+       hardcode_direct_absolute=yes
+       if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+         archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+         archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+         hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+         export_dynamic_flag_spec='${wl}-E'
+       else
+         case $host_os in
+          openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+            archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+            hardcode_libdir_flag_spec='-R$libdir'
+            ;;
+          *)
+            archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+            hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+            ;;
+         esac
+       fi
+      else
+       ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+       allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       allow_undefined_flag=' -expect_unresolved \*'
+       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)     # as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+       allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+       archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+       allow_undefined_flag=' -expect_unresolved \*'
+       archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+       # Both c and cxx compiler support -rpath directly
+       hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test "$GCC" = yes; then
+       wlarc='${wl}'
+       archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+       case `$CC -V 2>&1` in
+       *"Compilers 5.0"*)
+         wlarc=''
+         archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+         ;;
+       *)
+         wlarc='${wl}'
+         archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+         archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+         ;;
+       esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+       # The compiler driver will combine and reorder linker options,
+       # but understands `-z linker_flag'.  GCC discards it without `$wl',
+       # but is careful enough not to reorder.
+       # Supported since Solaris 2.6 (maybe 2.5.1?)
+       if test "$GCC" = yes; then
+         whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+       else
+         whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+       fi
+       ;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+       # Use $CC to link under sequent, because it throws in some extra .o
+       # files that make .init and .fini sections work.
+       archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+       sni)
+         archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         hardcode_direct=yes # is this really true???
+       ;;
+       siemens)
+         ## LD is ld it makes a PLAMLIB
+         ## CC just makes a GrossModule.
+         archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+         reload_cmds='$CC -r -o $output$reload_objs'
+         hardcode_direct=no
+        ;;
+       motorola)
+         archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+       ;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       hardcode_shlibpath_var=no
+       runpath_var=LD_RUN_PATH
+       hardcode_runpath_var=yes
+       ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='${wl}-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='${wl}-z,text'
+      allow_undefined_flag='${wl}-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+       export_dynamic_flag_spec='${wl}-Blargedynsym'
+       ;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+       if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+         soname=conftest
+         lib=conftest
+         libobjs=conftest.$ac_objext
+         deplibs=
+         wl=$lt_prog_compiler_wl
+         pic_flag=$lt_prog_compiler_pic
+         compiler_flags=-v
+         linker_flags=-v
+         verstring=
+         output_objdir=.
+         libname=conftest
+         lt_save_allow_undefined_flag=$allow_undefined_flag
+         allow_undefined_flag=
+         if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+         then
+           lt_cv_archive_cmds_need_lc=no
+         else
+           lt_cv_archive_cmds_need_lc=yes
+         fi
+         allow_undefined_flag=$lt_save_allow_undefined_flag
+       else
+         cat conftest.err 1>&5
+       fi
+       $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+       lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+          echo ' yes '
+          echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+       :
+      else
+       can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+       if test "$lt_cv_prog_gnu_ld" = yes; then
+               version_type=linux # correct to gnu/linux during the next big refactor
+       else
+               version_type=irix
+       fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+        LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Add ABI-specific directories to the system library path.
+  sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[      ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+    *)                         need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+       shlibpath_overrides_runpath=no
+       ;;
+      *)
+       shlibpath_overrides_runpath=yes
+       ;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+       ;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test "X$hardcode_automatic" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+   test "$inherit_rpath" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+         if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL          RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL                DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL                0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW         DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW       RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW     DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW     0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+       }
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+         if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL          RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL                DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL                0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW         DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW       RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW     DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW     0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+       }
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report which library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+for ac_prog in 'flex'
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_FLEX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$FLEX"; then
+  ac_cv_prog_FLEX="$FLEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_FLEX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+FLEX=$ac_cv_prog_FLEX
+if test -n "$FLEX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5
+$as_echo "$FLEX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$FLEX" && break
+done
+
+for ac_prog in 'bison -y'
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_YACC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_YACC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset cs;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *pcpcc;
+  char **ppc;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  pcpcc = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++pcpcc;
+  ppc = (char**) pcpcc;
+  pcpcc = (char const *const *) ppc;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+    if (s) return 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+    if (!foo) return 0;
+  }
+  return !cs[0] && !zero.x;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_const=yes
+else
+  ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=0.9.0
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       else
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+               PKG_CONFIG=""
+       fi
+fi
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CHECK" >&5
+$as_echo_n "checking for CHECK... " >&6; }
+
+if test -n "$CHECK_CFLAGS"; then
+    pkg_cv_CHECK_CFLAGS="$CHECK_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "check >= 0.9.0") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CHECK_CFLAGS=`$PKG_CONFIG --cflags "check >= 0.9.0" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$CHECK_LIBS"; then
+    pkg_cv_CHECK_LIBS="$CHECK_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "check >= 0.9.0") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_CHECK_LIBS=`$PKG_CONFIG --libs "check >= 0.9.0" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               CHECK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "check >= 0.9.0" 2>&1`
+        else
+               CHECK_PKG_ERRORS=`$PKG_CONFIG --print-errors "check >= 0.9.0" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$CHECK_PKG_ERRORS" >&5
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Disabling building of unit tests" >&5
+$as_echo "$as_me: WARNING: *** Disabling building of unit tests" >&2;}
+        enable_unit_tests="no"
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: *** Disabling building of unit tests" >&5
+$as_echo "$as_me: WARNING: *** Disabling building of unit tests" >&2;}
+        enable_unit_tests="no"
+else
+       CHECK_CFLAGS=$pkg_cv_CHECK_CFLAGS
+       CHECK_LIBS=$pkg_cv_CHECK_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       enable_unit_tests="yes"
+fi
+
+ if test "$enable_unit_tests" = "yes"; then
+  ENABLE_UNIT_TESTS_TRUE=
+  ENABLE_UNIT_TESTS_FALSE='#'
+else
+  ENABLE_UNIT_TESTS_TRUE='#'
+  ENABLE_UNIT_TESTS_FALSE=
+fi
+
+
+
+# Check whether --with-pkgconfigdir was given.
+if test "${with_pkgconfigdir+set}" = set; then :
+  withval=$with_pkgconfigdir; pkgconfigdir="$withval"
+else
+  pkgconfigdir='${libdir}/pkgconfig'
+fi
+
+
+
+# Check whether --enable-cli was given.
+if test "${enable_cli+set}" = set; then :
+  enableval=$enable_cli; enable_cli="$enableval"
+else
+  enable_cli="yes"
+fi
+
+ if test "$enable_cli" = "yes"; then
+  ENABLE_CLI_TRUE=
+  ENABLE_CLI_FALSE='#'
+else
+  ENABLE_CLI_TRUE='#'
+  ENABLE_CLI_FALSE=
+fi
+
+
+# Check whether --enable-pthreads was given.
+if test "${enable_pthreads+set}" = set; then :
+  enableval=$enable_pthreads; enable_pthreads="$enableval"
+else
+  enable_pthreads="yes"
+fi
+
+ if test "$enable_pthreads" = "no"; then
+  DISABLE_PTHREADS_TRUE=
+  DISABLE_PTHREADS_FALSE='#'
+else
+  DISABLE_PTHREADS_TRUE='#'
+  DISABLE_PTHREADS_FALSE=
+fi
+
+
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug; enable_debug="$enableval"
+else
+  enable_debug="yes"
+fi
+
+ if test "$enable_debug" = "no" ; then
+  ENABLE_DEBUG_TRUE=
+  ENABLE_DEBUG_FALSE='#'
+else
+  ENABLE_DEBUG_TRUE='#'
+  ENABLE_DEBUG_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5
+$as_echo_n "checking for pow in -lm... " >&6; }
+if ${ac_cv_lib_m_pow+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pow ();
+int
+main ()
+{
+return pow ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_pow=yes
+else
+  ac_cv_lib_m_pow=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5
+$as_echo "$ac_cv_lib_m_pow" >&6; }
+if test "x$ac_cv_lib_m_pow" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+else
+  as_fn_error $? "libm is required" "$LINENO" 5
+fi
+
+
+if test "x$enable_pthreads" = "xno"; then
+
+$as_echo "#define DISABLE_PTHREADS 1" >>confdefs.h
+
+else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_lock in -lpthread" >&5
+$as_echo_n "checking for pthread_mutex_lock in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_mutex_lock+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_mutex_lock ();
+int
+main ()
+{
+return pthread_mutex_lock ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_mutex_lock=yes
+else
+  ac_cv_lib_pthread_pthread_mutex_lock=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_lock" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_mutex_lock" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_mutex_lock" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "libpthread is required" "$LINENO" 5
+fi
+
+fi
+
+if test "x$enable_debug" = "xyes"; then
+
+$as_echo "#define NL_DEBUG 1" >>confdefs.h
+
+fi
+
+
+
+subdirs="$subdirs doc"
+
+
+ac_config_files="$ac_config_files Makefile libnl-3.0.pc libnl-route-3.0.pc libnl-genl-3.0.pc libnl-nf-3.0.pc libnl-cli-3.0.pc lib/Makefile include/Makefile src/Makefile src/lib/Makefile tests/Makefile man/Makefile python/Makefile python/setup.py python/netlink/Makefile python/netlink/route/Makefile include/netlink/version.h"
+
+
+ac_errcount=0
+if test -z "$YACC"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: bison not found. Please install before continuing." >&5
+$as_echo "$as_me: WARNING: bison not found. Please install before continuing." >&2;}
+    ac_errcount=$((ac_errcount + 1))
+fi
+if test -z "$FLEX"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: flex not found. Please install before continuing." >&5
+$as_echo "$as_me: WARNING: flex not found. Please install before continuing." >&2;}
+    ac_errcount=$((ac_errcount + 1))
+fi
+if test $ac_errcount -gt 0; then
+    as_fn_error $? "Required packages are missing. Please install them and rerun ./configure" "$LINENO" 5
+fi
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+       cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+         mv -f confcache "$cache_file"$$ &&
+         mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+         mv -f confcache "$cache_file" ;;
+       esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_UNIT_TESTS_TRUE}" && test -z "${ENABLE_UNIT_TESTS_FALSE}"; then
+  as_fn_error $? "conditional \"ENABLE_UNIT_TESTS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_CLI_TRUE}" && test -z "${ENABLE_CLI_FALSE}"; then
+  as_fn_error $? "conditional \"ENABLE_CLI\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${DISABLE_PTHREADS_TRUE}" && test -z "${DISABLE_PTHREADS_FALSE}"; then
+  as_fn_error $? "conditional \"DISABLE_PTHREADS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_DEBUG_TRUE}" && test -z "${ENABLE_DEBUG_FALSE}"; then
+  as_fn_error $? "conditional \"ENABLE_DEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='        ';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in #(
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by libnl $as_me 3.2.22, which was
+generated by GNU Autoconf 2.68.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider.
+libnl home page: <http://www.infradead.org/~tgr/libnl/>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+libnl config.status 3.2.22
+configured by $0, generated by GNU Autoconf 2.68,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "lib/defs.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/defs.h" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "libnl-3.0.pc") CONFIG_FILES="$CONFIG_FILES libnl-3.0.pc" ;;
+    "libnl-route-3.0.pc") CONFIG_FILES="$CONFIG_FILES libnl-route-3.0.pc" ;;
+    "libnl-genl-3.0.pc") CONFIG_FILES="$CONFIG_FILES libnl-genl-3.0.pc" ;;
+    "libnl-nf-3.0.pc") CONFIG_FILES="$CONFIG_FILES libnl-nf-3.0.pc" ;;
+    "libnl-cli-3.0.pc") CONFIG_FILES="$CONFIG_FILES libnl-cli-3.0.pc" ;;
+    "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
+    "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
+    "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+    "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;;
+    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
+    "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
+    "python/Makefile") CONFIG_FILES="$CONFIG_FILES python/Makefile" ;;
+    "python/setup.py") CONFIG_FILES="$CONFIG_FILES python/setup.py" ;;
+    "python/netlink/Makefile") CONFIG_FILES="$CONFIG_FILES python/netlink/Makefile" ;;
+    "python/netlink/route/Makefile") CONFIG_FILES="$CONFIG_FILES python/netlink/route/Makefile" ;;
+    "include/netlink/version.h") CONFIG_FILES="$CONFIG_FILES include/netlink/version.h" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
+h
+s///
+s/^/:/
+s/[     ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[  ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[    ]*#[    ]*define[       ][      ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+       `' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+       || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$_am_arg" : 'X\(//\)[^/]' \| \
+        X"$_am_arg" : 'X\(//\)$' \| \
+        X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named `Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$mf" : 'X\(//\)[^/]' \| \
+        X"$mf" : 'X\(//\)$' \| \
+        X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running `make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+        sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$file" : 'X\(//\)[^/]' \| \
+        X"$file" : 'X\(//\)$' \| \
+        X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  if test x"$xsi_shell" = xyes; then
+  sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\    # positional parameters, so assign one to ordinary parameter first.\
+\    func_stripname_result=${3}\
+\    func_stripname_result=${func_stripname_result#"${1}"}\
+\    func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\    func_split_long_opt_name=${1%%=*}\
+\    func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\    func_split_short_opt_arg=${1#??}\
+\    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\    case ${1} in\
+\      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\      *)    func_lo2o_result=${1} ;;\
+\    esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+    func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+    func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+    func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+    eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\    func_quote_for_eval "${2}"\
+\    eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+
+#
+# CONFIG_SUBDIRS section.
+#
+if test "$no_recursion" != yes; then
+
+  # Remove --cache-file, --srcdir, and --disable-option-checking arguments
+  # so they do not pile up.
+  ac_sub_configure_args=
+  ac_prev=
+  eval "set x $ac_configure_args"
+  shift
+  for ac_arg
+  do
+    if test -n "$ac_prev"; then
+      ac_prev=
+      continue
+    fi
+    case $ac_arg in
+    -cache-file | --cache-file | --cache-fil | --cache-fi \
+    | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+      ac_prev=cache_file ;;
+    -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+    | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \
+    | --c=*)
+      ;;
+    --config-cache | -C)
+      ;;
+    -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+      ac_prev=srcdir ;;
+    -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+      ;;
+    -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+      ac_prev=prefix ;;
+    -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+      ;;
+    --disable-option-checking)
+      ;;
+    *)
+      case $ac_arg in
+      *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+      esac
+      as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
+    esac
+  done
+
+  # Always prepend --prefix to ensure using the same prefix
+  # in subdir configurations.
+  ac_arg="--prefix=$prefix"
+  case $ac_arg in
+  *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+  esac
+  ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
+
+  # Pass --silent
+  if test "$silent" = yes; then
+    ac_sub_configure_args="--silent $ac_sub_configure_args"
+  fi
+
+  # Always prepend --disable-option-checking to silence warnings, since
+  # different subdirs can have different --enable and --with options.
+  ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
+
+  ac_popdir=`pwd`
+  for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
+
+    # Do not complain, so a configure script can configure whichever
+    # parts of a large source tree are present.
+    test -d "$srcdir/$ac_dir" || continue
+
+    ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
+    $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
+    $as_echo "$ac_msg" >&6
+    as_dir="$ac_dir"; as_fn_mkdir_p
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+    cd "$ac_dir"
+
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      ac_sub_configure=$ac_srcdir/configure.gnu
+    elif test -f "$ac_srcdir/configure"; then
+      ac_sub_configure=$ac_srcdir/configure
+    elif test -f "$ac_srcdir/configure.in"; then
+      # This should be Cygnus configure.
+      ac_sub_configure=$ac_aux_dir/configure
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
+$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
+      ac_sub_configure=
+    fi
+
+    # The recursion is here.
+    if test -n "$ac_sub_configure"; then
+      # Make the cache file name correct relative to the subdirectory.
+      case $cache_file in
+      [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
+      *) # Relative name.
+       ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
+      esac
+
+      { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
+      # The eval makes quoting arguments work.
+      eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
+          --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
+       as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
+    fi
+
+    cd "$ac_popdir"
+  done
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+echo "-------------------------------------------------------------------------------"
+echo "                                  NOTE"
+echo ""
+echo " There have been some changes starting with 3.2 regarding where and how libnl"
+echo " is being installed on the system in order to allow multiple libnl versions"
+echo " to be installed in parallel:"
+echo ""
+echo "    - Headers will be installed in ${includedir}/libnl${MAJ_VERSION}, therefore"
+echo "      you will need to add \"-I/usr/include/libnl${MAJ_VERSION}\" to CFLAGS"
+echo ""
+echo "    - The library basename was renamed to libnl-${MAJ_VERSION}, i.e. the SO names become"
+echo "      libnl-${MAJ_VERSION}.so., libnl-route-${MAJ_VERSION}.so, etc."
+echo ""
+echo "    - libtool versioning was assumed, to ease detection of compatible library"
+echo "      versions."
+echo ""
+echo " If you are using pkg-config for detecting and linking against the library "
+echo " things will continue magically as if nothing every happened. If you are "
+echo " linking manually you need to adapt your Makefiles or switch to using "
+echo " pkg-config files."
+echo ""
+echo "-------------------------------------------------------------------------------"
+
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..34e8c9f
--- /dev/null
@@ -0,0 +1,176 @@
+#
+# configure.in
+#
+#      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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+#
+
+
+# copied from glib
+m4_define([libnl_major_version], [3])
+m4_define([libnl_minor_version], [2])
+m4_define([libnl_micro_version], [22])
+
+
+# The following explanation may help to understand the above rules a bit
+# better: consider that there are three possible kinds of reactions from
+# users of your library to changes in a shared library:
+#
+# 1. Programs using the previous version may use the new version as drop-in
+#    replacement, and programs using the new version can also work with the
+#    previous one. In other words, no recompiling nor relinking is needed.
+#    In this case, bump revision only, don't touch current nor age.
+#
+# 2. Programs using the previous version may use the new version as drop-in
+#    replacement, but programs using the new version may use APIs not
+#    present in the previous one. In other words, a program linking against
+#    the new version may fail with “unresolved symbols” if linking against
+#    the old version at runtime: set revision to 0, bump current and age.
+#
+# 3. Programs may need to be changed, recompiled, relinked in order to use
+#    the new version. Bump current, set revision and age to 0.
+
+m4_define([libnl_lt_current],    [217])
+m4_define([libnl_lt_revision],  [0])
+m4_define([libnl_lt_age],        [17])
+
+m4_define([libnl_version],
+         [libnl_major_version.libnl_minor_version.libnl_micro_version])
+
+AC_INIT(libnl, [libnl_version], [], [], [http://www.infradead.org/~tgr/libnl/])
+AC_CONFIG_HEADERS([lib/defs.h])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)], [])
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+
+MAJ_VERSION=libnl_major_version
+AC_SUBST(MAJ_VERSION)
+MIN_VERSION=libnl_minor_version
+AC_SUBST(MIN_VERSION)
+MIC_VERSION=libnl_micro_version
+AC_SUBST(MIC_VERSION)
+LIBNL_VERSION=libnl_version
+AC_SUBST(LIBNL_VERSION)
+
+LT_CURRENT=libnl_lt_current
+AC_SUBST(LT_CURRENT)
+LT_REVISION=libnl_lt_revision
+AC_SUBST(LT_REVISION)
+LT_AGE=libnl_lt_age
+AC_SUBST(LT_AGE)
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+AM_PROG_LIBTOOL
+AC_CHECK_PROGS(FLEX, 'flex')
+AC_CHECK_PROGS(YACC, 'bison -y')
+
+AC_C_CONST
+AC_C_INLINE
+
+PKG_CHECK_MODULES([CHECK], [check >= 0.9.0],
+       [enable_unit_tests="yes"],
+       [AC_MSG_WARN([*** Disabling building of unit tests])
+        enable_unit_tests="no"])
+
+AM_CONDITIONAL([ENABLE_UNIT_TESTS], [test "$enable_unit_tests" = "yes"])
+
+AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
+       [Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]),
+       [pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
+AC_SUBST([pkgconfigdir])
+
+AC_ARG_ENABLE([cli],
+       AS_HELP_STRING([--disable-cli], [Do not build command line interface utils]),
+       [enable_cli="$enableval"], [enable_cli="yes"])
+AM_CONDITIONAL([ENABLE_CLI], [test "$enable_cli" = "yes"])
+
+AC_ARG_ENABLE([pthreads],
+       AS_HELP_STRING([--disable-pthreads], [Disable pthreads support]),
+       [enable_pthreads="$enableval"], [enable_pthreads="yes"])
+AM_CONDITIONAL([DISABLE_PTHREADS], [test "$enable_pthreads" = "no"])
+
+AC_ARG_ENABLE([debug],
+       AS_HELP_STRING([--disable-debug], [Do not include debugging statements]),
+       [enable_debug="$enableval"], [enable_debug="yes"])
+AM_CONDITIONAL([ENABLE_DEBUG], [test "$enable_debug" = "no" ])
+
+AC_CHECK_LIB([m], [pow], [], AC_MSG_ERROR([libm is required]))
+
+if test "x$enable_pthreads" = "xno"; then
+    AC_DEFINE([DISABLE_PTHREADS], [1], [Define to 1 to disable pthreads])
+else
+    AC_CHECK_LIB([pthread], [pthread_mutex_lock], [], AC_MSG_ERROR([libpthread is required]))
+fi
+
+if test "x$enable_debug" = "xyes"; then
+    AC_DEFINE([NL_DEBUG], [1], [Define to 1 to enable debugging])
+fi
+
+AC_CONFIG_SUBDIRS([doc])
+
+AC_CONFIG_FILES([
+Makefile
+libnl-3.0.pc
+libnl-route-3.0.pc
+libnl-genl-3.0.pc
+libnl-nf-3.0.pc
+libnl-cli-3.0.pc
+lib/Makefile
+include/Makefile
+src/Makefile
+src/lib/Makefile
+tests/Makefile
+man/Makefile
+python/Makefile
+python/setup.py
+python/netlink/Makefile
+python/netlink/route/Makefile
+include/netlink/version.h
+])
+
+ac_errcount=0
+if test -z "$YACC"; then
+    AC_MSG_WARN(bison not found. Please install before continuing.)
+    ac_errcount=$((ac_errcount + 1))
+fi
+if test -z "$FLEX"; then
+    AC_MSG_WARN(flex not found. Please install before continuing.)
+    ac_errcount=$((ac_errcount + 1))
+fi
+if test $ac_errcount -gt 0; then
+    AC_MSG_ERROR(Required packages are missing. Please install them and rerun ./configure)
+fi
+
+AC_OUTPUT
+
+echo "-------------------------------------------------------------------------------"
+echo "                                  NOTE"
+echo ""
+echo " There have been some changes starting with 3.2 regarding where and how libnl"
+echo " is being installed on the system in order to allow multiple libnl versions"
+echo " to be installed in parallel:"
+echo ""
+echo "    - Headers will be installed in ${includedir}/libnl${MAJ_VERSION}, therefore"
+echo "      you will need to add \"-I/usr/include/libnl${MAJ_VERSION}\" to CFLAGS"
+echo ""
+echo "    - The library basename was renamed to libnl-${MAJ_VERSION}, i.e. the SO names become"
+echo "      libnl-${MAJ_VERSION}.so., libnl-route-${MAJ_VERSION}.so, etc."
+echo ""
+echo "    - libtool versioning was assumed, to ease detection of compatible library"
+echo "      versions."
+echo ""
+echo " If you are using pkg-config for detecting and linking against the library "
+echo " things will continue magically as if nothing every happened. If you are "
+echo " linking manually you need to adapt your Makefiles or switch to using "
+echo " pkg-config files."
+echo ""
+echo "-------------------------------------------------------------------------------"
+
diff --git a/etc/classid b/etc/classid
new file mode 100644 (file)
index 0000000..2203243
--- /dev/null
@@ -0,0 +1,45 @@
+###############################################################################
+#
+# ClassID <-> Name Translation Table
+#
+# This file can be used to assign names to classids for easier reference
+# in all libnl tools.
+#
+# Format:
+#   <MAJ:>             <NAME>          # qdisc definition
+#   <MAJ:MIN>          <NAME>          # class deifnition
+#   <NAME:MIN>         <NAME>          # class definition referencing an
+#                                        existing qdisc definition.
+#
+# Example:
+#   1:                 top             # top -> 1:0
+#   top:1              interactive     # interactive -> 1:1
+#   top:2              www             # www -> 1:2
+#   top:3              bulk            # bulk -> 1:3
+#   2:1                        test_class      # test_class -> 2:1
+#
+# Illegal Example:
+#   30:1                classD
+#   classD:2            invalidClass    # classD refers to a class, not a qdisc
+#
+###############################################################################
+
+# <CLASSID>            <NAME>
+
+# Reserved default classids
+0:0                    none
+ffff:ffff              root
+ffff:fff1              ingress
+
+#
+# List your classid definitions here:
+#
+
+
+
+###############################################################################
+# List of auto-generated classids
+#
+# DO NOT ADD CLASSID DEFINITIONS BELOW THIS LINE
+#
+# <CLASSID>            <NAME>
diff --git a/etc/pktloc b/etc/pktloc
new file mode 100644 (file)
index 0000000..505c44e
--- /dev/null
@@ -0,0 +1,76 @@
+#
+# Location definitions for packet matching
+#
+
+# name         alignment       offset          mask            shift
+ip.version     u8              net+0           0xF0            4
+ip.hdrlen      u8              net+0           0x0F
+ip.diffserv    u8              net+1
+ip.length      u16             net+2
+ip.id          u16             net+4
+ip.flag.res    u8              net+6           0xff            7
+ip.df          u8              net+6           0x40            6
+ip.mf          u8              net+6           0x20            5
+ip.offset      u16             net+6           0x1FFF
+ip.ttl         u8              net+8
+ip.proto       u8              net+9
+ip.chksum      u16             net+10
+ip.src         u32             net+12
+ip.dst         u32             net+16
+
+# if ip.ihl > 5
+ip.opts                u32             net+20
+
+
+#
+# IP version 6
+#
+# name         alignment       offset          mask            shift
+ip6.version    u8              net+0           0xF0            4
+ip6.tc         u16             net+0           0xFF0           4
+ip6.flowlabel  u32             net+0           0xFFFFF
+ip6.length     u16             net+4
+ip6.nexthdr    u8              net+6
+ip6.hoplimit   u8              net+7
+ip6.src                16              net+8
+ip6.dst                16              net+24
+
+#
+# Transmission Control Protocol (TCP)
+#
+# name         alignment       offset          mask            shift
+tcp.sport      u16             tcp+0
+tcp.dport      u16             tcp+2
+tcp.seq                u32             tcp+4
+tcp.ack                u32             tcp+8
+
+# Data offset (4 bits)
+tcp.off                u8              tcp+12          0xF0            4
+
+# Reserved [0 0 0] (3 bits)
+tcp.reserved   u8              tcp+12          0x04            1
+
+# ECN [N C E] (3 bits)
+tcp.ecn                u16             tcp+12          0x01C00         6
+
+# Individual TCP flags (0|1) (6 bits in total)
+tcp.flag.urg   u8              tcp+13          0x20            5
+tcp.flag.ack   u8              tcp+13          0x10            4
+tcp.flag.psh   u8              tcp+13          0x08            3
+tcp.flag.rst   u8              tcp+13          0x04            2
+tpc.flag.syn   u8              tcp+13          0x02            1
+tcp.flag.fin   u8              tcp+13          0x01
+
+tcp.win                u16             tcp+14
+tcp.csum       u16             tcp+16
+tcp.urg                u16             tcp+18
+tcp.opts       u32             tcp+20
+
+#
+# User Datagram Protocol (UDP)
+#
+# name         alignment       offset          mask            shift
+udp.sport      u16             tcp+0
+udp.dport      u16             tcp+2
+udp.length     u16             tcp+4
+udp.csum       u16             tcp+6
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644 (file)
index 0000000..3488c52
--- /dev/null
@@ -0,0 +1,135 @@
+# -*- Makefile -*-
+
+libnlincludedir = $(includedir)/libnl@MAJ_VERSION@
+
+nobase_libnlinclude_HEADERS = \
+       netlink/fib_lookup/lookup.h \
+       netlink/fib_lookup/request.h \
+       netlink/genl/ctrl.h \
+       netlink/genl/family.h \
+       netlink/genl/genl.h \
+       netlink/genl/mngt.h \
+       netlink/netfilter/ct.h \
+       netlink/netfilter/exp.h \
+       netlink/netfilter/log.h \
+       netlink/netfilter/log_msg.h \
+       netlink/netfilter/netfilter.h \
+       netlink/netfilter/nfnl.h \
+       netlink/netfilter/queue.h \
+       netlink/netfilter/queue_msg.h \
+       netlink/addr.h \
+       netlink/attr.h \
+       netlink/cache.h \
+       netlink/data.h \
+       netlink/errno.h \
+       netlink/handlers.h \
+       netlink/hash.h \
+       netlink/hashtable.h \
+       netlink/list.h \
+       netlink/msg.h \
+       netlink/netlink-compat.h \
+       netlink/netlink-kernel.h \
+       netlink/netlink.h \
+       netlink/object.h \
+       netlink/route/cls/ematch/cmp.h \
+       netlink/route/cls/ematch/meta.h \
+       netlink/route/cls/ematch/nbyte.h \
+       netlink/route/cls/ematch/text.h \
+       netlink/route/cls/basic.h \
+       netlink/route/cls/cgroup.h \
+       netlink/route/cls/ematch.h \
+       netlink/route/cls/fw.h \
+       netlink/route/cls/police.h \
+       netlink/route/cls/u32.h \
+       netlink/route/link/bonding.h \
+       netlink/route/link/bridge.h \
+       netlink/route/link/can.h \
+       netlink/route/link/inet.h \
+       netlink/route/link/vlan.h \
+       netlink/route/qdisc/cbq.h \
+       netlink/route/qdisc/dsmark.h \
+       netlink/route/qdisc/fifo.h \
+       netlink/route/qdisc/htb.h \
+       netlink/route/qdisc/netem.h \
+       netlink/route/qdisc/prio.h \
+       netlink/route/qdisc/red.h \
+       netlink/route/qdisc/sfq.h \
+       netlink/route/qdisc/tbf.h \
+       netlink/route/qdisc/plug.h \
+       netlink/route/addr.h \
+       netlink/route/class.h \
+       netlink/route/classifier.h \
+       netlink/route/link.h \
+       netlink/route/neighbour.h \
+       netlink/route/neightbl.h \
+       netlink/route/nexthop.h \
+       netlink/route/pktloc.h \
+       netlink/route/qdisc.h \
+       netlink/route/route.h \
+       netlink/route/rtnl.h \
+       netlink/route/rule.h \
+       netlink/route/tc.h \
+       netlink/socket.h \
+       netlink/types.h \
+       netlink/utils.h \
+       netlink/version.h \
+       netlink/cache-api.h \
+       netlink/object-api.h \
+       netlink/route/link/api.h \
+       netlink/route/link/info-api.h \
+       netlink/route/tc-api.h
+
+
+if ENABLE_CLI
+nobase_libnlinclude_HEADERS += \
+       netlink/cli/addr.h \
+       netlink/cli/class.h \
+       netlink/cli/cls.h \
+       netlink/cli/ct.h \
+       netlink/cli/exp.h \
+       netlink/cli/link.h \
+       netlink/cli/neigh.h \
+       netlink/cli/qdisc.h \
+       netlink/cli/route.h \
+       netlink/cli/rule.h \
+       netlink/cli/tc.h \
+       netlink/cli/utils.h
+endif
+
+noinst_HEADERS = \
+       linux/fib_rules.h \
+       linux/genetlink.h \
+       linux/gen_stats.h \
+       linux/if_addr.h \
+       linux/if_arp.h \
+       linux/if_ether.h \
+       linux/if.h \
+       linux/if_bridge.h \
+       linux/if_link.h \
+       linux/if_vlan.h \
+       linux/inetdevice.h \
+       linux/ip_mp_alg.h \
+       linux/ipv6.h \
+       linux/can/netlink.h \
+       linux/neighbour.h \
+       linux/netfilter.h \
+       linux/netfilter/nf_conntrack_common.h \
+       linux/netfilter/nfnetlink_compat.h \
+       linux/netfilter/nfnetlink_conntrack.h \
+       linux/netfilter/nfnetlink.h \
+       linux/netfilter/nfnetlink_log.h \
+       linux/netfilter/nfnetlink_queue.h \
+       linux/netlink.h \
+       linux/pkt_cls.h \
+       linux/pkt_sched.h \
+       linux/rtnetlink.h \
+       linux/snmp.h \
+       linux/tc_ematch/tc_em_meta.h \
+       netlink-private/genl.h \
+       netlink-private/netlink.h \
+       netlink-private/tc.h \
+       netlink-private/types.h \
+       netlink-private/cache-api.h \
+       netlink-private/object-api.h \
+       netlink-private/route/link/api.h \
+       netlink-private/route/tc-api.h
diff --git a/include/Makefile.in b/include/Makefile.in
new file mode 100644 (file)
index 0000000..142c716
--- /dev/null
@@ -0,0 +1,640 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@ENABLE_CLI_TRUE@am__append_1 = \
+@ENABLE_CLI_TRUE@      netlink/cli/addr.h \
+@ENABLE_CLI_TRUE@      netlink/cli/class.h \
+@ENABLE_CLI_TRUE@      netlink/cli/cls.h \
+@ENABLE_CLI_TRUE@      netlink/cli/ct.h \
+@ENABLE_CLI_TRUE@      netlink/cli/exp.h \
+@ENABLE_CLI_TRUE@      netlink/cli/link.h \
+@ENABLE_CLI_TRUE@      netlink/cli/neigh.h \
+@ENABLE_CLI_TRUE@      netlink/cli/qdisc.h \
+@ENABLE_CLI_TRUE@      netlink/cli/route.h \
+@ENABLE_CLI_TRUE@      netlink/cli/rule.h \
+@ENABLE_CLI_TRUE@      netlink/cli/tc.h \
+@ENABLE_CLI_TRUE@      netlink/cli/utils.h
+
+subdir = include
+DIST_COMMON = $(am__nobase_libnlinclude_HEADERS_DIST) \
+       $(noinst_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__nobase_libnlinclude_HEADERS_DIST = netlink/fib_lookup/lookup.h \
+       netlink/fib_lookup/request.h netlink/genl/ctrl.h \
+       netlink/genl/family.h netlink/genl/genl.h netlink/genl/mngt.h \
+       netlink/netfilter/ct.h netlink/netfilter/exp.h \
+       netlink/netfilter/log.h netlink/netfilter/log_msg.h \
+       netlink/netfilter/netfilter.h netlink/netfilter/nfnl.h \
+       netlink/netfilter/queue.h netlink/netfilter/queue_msg.h \
+       netlink/addr.h netlink/attr.h netlink/cache.h netlink/data.h \
+       netlink/errno.h netlink/handlers.h netlink/hash.h \
+       netlink/hashtable.h netlink/list.h netlink/msg.h \
+       netlink/netlink-compat.h netlink/netlink-kernel.h \
+       netlink/netlink.h netlink/object.h \
+       netlink/route/cls/ematch/cmp.h netlink/route/cls/ematch/meta.h \
+       netlink/route/cls/ematch/nbyte.h \
+       netlink/route/cls/ematch/text.h netlink/route/cls/basic.h \
+       netlink/route/cls/cgroup.h netlink/route/cls/ematch.h \
+       netlink/route/cls/fw.h netlink/route/cls/police.h \
+       netlink/route/cls/u32.h netlink/route/link/bonding.h \
+       netlink/route/link/bridge.h netlink/route/link/can.h \
+       netlink/route/link/inet.h netlink/route/link/vlan.h \
+       netlink/route/qdisc/cbq.h netlink/route/qdisc/dsmark.h \
+       netlink/route/qdisc/fifo.h netlink/route/qdisc/htb.h \
+       netlink/route/qdisc/netem.h netlink/route/qdisc/prio.h \
+       netlink/route/qdisc/red.h netlink/route/qdisc/sfq.h \
+       netlink/route/qdisc/tbf.h netlink/route/qdisc/plug.h \
+       netlink/route/addr.h netlink/route/class.h \
+       netlink/route/classifier.h netlink/route/link.h \
+       netlink/route/neighbour.h netlink/route/neightbl.h \
+       netlink/route/nexthop.h netlink/route/pktloc.h \
+       netlink/route/qdisc.h netlink/route/route.h \
+       netlink/route/rtnl.h netlink/route/rule.h netlink/route/tc.h \
+       netlink/socket.h netlink/types.h netlink/utils.h \
+       netlink/version.h netlink/cache-api.h netlink/object-api.h \
+       netlink/route/link/api.h netlink/route/link/info-api.h \
+       netlink/route/tc-api.h netlink/cli/addr.h netlink/cli/class.h \
+       netlink/cli/cls.h netlink/cli/ct.h netlink/cli/exp.h \
+       netlink/cli/link.h netlink/cli/neigh.h netlink/cli/qdisc.h \
+       netlink/cli/route.h netlink/cli/rule.h netlink/cli/tc.h \
+       netlink/cli/utils.h
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libnlincludedir)"
+HEADERS = $(nobase_libnlinclude_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+libnlincludedir = $(includedir)/libnl@MAJ_VERSION@
+nobase_libnlinclude_HEADERS = netlink/fib_lookup/lookup.h \
+       netlink/fib_lookup/request.h netlink/genl/ctrl.h \
+       netlink/genl/family.h netlink/genl/genl.h netlink/genl/mngt.h \
+       netlink/netfilter/ct.h netlink/netfilter/exp.h \
+       netlink/netfilter/log.h netlink/netfilter/log_msg.h \
+       netlink/netfilter/netfilter.h netlink/netfilter/nfnl.h \
+       netlink/netfilter/queue.h netlink/netfilter/queue_msg.h \
+       netlink/addr.h netlink/attr.h netlink/cache.h netlink/data.h \
+       netlink/errno.h netlink/handlers.h netlink/hash.h \
+       netlink/hashtable.h netlink/list.h netlink/msg.h \
+       netlink/netlink-compat.h netlink/netlink-kernel.h \
+       netlink/netlink.h netlink/object.h \
+       netlink/route/cls/ematch/cmp.h netlink/route/cls/ematch/meta.h \
+       netlink/route/cls/ematch/nbyte.h \
+       netlink/route/cls/ematch/text.h netlink/route/cls/basic.h \
+       netlink/route/cls/cgroup.h netlink/route/cls/ematch.h \
+       netlink/route/cls/fw.h netlink/route/cls/police.h \
+       netlink/route/cls/u32.h netlink/route/link/bonding.h \
+       netlink/route/link/bridge.h netlink/route/link/can.h \
+       netlink/route/link/inet.h netlink/route/link/vlan.h \
+       netlink/route/qdisc/cbq.h netlink/route/qdisc/dsmark.h \
+       netlink/route/qdisc/fifo.h netlink/route/qdisc/htb.h \
+       netlink/route/qdisc/netem.h netlink/route/qdisc/prio.h \
+       netlink/route/qdisc/red.h netlink/route/qdisc/sfq.h \
+       netlink/route/qdisc/tbf.h netlink/route/qdisc/plug.h \
+       netlink/route/addr.h netlink/route/class.h \
+       netlink/route/classifier.h netlink/route/link.h \
+       netlink/route/neighbour.h netlink/route/neightbl.h \
+       netlink/route/nexthop.h netlink/route/pktloc.h \
+       netlink/route/qdisc.h netlink/route/route.h \
+       netlink/route/rtnl.h netlink/route/rule.h netlink/route/tc.h \
+       netlink/socket.h netlink/types.h netlink/utils.h \
+       netlink/version.h netlink/cache-api.h netlink/object-api.h \
+       netlink/route/link/api.h netlink/route/link/info-api.h \
+       netlink/route/tc-api.h $(am__append_1)
+noinst_HEADERS = \
+       linux/fib_rules.h \
+       linux/genetlink.h \
+       linux/gen_stats.h \
+       linux/if_addr.h \
+       linux/if_arp.h \
+       linux/if_ether.h \
+       linux/if.h \
+       linux/if_bridge.h \
+       linux/if_link.h \
+       linux/if_vlan.h \
+       linux/inetdevice.h \
+       linux/ip_mp_alg.h \
+       linux/ipv6.h \
+       linux/can/netlink.h \
+       linux/neighbour.h \
+       linux/netfilter.h \
+       linux/netfilter/nf_conntrack_common.h \
+       linux/netfilter/nfnetlink_compat.h \
+       linux/netfilter/nfnetlink_conntrack.h \
+       linux/netfilter/nfnetlink.h \
+       linux/netfilter/nfnetlink_log.h \
+       linux/netfilter/nfnetlink_queue.h \
+       linux/netlink.h \
+       linux/pkt_cls.h \
+       linux/pkt_sched.h \
+       linux/rtnetlink.h \
+       linux/snmp.h \
+       linux/tc_ematch/tc_em_meta.h \
+       netlink-private/genl.h \
+       netlink-private/netlink.h \
+       netlink-private/tc.h \
+       netlink-private/types.h \
+       netlink-private/cache-api.h \
+       netlink-private/object-api.h \
+       netlink-private/route/link/api.h \
+       netlink-private/route/tc-api.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign include/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+install-nobase_libnlincludeHEADERS: $(nobase_libnlinclude_HEADERS)
+       @$(NORMAL_INSTALL)
+       @list='$(nobase_libnlinclude_HEADERS)'; test -n "$(libnlincludedir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(libnlincludedir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(libnlincludedir)" || exit 1; \
+       fi; \
+       $(am__nobase_list) | while read dir files; do \
+         xfiles=; for file in $$files; do \
+           if test -f "$$file"; then xfiles="$$xfiles $$file"; \
+           else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
+         test -z "$$xfiles" || { \
+           test "x$$dir" = x. || { \
+             echo " $(MKDIR_P) '$(DESTDIR)$(libnlincludedir)/$$dir'"; \
+             $(MKDIR_P) "$(DESTDIR)$(libnlincludedir)/$$dir"; }; \
+           echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(libnlincludedir)/$$dir'"; \
+           $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(libnlincludedir)/$$dir" || exit $$?; }; \
+       done
+
+uninstall-nobase_libnlincludeHEADERS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(nobase_libnlinclude_HEADERS)'; test -n "$(libnlincludedir)" || list=; \
+       $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+       dir='$(DESTDIR)$(libnlincludedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+       for dir in "$(DESTDIR)$(libnlincludedir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_libnlincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-nobase_libnlincludeHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-libtool ctags distclean distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-nobase_libnlincludeHEADERS \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am \
+       uninstall-nobase_libnlincludeHEADERS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/linux/can/netlink.h b/include/linux/can/netlink.h
new file mode 100644 (file)
index 0000000..14966dd
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * linux/can/netlink.h
+ *
+ * Definitions for the CAN netlink interface
+ *
+ * Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ */
+
+#ifndef CAN_NETLINK_H
+#define CAN_NETLINK_H
+
+#include <linux/types.h>
+
+/*
+ * CAN bit-timing parameters
+ *
+ * For further information, please read chapter "8 BIT TIMING
+ * REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
+ * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
+ */
+struct can_bittiming {
+       __u32 bitrate;          /* Bit-rate in bits/second */
+       __u32 sample_point;     /* Sample point in one-tenth of a percent */
+       __u32 tq;               /* Time quanta (TQ) in nanoseconds */
+       __u32 prop_seg;         /* Propagation segment in TQs */
+       __u32 phase_seg1;       /* Phase buffer segment 1 in TQs */
+       __u32 phase_seg2;       /* Phase buffer segment 2 in TQs */
+       __u32 sjw;              /* Synchronisation jump width in TQs */
+       __u32 brp;              /* Bit-rate prescaler */
+};
+
+/*
+ * CAN harware-dependent bit-timing constant
+ *
+ * Used for calculating and checking bit-timing parameters
+ */
+struct can_bittiming_const {
+       char name[16];          /* Name of the CAN controller hardware */
+       __u32 tseg1_min;        /* Time segement 1 = prop_seg + phase_seg1 */
+       __u32 tseg1_max;
+       __u32 tseg2_min;        /* Time segement 2 = phase_seg2 */
+       __u32 tseg2_max;
+       __u32 sjw_max;          /* Synchronisation jump width */
+       __u32 brp_min;          /* Bit-rate prescaler */
+       __u32 brp_max;
+       __u32 brp_inc;
+};
+
+/*
+ * CAN clock parameters
+ */
+struct can_clock {
+       __u32 freq;             /* CAN system clock frequency in Hz */
+};
+
+/*
+ * CAN operational and error states
+ */
+enum can_state {
+       CAN_STATE_ERROR_ACTIVE = 0,     /* RX/TX error count < 96 */
+       CAN_STATE_ERROR_WARNING,        /* RX/TX error count < 128 */
+       CAN_STATE_ERROR_PASSIVE,        /* RX/TX error count < 256 */
+       CAN_STATE_BUS_OFF,              /* RX/TX error count >= 256 */
+       CAN_STATE_STOPPED,              /* Device is stopped */
+       CAN_STATE_SLEEPING,             /* Device is sleeping */
+       CAN_STATE_MAX
+};
+
+/*
+ * CAN bus error counters
+ */
+struct can_berr_counter {
+       __u16 txerr;
+       __u16 rxerr;
+};
+
+/*
+ * CAN controller mode
+ */
+struct can_ctrlmode {
+       __u32 mask;
+       __u32 flags;
+};
+
+#define CAN_CTRLMODE_LOOPBACK          0x01    /* Loopback mode */
+#define CAN_CTRLMODE_LISTENONLY                0x02    /* Listen-only mode */
+#define CAN_CTRLMODE_3_SAMPLES         0x04    /* Triple sampling mode */
+#define CAN_CTRLMODE_ONE_SHOT          0x08    /* One-Shot mode */
+#define CAN_CTRLMODE_BERR_REPORTING    0x10    /* Bus-error reporting */
+
+/*
+ * CAN device statistics
+ */
+struct can_device_stats {
+       __u32 bus_error;        /* Bus errors */
+       __u32 error_warning;    /* Changes to error warning state */
+       __u32 error_passive;    /* Changes to error passive state */
+       __u32 bus_off;          /* Changes to bus off state */
+       __u32 arbitration_lost; /* Arbitration lost errors */
+       __u32 restarts;         /* CAN controller re-starts */
+};
+
+/*
+ * CAN netlink interface
+ */
+enum {
+       IFLA_CAN_UNSPEC,
+       IFLA_CAN_BITTIMING,
+       IFLA_CAN_BITTIMING_CONST,
+       IFLA_CAN_CLOCK,
+       IFLA_CAN_STATE,
+       IFLA_CAN_CTRLMODE,
+       IFLA_CAN_RESTART_MS,
+       IFLA_CAN_RESTART,
+       IFLA_CAN_BERR_COUNTER,
+       __IFLA_CAN_MAX
+};
+
+#define IFLA_CAN_MAX   (__IFLA_CAN_MAX - 1)
+
+#endif /* CAN_NETLINK_H */
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
new file mode 100644 (file)
index 0000000..ed4504a
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __LINUX_FIB_RULES_H
+#define __LINUX_FIB_RULES_H
+
+/* rule is permanent, and cannot be deleted */
+#define FIB_RULE_PERMANENT     0x00000001
+#define FIB_RULE_INVERT                0x00000002
+#define FIB_RULE_UNRESOLVED    0x00000004
+#define FIB_RULE_IIF_DETACHED  0x00000008
+#define FIB_RULE_DEV_DETACHED  FIB_RULE_IIF_DETACHED
+#define FIB_RULE_OIF_DETACHED  0x00000010
+
+/* try to find source address in routing lookups */
+#define FIB_RULE_FIND_SADDR    0x00010000
+
+struct fib_rule_hdr {
+       __u8            family;
+       __u8            dst_len;
+       __u8            src_len;
+       __u8            tos;
+
+       __u8            table;
+       __u8            res1;   /* reserved */
+       __u8            res2;   /* reserved */
+       __u8            action;
+
+       __u32           flags;
+};
+
+enum {
+       FRA_UNSPEC,
+       FRA_DST,        /* destination address */
+       FRA_SRC,        /* source address */
+       FRA_IIFNAME,    /* interface name */
+#define FRA_IFNAME     FRA_IIFNAME
+       FRA_GOTO,       /* target to jump to (FR_ACT_GOTO) */
+       FRA_UNUSED2,
+       FRA_PRIORITY,   /* priority/preference */
+       FRA_UNUSED3,
+       FRA_UNUSED4,
+       FRA_UNUSED5,
+       FRA_FWMARK,     /* mark */
+       FRA_FLOW,       /* flow/class id */
+       FRA_UNUSED6,
+       FRA_UNUSED7,
+       FRA_UNUSED8,
+       FRA_TABLE,      /* Extended table id */
+       FRA_FWMASK,     /* mask for netfilter mark */
+       FRA_OIFNAME,
+       __FRA_MAX
+};
+
+#define FRA_MAX (__FRA_MAX - 1)
+
+enum {
+       FR_ACT_UNSPEC,
+       FR_ACT_TO_TBL,          /* Pass to fixed table */
+       FR_ACT_GOTO,            /* Jump to another rule */
+       FR_ACT_NOP,             /* No operation */
+       FR_ACT_RES3,
+       FR_ACT_RES4,
+       FR_ACT_BLACKHOLE,       /* Drop without notification */
+       FR_ACT_UNREACHABLE,     /* Drop with ENETUNREACH */
+       FR_ACT_PROHIBIT,        /* Drop with EACCES */
+       __FR_ACT_MAX,
+};
+
+#define FR_ACT_MAX (__FR_ACT_MAX - 1)
+
+#endif
diff --git a/include/linux/gen_stats.h b/include/linux/gen_stats.h
new file mode 100644 (file)
index 0000000..552c8a0
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __LINUX_GEN_STATS_H
+#define __LINUX_GEN_STATS_H
+
+#include <linux/types.h>
+
+enum {
+       TCA_STATS_UNSPEC,
+       TCA_STATS_BASIC,
+       TCA_STATS_RATE_EST,
+       TCA_STATS_QUEUE,
+       TCA_STATS_APP,
+       __TCA_STATS_MAX,
+};
+#define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
+
+/**
+ * struct gnet_stats_basic - byte/packet throughput statistics
+ * @bytes: number of seen bytes
+ * @packets: number of seen packets
+ */
+struct gnet_stats_basic {
+       __u64   bytes;
+       __u32   packets;
+};
+struct gnet_stats_basic_packed {
+       __u64   bytes;
+       __u32   packets;
+} __attribute__ ((packed));
+
+/**
+ * struct gnet_stats_rate_est - rate estimator
+ * @bps: current byte rate
+ * @pps: current packet rate
+ */
+struct gnet_stats_rate_est {
+       __u32   bps;
+       __u32   pps;
+};
+
+/**
+ * struct gnet_stats_queue - queuing statistics
+ * @qlen: queue length
+ * @backlog: backlog size of queue
+ * @drops: number of dropped packets
+ * @requeues: number of requeues
+ * @overlimits: number of enqueues over the limit
+ */
+struct gnet_stats_queue {
+       __u32   qlen;
+       __u32   backlog;
+       __u32   drops;
+       __u32   requeues;
+       __u32   overlimits;
+};
+
+/**
+ * struct gnet_estimator - rate estimator configuration
+ * @interval: sampling period
+ * @ewma_log: the log of measurement window weight
+ */
+struct gnet_estimator {
+       signed char     interval;
+       unsigned char   ewma_log;
+};
+
+
+#endif /* __LINUX_GEN_STATS_H */
diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h
new file mode 100644 (file)
index 0000000..b834ef6
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __LINUX_GENERIC_NETLINK_H
+#define __LINUX_GENERIC_NETLINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+#define GENL_NAMSIZ    16      /* length of family name */
+
+#define GENL_MIN_ID    NLMSG_MIN_TYPE
+#define GENL_MAX_ID    1023
+
+struct genlmsghdr {
+       __u8    cmd;
+       __u8    version;
+       __u16   reserved;
+};
+
+#define GENL_HDRLEN    NLMSG_ALIGN(sizeof(struct genlmsghdr))
+
+#define GENL_ADMIN_PERM                0x01
+#define GENL_CMD_CAP_DO                0x02
+#define GENL_CMD_CAP_DUMP      0x04
+#define GENL_CMD_CAP_HASPOL    0x08
+
+/*
+ * List of reserved static generic netlink identifiers:
+ */
+#define GENL_ID_GENERATE       0
+#define GENL_ID_CTRL           NLMSG_MIN_TYPE
+
+/**************************************************************************
+ * Controller
+ **************************************************************************/
+
+enum {
+       CTRL_CMD_UNSPEC,
+       CTRL_CMD_NEWFAMILY,
+       CTRL_CMD_DELFAMILY,
+       CTRL_CMD_GETFAMILY,
+       CTRL_CMD_NEWOPS,
+       CTRL_CMD_DELOPS,
+       CTRL_CMD_GETOPS,
+       CTRL_CMD_NEWMCAST_GRP,
+       CTRL_CMD_DELMCAST_GRP,
+       CTRL_CMD_GETMCAST_GRP, /* unused */
+       __CTRL_CMD_MAX,
+};
+
+#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1)
+
+enum {
+       CTRL_ATTR_UNSPEC,
+       CTRL_ATTR_FAMILY_ID,
+       CTRL_ATTR_FAMILY_NAME,
+       CTRL_ATTR_VERSION,
+       CTRL_ATTR_HDRSIZE,
+       CTRL_ATTR_MAXATTR,
+       CTRL_ATTR_OPS,
+       CTRL_ATTR_MCAST_GROUPS,
+       __CTRL_ATTR_MAX,
+};
+
+#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1)
+
+enum {
+       CTRL_ATTR_OP_UNSPEC,
+       CTRL_ATTR_OP_ID,
+       CTRL_ATTR_OP_FLAGS,
+       __CTRL_ATTR_OP_MAX,
+};
+
+#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
+
+enum {
+       CTRL_ATTR_MCAST_GRP_UNSPEC,
+       CTRL_ATTR_MCAST_GRP_NAME,
+       CTRL_ATTR_MCAST_GRP_ID,
+       __CTRL_ATTR_MCAST_GRP_MAX,
+};
+
+#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
+
+#endif /* __LINUX_GENERIC_NETLINK_H */
diff --git a/include/linux/if.h b/include/linux/if.h
new file mode 100644 (file)
index 0000000..238cf43
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Global definitions for the INET interface module.
+ *
+ * Version:    @(#)if.h        1.0.2   04/18/93
+ *
+ * Authors:    Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
+ *             Ross Biro
+ *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_H
+#define _LINUX_IF_H
+
+#define        IFNAMSIZ        16
+#define        IFALIASZ        256
+
+/* Standard interface flags (netdevice->flags). */
+#define        IFF_UP          0x1             /* interface is up              */
+#define        IFF_BROADCAST   0x2             /* broadcast address valid      */
+#define        IFF_DEBUG       0x4             /* turn on debugging            */
+#define        IFF_LOOPBACK    0x8             /* is a loopback net            */
+#define        IFF_POINTOPOINT 0x10            /* interface is has p-p link    */
+#define        IFF_NOTRAILERS  0x20            /* avoid use of trailers        */
+#define        IFF_RUNNING     0x40            /* interface RFC2863 OPER_UP    */
+#define        IFF_NOARP       0x80            /* no ARP protocol              */
+#define        IFF_PROMISC     0x100           /* receive all packets          */
+#define        IFF_ALLMULTI    0x200           /* receive all multicast packets*/
+
+#define IFF_MASTER     0x400           /* master of a load balancer    */
+#define IFF_SLAVE      0x800           /* slave of a load balancer     */
+
+#define IFF_MULTICAST  0x1000          /* Supports multicast           */
+
+#define IFF_PORTSEL    0x2000          /* can set media type           */
+#define IFF_AUTOMEDIA  0x4000          /* auto media select active     */
+#define IFF_DYNAMIC    0x8000          /* dialup device with changing addresses*/
+
+#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
+#define IFF_DORMANT    0x20000         /* driver signals dormant       */
+
+#define IFF_ECHO       0x40000         /* echo sent packets            */
+
+#define IFF_VOLATILE   (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
+               IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
+/* Private (from user) interface flags (netdevice->priv_flags). */
+#define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
+#define IFF_EBRIDGE    0x2             /* Ethernet bridging device.    */
+#define IFF_SLAVE_INACTIVE     0x4     /* bonding slave not the curr. active */
+#define IFF_MASTER_8023AD      0x8     /* bonding master, 802.3ad.     */
+#define IFF_MASTER_ALB 0x10            /* bonding master, balance-alb. */
+#define IFF_BONDING    0x20            /* bonding master or slave      */
+#define IFF_SLAVE_NEEDARP 0x40         /* need ARPs for validation     */
+#define IFF_ISATAP     0x80            /* ISATAP interface (RFC4214)   */
+#define IFF_MASTER_ARPMON 0x100                /* bonding master, ARP mon in use */
+#define IFF_WAN_HDLC   0x200           /* WAN HDLC device              */
+#define IFF_XMIT_DST_RELEASE 0x400     /* dev_hard_start_xmit() is allowed to
+                                        * release skb->dst
+                                        */
+#define IFF_DONT_BRIDGE 0x800          /* disallow bridging this ether dev */
+#define IFF_IN_NETPOLL 0x1000          /* whether we are processing netpoll */
+#define IFF_DISABLE_NETPOLL    0x2000  /* disable netpoll at run-time */
+#define IFF_MACVLAN_PORT       0x4000  /* device used as macvlan port */
+#define IFF_BRIDGE_PORT        0x8000          /* device used as bridge port */
+#define IFF_OVS_DATAPATH       0x10000 /* device used as Open vSwitch
+                                        * datapath port */
+
+#define IF_GET_IFACE   0x0001          /* for querying only */
+#define IF_GET_PROTO   0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35   0x1000          /* V.35 serial interface        */
+#define IF_IFACE_V24   0x1001          /* V.24 serial interface        */
+#define IF_IFACE_X21   0x1002          /* X.21 serial interface        */
+#define IF_IFACE_T1    0x1003          /* T1 telco serial interface    */
+#define IF_IFACE_E1    0x1004          /* E1 telco serial interface    */
+#define IF_IFACE_SYNC_SERIAL 0x1005    /* can't be set by software     */
+#define IF_IFACE_X21D   0x1006          /* X.21 Dual Clocking (FarSite) */
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC  0x2000          /* raw HDLC protocol            */
+#define IF_PROTO_PPP   0x2001          /* PPP protocol                 */
+#define IF_PROTO_CISCO 0x2002          /* Cisco HDLC protocol          */
+#define IF_PROTO_FR    0x2003          /* Frame Relay protocol         */
+#define IF_PROTO_FR_ADD_PVC 0x2004     /*    Create FR PVC             */
+#define IF_PROTO_FR_DEL_PVC 0x2005     /*    Delete FR PVC             */
+#define IF_PROTO_X25   0x2006          /* X.25                         */
+#define IF_PROTO_HDLC_ETH 0x2007       /* raw HDLC, Ethernet emulation */
+#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /*  Create FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /*  Delete FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_PVC        0x200A          /* for reading PVC status       */
+#define IF_PROTO_FR_ETH_PVC 0x200B
+#define IF_PROTO_RAW    0x200C          /* RAW Socket                   */
+
+/* RFC 2863 operational status */
+enum {
+       IF_OPER_UNKNOWN,
+       IF_OPER_NOTPRESENT,
+       IF_OPER_DOWN,
+       IF_OPER_LOWERLAYERDOWN,
+       IF_OPER_TESTING,
+       IF_OPER_DORMANT,
+       IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+       IF_LINK_MODE_DEFAULT,
+       IF_LINK_MODE_DORMANT,   /* limit upward transition to dormant */
+};
+
+/* carrier state */
+enum {
+       IF_CARRIER_DOWN,
+       IF_CARRIER_UP
+};
+
+/*
+ *     Device mapping structure. I'd just gone off and designed a 
+ *     beautiful scheme using only loadable modules with arguments
+ *     for driver options and along come the PCMCIA people 8)
+ *
+ *     Ah well. The get() side of this is good for WDSETUP, and it'll
+ *     be handy for debugging things. The set side is fine for now and
+ *     being very small might be worth keeping for clean configuration.
+ */
+
+struct ifmap {
+       unsigned long mem_start;
+       unsigned long mem_end;
+       unsigned short base_addr; 
+       unsigned char irq;
+       unsigned char dma;
+       unsigned char port;
+       /* 3 bytes spare */
+};
+
+#endif /* _LINUX_IF_H */
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
new file mode 100644 (file)
index 0000000..c355522
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ifaddrmsg {
+       __u8            ifa_family;
+       __u8            ifa_prefixlen;  /* The prefix length            */
+       __u8            ifa_flags;      /* Flags                        */
+       __u8            ifa_scope;      /* Address scope                */
+       __u32           ifa_index;      /* Link index                   */
+};
+
+/*
+ * Important comment:
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ */
+enum {
+       IFA_UNSPEC,
+       IFA_ADDRESS,
+       IFA_LOCAL,
+       IFA_LABEL,
+       IFA_BROADCAST,
+       IFA_ANYCAST,
+       IFA_CACHEINFO,
+       IFA_MULTICAST,
+       __IFA_MAX,
+};
+
+#define IFA_MAX (__IFA_MAX - 1)
+
+/* ifa_flags */
+#define IFA_F_SECONDARY                0x01
+#define IFA_F_TEMPORARY                IFA_F_SECONDARY
+
+#define        IFA_F_NODAD             0x02
+#define IFA_F_OPTIMISTIC       0x04
+#define IFA_F_DADFAILED                0x08
+#define        IFA_F_HOMEADDRESS       0x10
+#define IFA_F_DEPRECATED       0x20
+#define IFA_F_TENTATIVE                0x40
+#define IFA_F_PERMANENT                0x80
+
+struct ifa_cacheinfo {
+       __u32   ifa_prefered;
+       __u32   ifa_valid;
+       __u32   cstamp; /* created timestamp, hundredths of seconds */
+       __u32   tstamp; /* updated timestamp, hundredths of seconds */
+};
+
+#endif
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
new file mode 100644 (file)
index 0000000..e04cd2c
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Global definitions for the ARP (RFC 826) protocol.
+ *
+ * Version:    @(#)if_arp.h    1.0.1   04/16/93
+ *
+ * Authors:    Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ *             Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
+ *             Ross Biro
+ *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *             Florian La Roche,
+ *             Jonathan Layes <layes@loran.com>
+ *             Arnaldo Carvalho de Melo <acme@conectiva.com.br> ARPHRD_HWX25
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_ARP_H
+#define _LINUX_IF_ARP_H
+
+#include <linux/netdevice.h>
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM  0               /* from KA9Q: NET/ROM pseudo    */
+#define ARPHRD_ETHER   1               /* Ethernet 10Mbps              */
+#define        ARPHRD_EETHER   2               /* Experimental Ethernet        */
+#define        ARPHRD_AX25     3               /* AX.25 Level 2                */
+#define        ARPHRD_PRONET   4               /* PROnet token ring            */
+#define        ARPHRD_CHAOS    5               /* Chaosnet                     */
+#define        ARPHRD_IEEE802  6               /* IEEE 802.2 Ethernet/TR/TB    */
+#define        ARPHRD_ARCNET   7               /* ARCnet                       */
+#define        ARPHRD_APPLETLK 8               /* APPLEtalk                    */
+#define ARPHRD_DLCI    15              /* Frame Relay DLCI             */
+#define ARPHRD_ATM     19              /* ATM                          */
+#define ARPHRD_METRICOM        23              /* Metricom STRIP (new IANA id) */
+#define        ARPHRD_IEEE1394 24              /* IEEE 1394 IPv4 - RFC 2734    */
+#define ARPHRD_EUI64   27              /* EUI-64                       */
+#define ARPHRD_INFINIBAND 32           /* InfiniBand                   */
+
+/* Dummy types for non ARP hardware */
+#define ARPHRD_SLIP    256
+#define ARPHRD_CSLIP   257
+#define ARPHRD_SLIP6   258
+#define ARPHRD_CSLIP6  259
+#define ARPHRD_RSRVD   260             /* Notional KISS type           */
+#define ARPHRD_ADAPT   264
+#define ARPHRD_ROSE    270
+#define ARPHRD_X25     271             /* CCITT X.25                   */
+#define ARPHRD_HWX25   272             /* Boards with X.25 in firmware */
+#define ARPHRD_CAN     280             /* Controller Area Network      */
+#define ARPHRD_PPP     512
+#define ARPHRD_CISCO   513             /* Cisco HDLC                   */
+#define ARPHRD_HDLC    ARPHRD_CISCO
+#define ARPHRD_LAPB    516             /* LAPB                         */
+#define ARPHRD_DDCMP    517            /* Digital's DDCMP protocol     */
+#define ARPHRD_RAWHDLC 518             /* Raw HDLC                     */
+
+#define ARPHRD_TUNNEL  768             /* IPIP tunnel                  */
+#define ARPHRD_TUNNEL6 769             /* IP6IP6 tunnel                */
+#define ARPHRD_FRAD    770             /* Frame Relay Access Device    */
+#define ARPHRD_SKIP    771             /* SKIP vif                     */
+#define ARPHRD_LOOPBACK        772             /* Loopback device              */
+#define ARPHRD_LOCALTLK 773            /* Localtalk device             */
+#define ARPHRD_FDDI    774             /* Fiber Distributed Data Interface */
+#define ARPHRD_BIF      775             /* AP1000 BIF                   */
+#define ARPHRD_SIT     776             /* sit0 device - IPv6-in-IPv4   */
+#define ARPHRD_IPDDP   777             /* IP over DDP tunneller        */
+#define ARPHRD_IPGRE   778             /* GRE over IP                  */
+#define ARPHRD_PIMREG  779             /* PIMSM register interface     */
+#define ARPHRD_HIPPI   780             /* High Performance Parallel Interface */
+#define ARPHRD_ASH     781             /* Nexus 64Mbps Ash             */
+#define ARPHRD_ECONET  782             /* Acorn Econet                 */
+#define ARPHRD_IRDA    783             /* Linux-IrDA                   */
+/* ARP works differently on different FC media .. so  */
+#define ARPHRD_FCPP    784             /* Point to point fibrechannel  */
+#define ARPHRD_FCAL    785             /* Fibrechannel arbitrated loop */
+#define ARPHRD_FCPL    786             /* Fibrechannel public loop     */
+#define ARPHRD_FCFABRIC        787             /* Fibrechannel fabric          */
+       /* 787->799 reserved for fibrechannel media types */
+#define ARPHRD_IEEE802_TR 800          /* Magic type ident for TR      */
+#define ARPHRD_IEEE80211 801           /* IEEE 802.11                  */
+#define ARPHRD_IEEE80211_PRISM 802     /* IEEE 802.11 + Prism2 header  */
+#define ARPHRD_IEEE80211_RADIOTAP 803  /* IEEE 802.11 + radiotap header */
+#define ARPHRD_IEEE802154        804
+
+#define ARPHRD_PHONET  820             /* PhoNet media type            */
+#define ARPHRD_PHONET_PIPE 821         /* PhoNet pipe header           */
+#define ARPHRD_CAIF    822             /* CAIF media type              */
+
+#define ARPHRD_VOID      0xFFFF        /* Void type, nothing is known */
+#define ARPHRD_NONE      0xFFFE        /* zero header length */
+
+/* ARP protocol opcodes. */
+#define        ARPOP_REQUEST   1               /* ARP request                  */
+#define        ARPOP_REPLY     2               /* ARP reply                    */
+#define        ARPOP_RREQUEST  3               /* RARP request                 */
+#define        ARPOP_RREPLY    4               /* RARP reply                   */
+#define        ARPOP_InREQUEST 8               /* InARP request                */
+#define        ARPOP_InREPLY   9               /* InARP reply                  */
+#define        ARPOP_NAK       10              /* (ATM)ARP NAK                 */
+
+
+/* ARP ioctl request. */
+struct arpreq {
+  struct sockaddr      arp_pa;         /* protocol address             */
+  struct sockaddr      arp_ha;         /* hardware address             */
+  int                  arp_flags;      /* flags                        */
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
+  char                 arp_dev[16];
+};
+
+struct arpreq_old {
+  struct sockaddr      arp_pa;         /* protocol address             */
+  struct sockaddr      arp_ha;         /* hardware address             */
+  int                  arp_flags;      /* flags                        */
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
+};
+
+/* ARP Flag values. */
+#define ATF_COM                0x02            /* completed entry (ha valid)   */
+#define        ATF_PERM        0x04            /* permanent entry              */
+#define        ATF_PUBL        0x08            /* publish entry                */
+#define        ATF_USETRAILERS 0x10            /* has requested trailers       */
+#define ATF_NETMASK     0x20            /* want to use a netmask (only
+                                          for proxy entries) */
+#define ATF_DONTPUB    0x40            /* don't answer this addresses  */
+
+/*
+ *     This structure defines an ethernet arp header.
+ */
+
+struct arphdr {
+       __be16          ar_hrd;         /* format of hardware address   */
+       __be16          ar_pro;         /* format of protocol address   */
+       unsigned char   ar_hln;         /* length of hardware address   */
+       unsigned char   ar_pln;         /* length of protocol address   */
+       __be16          ar_op;          /* ARP opcode (command)         */
+
+#if 0
+        /*
+         *      Ethernet looks like this : This bit is variable sized however...
+         */
+       unsigned char           ar_sha[ETH_ALEN];       /* sender hardware address      */
+       unsigned char           ar_sip[4];              /* sender IP address            */
+       unsigned char           ar_tha[ETH_ALEN];       /* target hardware address      */
+       unsigned char           ar_tip[4];              /* target IP address            */
+#endif
+
+};
+
+#endif /* _LINUX_IF_ARP_H */
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
new file mode 100644 (file)
index 0000000..5db2975
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *     Linux ethernet bridge
+ *
+ *     Authors:
+ *     Lennert Buytenhek               <buytenh@gnu.org>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_IF_BRIDGE_H
+#define _UAPI_LINUX_IF_BRIDGE_H
+
+#include <linux/types.h>
+
+#define SYSFS_BRIDGE_ATTR      "bridge"
+#define SYSFS_BRIDGE_FDB       "brforward"
+#define SYSFS_BRIDGE_PORT_SUBDIR "brif"
+#define SYSFS_BRIDGE_PORT_ATTR "brport"
+#define SYSFS_BRIDGE_PORT_LINK "bridge"
+
+#define BRCTL_VERSION 1
+
+#define BRCTL_GET_VERSION 0
+#define BRCTL_GET_BRIDGES 1
+#define BRCTL_ADD_BRIDGE 2
+#define BRCTL_DEL_BRIDGE 3
+#define BRCTL_ADD_IF 4
+#define BRCTL_DEL_IF 5
+#define BRCTL_GET_BRIDGE_INFO 6
+#define BRCTL_GET_PORT_LIST 7
+#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
+#define BRCTL_SET_BRIDGE_HELLO_TIME 9
+#define BRCTL_SET_BRIDGE_MAX_AGE 10
+#define BRCTL_SET_AGEING_TIME 11
+#define BRCTL_SET_GC_INTERVAL 12
+#define BRCTL_GET_PORT_INFO 13
+#define BRCTL_SET_BRIDGE_STP_STATE 14
+#define BRCTL_SET_BRIDGE_PRIORITY 15
+#define BRCTL_SET_PORT_PRIORITY 16
+#define BRCTL_SET_PATH_COST 17
+#define BRCTL_GET_FDB_ENTRIES 18
+
+#define BR_STATE_DISABLED 0
+#define BR_STATE_LISTENING 1
+#define BR_STATE_LEARNING 2
+#define BR_STATE_FORWARDING 3
+#define BR_STATE_BLOCKING 4
+
+struct __bridge_info {
+       __u64 designated_root;
+       __u64 bridge_id;
+       __u32 root_path_cost;
+       __u32 max_age;
+       __u32 hello_time;
+       __u32 forward_delay;
+       __u32 bridge_max_age;
+       __u32 bridge_hello_time;
+       __u32 bridge_forward_delay;
+       __u8 topology_change;
+       __u8 topology_change_detected;
+       __u8 root_port;
+       __u8 stp_enabled;
+       __u32 ageing_time;
+       __u32 gc_interval;
+       __u32 hello_timer_value;
+       __u32 tcn_timer_value;
+       __u32 topology_change_timer_value;
+       __u32 gc_timer_value;
+};
+
+struct __port_info {
+       __u64 designated_root;
+       __u64 designated_bridge;
+       __u16 port_id;
+       __u16 designated_port;
+       __u32 path_cost;
+       __u32 designated_cost;
+       __u8 state;
+       __u8 top_change_ack;
+       __u8 config_pending;
+       __u8 unused0;
+       __u32 message_age_timer_value;
+       __u32 forward_delay_timer_value;
+       __u32 hold_timer_value;
+};
+
+struct __fdb_entry {
+       __u8 mac_addr[6];
+       __u8 port_no;
+       __u8 is_local;
+       __u32 ageing_timer_value;
+       __u8 port_hi;
+       __u8 pad0;
+       __u16 unused;
+};
+
+/* Bridge Flags */
+#define BRIDGE_FLAGS_MASTER    1       /* Bridge command to/from master */
+#define BRIDGE_FLAGS_SELF      2       /* Bridge command to/from lowerdev */
+
+#define BRIDGE_MODE_VEB                0       /* Default loopback mode */
+#define BRIDGE_MODE_VEPA       1       /* 802.1Qbg defined VEPA mode */
+
+/* Bridge management nested attributes
+ * [IFLA_AF_SPEC] = {
+ *     [IFLA_BRIDGE_FLAGS]
+ *     [IFLA_BRIDGE_MODE]
+ * }
+ */
+enum {
+       IFLA_BRIDGE_FLAGS,
+       IFLA_BRIDGE_MODE,
+       __IFLA_BRIDGE_MAX,
+};
+#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
+
+/* Bridge multicast database attributes
+ * [MDBA_MDB] = {
+ *     [MDBA_MDB_ENTRY] = {
+ *         [MDBA_MDB_ENTRY_INFO]
+ *     }
+ * }
+ * [MDBA_ROUTER] = {
+ *    [MDBA_ROUTER_PORT]
+ * }
+ */
+enum {
+       MDBA_UNSPEC,
+       MDBA_MDB,
+       MDBA_ROUTER,
+       __MDBA_MAX,
+};
+#define MDBA_MAX (__MDBA_MAX - 1)
+
+enum {
+       MDBA_MDB_UNSPEC,
+       MDBA_MDB_ENTRY,
+       __MDBA_MDB_MAX,
+};
+#define MDBA_MDB_MAX (__MDBA_MDB_MAX - 1)
+
+enum {
+       MDBA_MDB_ENTRY_UNSPEC,
+       MDBA_MDB_ENTRY_INFO,
+       __MDBA_MDB_ENTRY_MAX,
+};
+#define MDBA_MDB_ENTRY_MAX (__MDBA_MDB_ENTRY_MAX - 1)
+
+enum {
+       MDBA_ROUTER_UNSPEC,
+       MDBA_ROUTER_PORT,
+       __MDBA_ROUTER_MAX,
+};
+#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1)
+
+struct br_port_msg {
+       __u8  family;
+       __u32 ifindex;
+};
+
+struct br_mdb_entry {
+       __u32 ifindex;
+#define MDB_TEMPORARY 0
+#define MDB_PERMANENT 1
+       __u8 state;
+       struct {
+               union {
+                       __be32  ip4;
+                       struct in6_addr ip6;
+               } u;
+               __be16          proto;
+       } addr;
+};
+
+enum {
+       MDBA_SET_ENTRY_UNSPEC,
+       MDBA_SET_ENTRY,
+       __MDBA_SET_ENTRY_MAX,
+};
+#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
+
+#endif /* _UAPI_LINUX_IF_BRIDGE_H */
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
new file mode 100644 (file)
index 0000000..a6af32d
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             Global definitions for the Ethernet IEEE 802.3 interface.
+ *
+ * Version:    @(#)if_ether.h  1.0.1a  02/08/94
+ *
+ * Author:     Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *             Donald Becker, <becker@super.org>
+ *             Alan Cox, <alan@lxorguk.ukuu.org.uk>
+ *             Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+#include <linux/types.h>
+
+/*
+ *     IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+ *     and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN       6               /* Octets in one ethernet addr   */
+#define ETH_HLEN       14              /* Total octets in header.       */
+#define ETH_ZLEN       60              /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN   1500            /* Max. octets in payload        */
+#define ETH_FRAME_LEN  1514            /* Max. octets in frame sans FCS */
+#define ETH_FCS_LEN    4               /* Octets in the FCS             */
+
+/*
+ *     These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP     0x0060          /* Ethernet Loopback packet     */
+#define ETH_P_PUP      0x0200          /* Xerox PUP packet             */
+#define ETH_P_PUPAT    0x0201          /* Xerox PUP Addr Trans packet  */
+#define ETH_P_IP       0x0800          /* Internet Protocol packet     */
+#define ETH_P_X25      0x0805          /* CCITT X.25                   */
+#define ETH_P_ARP      0x0806          /* Address Resolution packet    */
+#define        ETH_P_BPQ       0x08FF          /* G8BPQ AX.25 Ethernet Packet  [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IEEEPUP  0x0a00          /* Xerox IEEE802.3 PUP packet */
+#define ETH_P_IEEEPUPAT        0x0a01          /* Xerox IEEE802.3 PUP Addr Trans packet */
+#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
+#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
+#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
+#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
+#define ETH_P_LAT       0x6004          /* DEC LAT                      */
+#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
+#define ETH_P_CUST      0x6006          /* DEC Customer use             */
+#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
+#define ETH_P_TEB      0x6558          /* Trans Ether Bridging         */
+#define ETH_P_RARP      0x8035         /* Reverse Addr Res packet      */
+#define ETH_P_ATALK    0x809B          /* Appletalk DDP                */
+#define ETH_P_AARP     0x80F3          /* Appletalk AARP               */
+#define ETH_P_8021Q    0x8100          /* 802.1Q VLAN Extended Header  */
+#define ETH_P_IPX      0x8137          /* IPX over DIX                 */
+#define ETH_P_IPV6     0x86DD          /* IPv6 over bluebook           */
+#define ETH_P_PAUSE    0x8808          /* IEEE Pause frames. See 802.3 31B */
+#define ETH_P_SLOW     0x8809          /* Slow Protocol. See 802.3ad 43B */
+#define ETH_P_WCCP     0x883E          /* Web-cache coordination protocol
+                                        * defined in draft-wilson-wrec-wccp-v2-00.txt */
+#define ETH_P_PPP_DISC 0x8863          /* PPPoE discovery messages     */
+#define ETH_P_PPP_SES  0x8864          /* PPPoE session messages       */
+#define ETH_P_MPLS_UC  0x8847          /* MPLS Unicast traffic         */
+#define ETH_P_MPLS_MC  0x8848          /* MPLS Multicast traffic       */
+#define ETH_P_ATMMPOA  0x884c          /* MultiProtocol Over ATM       */
+#define ETH_P_LINK_CTL 0x886c          /* HPNA, wlan link local tunnel */
+#define ETH_P_ATMFATE  0x8884          /* Frame-based ATM Transport
+                                        * over Ethernet
+                                        */
+#define ETH_P_PAE      0x888E          /* Port Access Entity (IEEE 802.1X) */
+#define ETH_P_AOE      0x88A2          /* ATA over Ethernet            */
+#define ETH_P_TIPC     0x88CA          /* TIPC                         */
+#define ETH_P_1588     0x88F7          /* IEEE 1588 Timesync */
+#define ETH_P_FCOE     0x8906          /* Fibre Channel over Ethernet  */
+#define ETH_P_FIP      0x8914          /* FCoE Initialization Protocol */
+#define ETH_P_EDSA     0xDADA          /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+
+/*
+ *     Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3    0x0001          /* Dummy type for 802.3 frames  */
+#define ETH_P_AX25     0x0002          /* Dummy protocol id for AX.25  */
+#define ETH_P_ALL      0x0003          /* Every packet (be careful!!!) */
+#define ETH_P_802_2    0x0004          /* 802.2 frames                 */
+#define ETH_P_SNAP     0x0005          /* Internal only                */
+#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
+#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009         /* Localtalk pseudo type        */
+#define ETH_P_CAN      0x000C          /* Controller Area Network      */
+#define ETH_P_PPPTALK  0x0010          /* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2 0x0011          /* 802.2 frames                 */
+#define ETH_P_MOBITEX  0x0015          /* Mobitex (kaz@cafe.net)       */
+#define ETH_P_CONTROL  0x0016          /* Card specific control frames */
+#define ETH_P_IRDA     0x0017          /* Linux-IrDA                   */
+#define ETH_P_ECONET   0x0018          /* Acorn Econet                 */
+#define ETH_P_HDLC     0x0019          /* HDLC frames                  */
+#define ETH_P_ARCNET   0x001A          /* 1A for ArcNet :-)            */
+#define ETH_P_DSA      0x001B          /* Distributed Switch Arch.     */
+#define ETH_P_TRAILER  0x001C          /* Trailer switch tagging       */
+#define ETH_P_PHONET   0x00F5          /* Nokia Phonet frames          */
+#define ETH_P_IEEE802154 0x00F6                /* IEEE802.15.4 frame           */
+#define ETH_P_CAIF     0x00F7          /* ST-Ericsson CAIF protocol    */
+
+/*
+ *     This is an Ethernet frame header.
+ */
+
+struct ethhdr {
+       unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
+       unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
+       __be16          h_proto;                /* packet type ID field */
+} __attribute__((packed));
+
+#endif /* _LINUX_IF_ETHER_H */
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
new file mode 100644 (file)
index 0000000..73ee05c
--- /dev/null
@@ -0,0 +1,446 @@
+#ifndef _UAPI_LINUX_IF_LINK_H
+#define _UAPI_LINUX_IF_LINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+/* This struct should be in sync with struct rtnl_link_stats64 */
+struct rtnl_link_stats {
+       __u32   rx_packets;             /* total packets received       */
+       __u32   tx_packets;             /* total packets transmitted    */
+       __u32   rx_bytes;               /* total bytes received         */
+       __u32   tx_bytes;               /* total bytes transmitted      */
+       __u32   rx_errors;              /* bad packets received         */
+       __u32   tx_errors;              /* packet transmit problems     */
+       __u32   rx_dropped;             /* no space in linux buffers    */
+       __u32   tx_dropped;             /* no space available in linux  */
+       __u32   multicast;              /* multicast packets received   */
+       __u32   collisions;
+
+       /* detailed rx_errors: */
+       __u32   rx_length_errors;
+       __u32   rx_over_errors;         /* receiver ring buff overflow  */
+       __u32   rx_crc_errors;          /* recved pkt with crc error    */
+       __u32   rx_frame_errors;        /* recv'd frame alignment error */
+       __u32   rx_fifo_errors;         /* recv'r fifo overrun          */
+       __u32   rx_missed_errors;       /* receiver missed packet       */
+
+       /* detailed tx_errors */
+       __u32   tx_aborted_errors;
+       __u32   tx_carrier_errors;
+       __u32   tx_fifo_errors;
+       __u32   tx_heartbeat_errors;
+       __u32   tx_window_errors;
+
+       /* for cslip etc */
+       __u32   rx_compressed;
+       __u32   tx_compressed;
+};
+
+/* The main device statistics structure */
+struct rtnl_link_stats64 {
+       __u64   rx_packets;             /* total packets received       */
+       __u64   tx_packets;             /* total packets transmitted    */
+       __u64   rx_bytes;               /* total bytes received         */
+       __u64   tx_bytes;               /* total bytes transmitted      */
+       __u64   rx_errors;              /* bad packets received         */
+       __u64   tx_errors;              /* packet transmit problems     */
+       __u64   rx_dropped;             /* no space in linux buffers    */
+       __u64   tx_dropped;             /* no space available in linux  */
+       __u64   multicast;              /* multicast packets received   */
+       __u64   collisions;
+
+       /* detailed rx_errors: */
+       __u64   rx_length_errors;
+       __u64   rx_over_errors;         /* receiver ring buff overflow  */
+       __u64   rx_crc_errors;          /* recved pkt with crc error    */
+       __u64   rx_frame_errors;        /* recv'd frame alignment error */
+       __u64   rx_fifo_errors;         /* recv'r fifo overrun          */
+       __u64   rx_missed_errors;       /* receiver missed packet       */
+
+       /* detailed tx_errors */
+       __u64   tx_aborted_errors;
+       __u64   tx_carrier_errors;
+       __u64   tx_fifo_errors;
+       __u64   tx_heartbeat_errors;
+       __u64   tx_window_errors;
+
+       /* for cslip etc */
+       __u64   rx_compressed;
+       __u64   tx_compressed;
+};
+
+/* The struct should be in sync with struct ifmap */
+struct rtnl_link_ifmap {
+       __u64   mem_start;
+       __u64   mem_end;
+       __u64   base_addr;
+       __u16   irq;
+       __u8    dma;
+       __u8    port;
+};
+
+/*
+ * IFLA_AF_SPEC
+ *   Contains nested attributes for address family specific attributes.
+ *   Each address family may create a attribute with the address family
+ *   number as type and create its own attribute structure in it.
+ *
+ *   Example:
+ *   [IFLA_AF_SPEC] = {
+ *       [AF_INET] = {
+ *           [IFLA_INET_CONF] = ...,
+ *       },
+ *       [AF_INET6] = {
+ *           [IFLA_INET6_FLAGS] = ...,
+ *           [IFLA_INET6_CONF] = ...,
+ *       }
+ *   }
+ */
+
+enum {
+       IFLA_UNSPEC,
+       IFLA_ADDRESS,
+       IFLA_BROADCAST,
+       IFLA_IFNAME,
+       IFLA_MTU,
+       IFLA_LINK,
+       IFLA_QDISC,
+       IFLA_STATS,
+       IFLA_COST,
+#define IFLA_COST IFLA_COST
+       IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+       IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+       IFLA_WIRELESS,          /* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+       IFLA_PROTINFO,          /* Protocol specific information for a link */
+#define IFLA_PROTINFO IFLA_PROTINFO
+       IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+       IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
+       IFLA_WEIGHT,
+#define IFLA_WEIGHT IFLA_WEIGHT
+       IFLA_OPERSTATE,
+       IFLA_LINKMODE,
+       IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
+       IFLA_NET_NS_PID,
+       IFLA_IFALIAS,
+       IFLA_NUM_VF,            /* Number of VFs if device is SR-IOV PF */
+       IFLA_VFINFO_LIST,
+       IFLA_STATS64,
+       IFLA_VF_PORTS,
+       IFLA_PORT_SELF,
+       IFLA_AF_SPEC,
+       IFLA_GROUP,             /* Group the device belongs to */
+       IFLA_NET_NS_FD,
+       IFLA_EXT_MASK,          /* Extended info mask, VFs, etc */
+       IFLA_PROMISCUITY,       /* Promiscuity count: > 0 means acts PROMISC */
+#define IFLA_PROMISCUITY IFLA_PROMISCUITY
+       IFLA_NUM_TX_QUEUES,
+       IFLA_NUM_RX_QUEUES,
+       IFLA_CARRIER,
+       __IFLA_MAX
+};
+
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+enum {
+       IFLA_INET_UNSPEC,
+       IFLA_INET_CONF,
+       __IFLA_INET_MAX,
+};
+
+#define IFLA_INET_MAX (__IFLA_INET_MAX - 1)
+
+/* ifi_flags.
+
+   IFF_* flags.
+
+   The only change is:
+   IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+   more not changeable by user. They describe link media
+   characteristics and set by device driver.
+
+   Comments:
+   - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+   - If neither of these three flags are set;
+     the interface is NBMA.
+
+   - IFF_MULTICAST does not mean anything special:
+   multicasts can be used on all not-NBMA links.
+   IFF_MULTICAST means that this media uses special encapsulation
+   for multicast frames. Apparently, all IFF_POINTOPOINT and
+   IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+   For usual devices it is equal ifi_index.
+   If it is a "virtual interface" (f.e. tunnel), ifi_link
+   can point to real physical interface (f.e. for bandwidth calculations),
+   or maybe 0, what means, that real media is unknown (usual
+   for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/* Subtype attributes for IFLA_PROTINFO */
+enum {
+       IFLA_INET6_UNSPEC,
+       IFLA_INET6_FLAGS,       /* link flags                   */
+       IFLA_INET6_CONF,        /* sysctl parameters            */
+       IFLA_INET6_STATS,       /* statistics                   */
+       IFLA_INET6_MCAST,       /* MC things. What of them?     */
+       IFLA_INET6_CACHEINFO,   /* time values and max reasm size */
+       IFLA_INET6_ICMP6STATS,  /* statistics (icmpv6)          */
+       __IFLA_INET6_MAX
+};
+
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+
+enum {
+       BRIDGE_MODE_UNSPEC,
+       BRIDGE_MODE_HAIRPIN,
+};
+
+enum {
+       IFLA_BRPORT_UNSPEC,
+       IFLA_BRPORT_STATE,      /* Spanning tree state     */
+       IFLA_BRPORT_PRIORITY,   /* "             priority  */
+       IFLA_BRPORT_COST,       /* "             cost      */
+       IFLA_BRPORT_MODE,       /* mode (hairpin)          */
+       IFLA_BRPORT_GUARD,      /* bpdu guard              */
+       IFLA_BRPORT_PROTECT,    /* root port protection    */
+       IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave    */
+       __IFLA_BRPORT_MAX
+};
+#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+
+struct ifla_cacheinfo {
+       __u32   max_reasm_len;
+       __u32   tstamp;         /* ipv6InterfaceTable updated timestamp */
+       __u32   reachable_time;
+       __u32   retrans_time;
+};
+
+enum {
+       IFLA_INFO_UNSPEC,
+       IFLA_INFO_KIND,
+       IFLA_INFO_DATA,
+       IFLA_INFO_XSTATS,
+       __IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX  (__IFLA_INFO_MAX - 1)
+
+/* VLAN section */
+
+enum {
+       IFLA_VLAN_UNSPEC,
+       IFLA_VLAN_ID,
+       IFLA_VLAN_FLAGS,
+       IFLA_VLAN_EGRESS_QOS,
+       IFLA_VLAN_INGRESS_QOS,
+       __IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX  (__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+       __u32   flags;
+       __u32   mask;
+};
+
+enum {
+       IFLA_VLAN_QOS_UNSPEC,
+       IFLA_VLAN_QOS_MAPPING,
+       __IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX      (__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping {
+       __u32 from;
+       __u32 to;
+};
+
+/* MACVLAN section */
+enum {
+       IFLA_MACVLAN_UNSPEC,
+       IFLA_MACVLAN_MODE,
+       IFLA_MACVLAN_FLAGS,
+       __IFLA_MACVLAN_MAX,
+};
+
+#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
+
+enum macvlan_mode {
+       MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */
+       MACVLAN_MODE_VEPA    = 2, /* talk to other ports through ext bridge */
+       MACVLAN_MODE_BRIDGE  = 4, /* talk to bridge ports directly */
+       MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
+};
+
+#define MACVLAN_FLAG_NOPROMISC 1
+
+/* VXLAN section */
+enum {
+       IFLA_VXLAN_UNSPEC,
+       IFLA_VXLAN_ID,
+       IFLA_VXLAN_GROUP,
+       IFLA_VXLAN_LINK,
+       IFLA_VXLAN_LOCAL,
+       IFLA_VXLAN_TTL,
+       IFLA_VXLAN_TOS,
+       IFLA_VXLAN_LEARNING,
+       IFLA_VXLAN_AGEING,
+       IFLA_VXLAN_LIMIT,
+       IFLA_VXLAN_PORT_RANGE,
+       IFLA_VXLAN_PROXY,
+       IFLA_VXLAN_RSC,
+       IFLA_VXLAN_L2MISS,
+       IFLA_VXLAN_L3MISS,
+       __IFLA_VXLAN_MAX
+};
+#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
+
+struct ifla_vxlan_port_range {
+       __be16  low;
+       __be16  high;
+};
+
+/* SR-IOV virtual function management section */
+
+enum {
+       IFLA_VF_INFO_UNSPEC,
+       IFLA_VF_INFO,
+       __IFLA_VF_INFO_MAX,
+};
+
+#define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1)
+
+enum {
+       IFLA_VF_UNSPEC,
+       IFLA_VF_MAC,            /* Hardware queue specific attributes */
+       IFLA_VF_VLAN,
+       IFLA_VF_TX_RATE,        /* TX Bandwidth Allocation */
+       IFLA_VF_SPOOFCHK,       /* Spoof Checking on/off switch */
+       __IFLA_VF_MAX,
+};
+
+#define IFLA_VF_MAX (__IFLA_VF_MAX - 1)
+
+struct ifla_vf_mac {
+       __u32 vf;
+       __u8 mac[32]; /* MAX_ADDR_LEN */
+};
+
+struct ifla_vf_vlan {
+       __u32 vf;
+       __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+       __u32 qos;
+};
+
+struct ifla_vf_tx_rate {
+       __u32 vf;
+       __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+};
+
+struct ifla_vf_spoofchk {
+       __u32 vf;
+       __u32 setting;
+};
+
+/* VF ports management section
+ *
+ *     Nested layout of set/get msg is:
+ *
+ *             [IFLA_NUM_VF]
+ *             [IFLA_VF_PORTS]
+ *                     [IFLA_VF_PORT]
+ *                             [IFLA_PORT_*], ...
+ *                     [IFLA_VF_PORT]
+ *                             [IFLA_PORT_*], ...
+ *                     ...
+ *             [IFLA_PORT_SELF]
+ *                     [IFLA_PORT_*], ...
+ */
+
+enum {
+       IFLA_VF_PORT_UNSPEC,
+       IFLA_VF_PORT,                   /* nest */
+       __IFLA_VF_PORT_MAX,
+};
+
+#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1)
+
+enum {
+       IFLA_PORT_UNSPEC,
+       IFLA_PORT_VF,                   /* __u32 */
+       IFLA_PORT_PROFILE,              /* string */
+       IFLA_PORT_VSI_TYPE,             /* 802.1Qbg (pre-)standard VDP */
+       IFLA_PORT_INSTANCE_UUID,        /* binary UUID */
+       IFLA_PORT_HOST_UUID,            /* binary UUID */
+       IFLA_PORT_REQUEST,              /* __u8 */
+       IFLA_PORT_RESPONSE,             /* __u16, output only */
+       __IFLA_PORT_MAX,
+};
+
+#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1)
+
+#define PORT_PROFILE_MAX       40
+#define PORT_UUID_MAX          16
+#define PORT_SELF_VF           -1
+
+enum {
+       PORT_REQUEST_PREASSOCIATE = 0,
+       PORT_REQUEST_PREASSOCIATE_RR,
+       PORT_REQUEST_ASSOCIATE,
+       PORT_REQUEST_DISASSOCIATE,
+};
+
+enum {
+       PORT_VDP_RESPONSE_SUCCESS = 0,
+       PORT_VDP_RESPONSE_INVALID_FORMAT,
+       PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES,
+       PORT_VDP_RESPONSE_UNUSED_VTID,
+       PORT_VDP_RESPONSE_VTID_VIOLATION,
+       PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION,
+       PORT_VDP_RESPONSE_OUT_OF_SYNC,
+       /* 0x08-0xFF reserved for future VDP use */
+       PORT_PROFILE_RESPONSE_SUCCESS = 0x100,
+       PORT_PROFILE_RESPONSE_INPROGRESS,
+       PORT_PROFILE_RESPONSE_INVALID,
+       PORT_PROFILE_RESPONSE_BADSTATE,
+       PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES,
+       PORT_PROFILE_RESPONSE_ERROR,
+};
+
+struct ifla_port_vsi {
+       __u8 vsi_mgr_id;
+       __u8 vsi_type_id[3];
+       __u8 vsi_type_version;
+       __u8 pad[3];
+};
+
+
+/* IPoIB section */
+
+enum {
+       IFLA_IPOIB_UNSPEC,
+       IFLA_IPOIB_PKEY,
+       IFLA_IPOIB_MODE,
+       IFLA_IPOIB_UMCAST,
+       __IFLA_IPOIB_MAX
+};
+
+enum {
+       IPOIB_MODE_DATAGRAM  = 0, /* using unreliable datagram QPs */
+       IPOIB_MODE_CONNECTED = 1, /* using connected QPs */
+};
+
+#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)
+
+#endif /* _UAPI_LINUX_IF_LINK_H */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
new file mode 100644 (file)
index 0000000..67affd1
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * VLAN                An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors:    Ben Greear <greearb@candelatech.com>
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _LINUX_IF_VLAN_H_
+#define _LINUX_IF_VLAN_H_
+
+/* VLAN IOCTLs are found in sockios.h */
+
+/* Passed in vlan_ioctl_args structure to determine behaviour. */
+enum vlan_ioctl_cmds {
+       ADD_VLAN_CMD,
+       DEL_VLAN_CMD,
+       SET_VLAN_INGRESS_PRIORITY_CMD,
+       SET_VLAN_EGRESS_PRIORITY_CMD,
+       GET_VLAN_INGRESS_PRIORITY_CMD,
+       GET_VLAN_EGRESS_PRIORITY_CMD,
+       SET_VLAN_NAME_TYPE_CMD,
+       SET_VLAN_FLAG_CMD,
+       GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */
+       GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */
+};
+
+enum vlan_flags {
+       VLAN_FLAG_REORDER_HDR   = 0x1,
+       VLAN_FLAG_GVRP          = 0x2,
+       VLAN_FLAG_LOOSE_BINDING = 0x4,
+};
+
+enum vlan_name_types {
+       VLAN_NAME_TYPE_PLUS_VID, /* Name will look like:  vlan0005 */
+       VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like:  eth1.0005 */
+       VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like:  vlan5 */
+       VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like:  eth0.5 */
+       VLAN_NAME_TYPE_HIGHEST
+};
+
+struct vlan_ioctl_args {
+       int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
+       char device1[24];
+
+        union {
+               char device2[24];
+               int VID;
+               unsigned int skb_priority;
+               unsigned int name_type;
+               unsigned int bind_type;
+               unsigned int flag; /* Matches vlan_dev_info flags */
+        } u;
+
+       short vlan_qos;   
+};
+
+#endif /* !(_LINUX_IF_VLAN_H_) */
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
new file mode 100644 (file)
index 0000000..fd4d2df
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _LINUX_INETDEVICE_H
+#define _LINUX_INETDEVICE_H
+
+enum
+{
+       IPV4_DEVCONF_FORWARDING=1,
+       IPV4_DEVCONF_MC_FORWARDING,
+       IPV4_DEVCONF_PROXY_ARP,
+       IPV4_DEVCONF_ACCEPT_REDIRECTS,
+       IPV4_DEVCONF_SECURE_REDIRECTS,
+       IPV4_DEVCONF_SEND_REDIRECTS,
+       IPV4_DEVCONF_SHARED_MEDIA,
+       IPV4_DEVCONF_RP_FILTER,
+       IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE,
+       IPV4_DEVCONF_BOOTP_RELAY,
+       IPV4_DEVCONF_LOG_MARTIANS,
+       IPV4_DEVCONF_TAG,
+       IPV4_DEVCONF_ARPFILTER,
+       IPV4_DEVCONF_MEDIUM_ID,
+       IPV4_DEVCONF_NOXFRM,
+       IPV4_DEVCONF_NOPOLICY,
+       IPV4_DEVCONF_FORCE_IGMP_VERSION,
+       IPV4_DEVCONF_ARP_ANNOUNCE,
+       IPV4_DEVCONF_ARP_IGNORE,
+       IPV4_DEVCONF_PROMOTE_SECONDARIES,
+       IPV4_DEVCONF_ARP_ACCEPT,
+       IPV4_DEVCONF_ARP_NOTIFY,
+       IPV4_DEVCONF_ACCEPT_LOCAL,
+       IPV4_DEVCONF_SRC_VMARK,
+       IPV4_DEVCONF_PROXY_ARP_PVLAN,
+       __IPV4_DEVCONF_MAX
+};
+
+#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1)
+
+#endif /* _LINUX_INETDEVICE_H */
diff --git a/include/linux/ip_mp_alg.h b/include/linux/ip_mp_alg.h
new file mode 100644 (file)
index 0000000..e234e20
--- /dev/null
@@ -0,0 +1,22 @@
+/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
+ *
+ * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
+ * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
+ */
+
+#ifndef _LINUX_IP_MP_ALG_H
+#define _LINUX_IP_MP_ALG_H
+
+enum ip_mp_alg {
+       IP_MP_ALG_NONE,
+       IP_MP_ALG_RR,
+       IP_MP_ALG_DRR,
+       IP_MP_ALG_RANDOM,
+       IP_MP_ALG_WRANDOM,
+       __IP_MP_ALG_MAX
+};
+
+#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1)
+
+#endif /* _LINUX_IP_MP_ALG_H */
+
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
new file mode 100644 (file)
index 0000000..f16349d
--- /dev/null
@@ -0,0 +1,146 @@
+#ifndef _IPV6_H
+#define _IPV6_H
+
+#include <asm/byteorder.h>
+
+/* The latest drafts declared increase in minimal mtu up to 1280. */
+
+#define IPV6_MIN_MTU   1280
+
+/*
+ *     Advanced API
+ *     source interface/address selection, source routing, etc...
+ *     *under construction*
+ */
+
+
+#define IPV6_SRCRT_STRICT      0x01    /* Deprecated; will be removed */
+#define IPV6_SRCRT_TYPE_0      0       /* Deprecated; will be removed */
+#define IPV6_SRCRT_TYPE_2      2       /* IPv6 type 2 Routing Header   */
+
+/*
+ *     routing header
+ */
+struct ipv6_rt_hdr {
+       __u8            nexthdr;
+       __u8            hdrlen;
+       __u8            type;
+       __u8            segments_left;
+
+       /*
+        *      type specific data
+        *      variable length field
+        */
+};
+
+
+struct ipv6_opt_hdr {
+       __u8            nexthdr;
+       __u8            hdrlen;
+       /* 
+        * TLV encoded option data follows.
+        */
+} __attribute__((packed));     /* required for some archs */
+
+#define ipv6_destopt_hdr ipv6_opt_hdr
+#define ipv6_hopopt_hdr  ipv6_opt_hdr
+
+
+/*
+ *     routing header type 0 (used in cmsghdr struct)
+ */
+
+struct rt0_hdr {
+       struct ipv6_rt_hdr      rt_hdr;
+       __u32                   reserved;
+       struct in6_addr         addr[0];
+
+#define rt0_type               rt_hdr.type
+};
+
+/*
+ *     routing header type 2
+ */
+
+struct rt2_hdr {
+       struct ipv6_rt_hdr      rt_hdr;
+       __u32                   reserved;
+       struct in6_addr         addr;
+
+#define rt2_type               rt_hdr.type
+};
+
+/*
+ *     home address option in destination options header
+ */
+
+struct ipv6_destopt_hao {
+       __u8                    type;
+       __u8                    length;
+       struct in6_addr         addr;
+} __attribute__((packed));
+
+/*
+ *     IPv6 fixed header
+ *
+ *     BEWARE, it is incorrect. The first 4 bits of flow_lbl
+ *     are glued to priority now, forming "class".
+ */
+
+struct ipv6hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8                    priority:4,
+                               version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u8                    version:4,
+                               priority:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+       __u8                    flow_lbl[3];
+
+       __be16                  payload_len;
+       __u8                    nexthdr;
+       __u8                    hop_limit;
+
+       struct  in6_addr        saddr;
+       struct  in6_addr        daddr;
+};
+
+
+/* index values for the variables in ipv6_devconf */
+enum {
+       DEVCONF_FORWARDING = 0,
+       DEVCONF_HOPLIMIT,
+       DEVCONF_MTU6,
+       DEVCONF_ACCEPT_RA,
+       DEVCONF_ACCEPT_REDIRECTS,
+       DEVCONF_AUTOCONF,
+       DEVCONF_DAD_TRANSMITS,
+       DEVCONF_RTR_SOLICITS,
+       DEVCONF_RTR_SOLICIT_INTERVAL,
+       DEVCONF_RTR_SOLICIT_DELAY,
+       DEVCONF_USE_TEMPADDR,
+       DEVCONF_TEMP_VALID_LFT,
+       DEVCONF_TEMP_PREFERED_LFT,
+       DEVCONF_REGEN_MAX_RETRY,
+       DEVCONF_MAX_DESYNC_FACTOR,
+       DEVCONF_MAX_ADDRESSES,
+       DEVCONF_FORCE_MLD_VERSION,
+       DEVCONF_ACCEPT_RA_DEFRTR,
+       DEVCONF_ACCEPT_RA_PINFO,
+       DEVCONF_ACCEPT_RA_RTR_PREF,
+       DEVCONF_RTR_PROBE_INTERVAL,
+       DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
+       DEVCONF_PROXY_NDP,
+       DEVCONF_OPTIMISTIC_DAD,
+       DEVCONF_ACCEPT_SOURCE_ROUTE,
+       DEVCONF_MC_FORWARDING,
+       DEVCONF_DISABLE_IPV6,
+       DEVCONF_ACCEPT_DAD,
+       DEVCONF_FORCE_TLLAO,
+       DEVCONF_MAX
+};
+
+
+#endif /* _IPV6_H */
diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h
new file mode 100644 (file)
index 0000000..a7003b7
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef __LINUX_NEIGHBOUR_H
+#define __LINUX_NEIGHBOUR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ndmsg {
+       __u8            ndm_family;
+       __u8            ndm_pad1;
+       __u16           ndm_pad2;
+       __s32           ndm_ifindex;
+       __u16           ndm_state;
+       __u8            ndm_flags;
+       __u8            ndm_type;
+};
+
+enum {
+       NDA_UNSPEC,
+       NDA_DST,
+       NDA_LLADDR,
+       NDA_CACHEINFO,
+       NDA_PROBES,
+       __NDA_MAX
+};
+
+#define NDA_MAX (__NDA_MAX - 1)
+
+/*
+ *     Neighbor Cache Entry Flags
+ */
+
+#define NTF_USE                0x01
+#define NTF_PROXY      0x08    /* == ATF_PUBL */
+#define NTF_ROUTER     0x80
+
+/*
+ *     Neighbor Cache Entry States.
+ */
+
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE  0x02
+#define NUD_STALE      0x04
+#define NUD_DELAY      0x08
+#define NUD_PROBE      0x10
+#define NUD_FAILED     0x20
+
+/* Dummy states */
+#define NUD_NOARP      0x40
+#define NUD_PERMANENT  0x80
+#define NUD_NONE       0x00
+
+/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
+   and make no address resolution or NUD.
+   NUD_PERMANENT is also cannot be deleted by garbage collectors.
+ */
+
+struct nda_cacheinfo {
+       __u32           ndm_confirmed;
+       __u32           ndm_used;
+       __u32           ndm_updated;
+       __u32           ndm_refcnt;
+};
+
+/*****************************************************************
+ *             Neighbour tables specific messages.
+ *
+ * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the
+ * NLM_F_DUMP flag set. Every neighbour table configuration is
+ * spread over multiple messages to avoid running into message
+ * size limits on systems with many interfaces. The first message
+ * in the sequence transports all not device specific data such as
+ * statistics, configuration, and the default parameter set.
+ * This message is followed by 0..n messages carrying device
+ * specific parameter sets.
+ * Although the ordering should be sufficient, NDTA_NAME can be
+ * used to identify sequences. The initial message can be identified
+ * by checking for NDTA_CONFIG. The device specific messages do
+ * not contain this TLV but have NDTPA_IFINDEX set to the
+ * corresponding interface index.
+ *
+ * To change neighbour table attributes, send RTM_SETNEIGHTBL
+ * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3],
+ * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked
+ * otherwise. Device specific parameter sets can be changed by
+ * setting NDTPA_IFINDEX to the interface index of the corresponding
+ * device.
+ ****/
+
+struct ndt_stats {
+       __u64           ndts_allocs;
+       __u64           ndts_destroys;
+       __u64           ndts_hash_grows;
+       __u64           ndts_res_failed;
+       __u64           ndts_lookups;
+       __u64           ndts_hits;
+       __u64           ndts_rcv_probes_mcast;
+       __u64           ndts_rcv_probes_ucast;
+       __u64           ndts_periodic_gc_runs;
+       __u64           ndts_forced_gc_runs;
+};
+
+enum {
+       NDTPA_UNSPEC,
+       NDTPA_IFINDEX,                  /* u32, unchangeable */
+       NDTPA_REFCNT,                   /* u32, read-only */
+       NDTPA_REACHABLE_TIME,           /* u64, read-only, msecs */
+       NDTPA_BASE_REACHABLE_TIME,      /* u64, msecs */
+       NDTPA_RETRANS_TIME,             /* u64, msecs */
+       NDTPA_GC_STALETIME,             /* u64, msecs */
+       NDTPA_DELAY_PROBE_TIME,         /* u64, msecs */
+       NDTPA_QUEUE_LEN,                /* u32 */
+       NDTPA_APP_PROBES,               /* u32 */
+       NDTPA_UCAST_PROBES,             /* u32 */
+       NDTPA_MCAST_PROBES,             /* u32 */
+       NDTPA_ANYCAST_DELAY,            /* u64, msecs */
+       NDTPA_PROXY_DELAY,              /* u64, msecs */
+       NDTPA_PROXY_QLEN,               /* u32 */
+       NDTPA_LOCKTIME,                 /* u64, msecs */
+       __NDTPA_MAX
+};
+#define NDTPA_MAX (__NDTPA_MAX - 1)
+
+struct ndtmsg {
+       __u8            ndtm_family;
+       __u8            ndtm_pad1;
+       __u16           ndtm_pad2;
+};
+
+struct ndt_config {
+       __u16           ndtc_key_len;
+       __u16           ndtc_entry_size;
+       __u32           ndtc_entries;
+       __u32           ndtc_last_flush;        /* delta to now in msecs */
+       __u32           ndtc_last_rand;         /* delta to now in msecs */
+       __u32           ndtc_hash_rnd;
+       __u32           ndtc_hash_mask;
+       __u32           ndtc_hash_chain_gc;
+       __u32           ndtc_proxy_qlen;
+};
+
+enum {
+       NDTA_UNSPEC,
+       NDTA_NAME,                      /* char *, unchangeable */
+       NDTA_THRESH1,                   /* u32 */
+       NDTA_THRESH2,                   /* u32 */
+       NDTA_THRESH3,                   /* u32 */
+       NDTA_CONFIG,                    /* struct ndt_config, read-only */
+       NDTA_PARMS,                     /* nested TLV NDTPA_* */
+       NDTA_STATS,                     /* struct ndt_stats, read-only */
+       NDTA_GC_INTERVAL,               /* u64, msecs */
+       __NDTA_MAX
+};
+#define NDTA_MAX (__NDTA_MAX - 1)
+
+#endif
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
new file mode 100644 (file)
index 0000000..7999885
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __LINUX_NETFILTER_H
+#define __LINUX_NETFILTER_H
+
+#include <linux/types.h>
+
+/* Responses from hook functions. */
+#define NF_DROP 0
+#define NF_ACCEPT 1
+#define NF_STOLEN 2
+#define NF_QUEUE 3
+#define NF_REPEAT 4
+#define NF_STOP 5
+#define NF_MAX_VERDICT NF_STOP
+
+/* we overload the higher bits for encoding auxiliary data such as the queue
+ * number. Not nice, but better than additional function arguments. */
+#define NF_VERDICT_MASK 0x0000ffff
+#define NF_VERDICT_BITS 16
+
+#define NF_VERDICT_QMASK 0xffff0000
+#define NF_VERDICT_QBITS 16
+
+#define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE)
+
+/* Generic cache responses from hook functions.
+   <= 0x2000 is used for protocol-flags. */
+#define NFC_UNKNOWN 0x4000
+#define NFC_ALTERED 0x8000
+
+enum nf_inet_hooks {
+       NF_INET_PRE_ROUTING,
+       NF_INET_LOCAL_IN,
+       NF_INET_FORWARD,
+       NF_INET_LOCAL_OUT,
+       NF_INET_POST_ROUTING,
+       NF_INET_NUMHOOKS
+};
+
+enum {
+       NFPROTO_UNSPEC =  0,
+       NFPROTO_IPV4   =  2,
+       NFPROTO_ARP    =  3,
+       NFPROTO_BRIDGE =  7,
+       NFPROTO_IPV6   = 10,
+       NFPROTO_DECNET = 12,
+       NFPROTO_NUMPROTO,
+};
+
+union nf_inet_addr {
+       __u32           all[4];
+       __be32          ip;
+       __be32          ip6[4];
+       struct in_addr  in;
+       struct in6_addr in6;
+};
+
+#endif /*__LINUX_NETFILTER_H*/
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
new file mode 100644 (file)
index 0000000..1644cdd
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef _UAPI_NF_CONNTRACK_COMMON_H
+#define _UAPI_NF_CONNTRACK_COMMON_H
+/* Connection state tracking for netfilter.  This is separated from,
+   but required by, the NAT layer; it can also be used by an iptables
+   extension. */
+enum ip_conntrack_info {
+       /* Part of an established connection (either direction). */
+       IP_CT_ESTABLISHED,
+
+       /* Like NEW, but related to an existing connection, or ICMP error
+          (in either direction). */
+       IP_CT_RELATED,
+
+       /* Started a new connection to track (only
+           IP_CT_DIR_ORIGINAL); may be a retransmission. */
+       IP_CT_NEW,
+
+       /* >= this indicates reply direction */
+       IP_CT_IS_REPLY,
+
+       IP_CT_ESTABLISHED_REPLY = IP_CT_ESTABLISHED + IP_CT_IS_REPLY,
+       IP_CT_RELATED_REPLY = IP_CT_RELATED + IP_CT_IS_REPLY,
+       IP_CT_NEW_REPLY = IP_CT_NEW + IP_CT_IS_REPLY,   
+       /* Number of distinct IP_CT types (no NEW in reply dirn). */
+       IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
+};
+
+/* Bitset representing status of connection. */
+enum ip_conntrack_status {
+       /* It's an expected connection: bit 0 set.  This bit never changed */
+       IPS_EXPECTED_BIT = 0,
+       IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
+
+       /* We've seen packets both ways: bit 1 set.  Can be set, not unset. */
+       IPS_SEEN_REPLY_BIT = 1,
+       IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
+
+       /* Conntrack should never be early-expired. */
+       IPS_ASSURED_BIT = 2,
+       IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+
+       /* Connection is confirmed: originating packet has left box */
+       IPS_CONFIRMED_BIT = 3,
+       IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
+
+       /* Connection needs src nat in orig dir.  This bit never changed. */
+       IPS_SRC_NAT_BIT = 4,
+       IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
+
+       /* Connection needs dst nat in orig dir.  This bit never changed. */
+       IPS_DST_NAT_BIT = 5,
+       IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
+
+       /* Both together. */
+       IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
+
+       /* Connection needs TCP sequence adjusted. */
+       IPS_SEQ_ADJUST_BIT = 6,
+       IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
+
+       /* NAT initialization bits. */
+       IPS_SRC_NAT_DONE_BIT = 7,
+       IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
+
+       IPS_DST_NAT_DONE_BIT = 8,
+       IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
+
+       /* Both together */
+       IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+       /* Connection is dying (removed from lists), can not be unset. */
+       IPS_DYING_BIT = 9,
+       IPS_DYING = (1 << IPS_DYING_BIT),
+
+       /* Connection has fixed timeout. */
+       IPS_FIXED_TIMEOUT_BIT = 10,
+       IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
+
+       /* Conntrack is a template */
+       IPS_TEMPLATE_BIT = 11,
+       IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
+
+       /* Conntrack is a fake untracked entry */
+       IPS_UNTRACKED_BIT = 12,
+       IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
+
+       /* Conntrack got a helper explicitly attached via CT target. */
+       IPS_HELPER_BIT = 13,
+       IPS_HELPER = (1 << IPS_HELPER_BIT),
+};
+
+/* Connection tracking event types */
+enum ip_conntrack_events {
+       IPCT_NEW,               /* new conntrack */
+       IPCT_RELATED,           /* related conntrack */
+       IPCT_DESTROY,           /* destroyed conntrack */
+       IPCT_REPLY,             /* connection has seen two-way traffic */
+       IPCT_ASSURED,           /* connection status has changed to assured */
+       IPCT_PROTOINFO,         /* protocol information has changed */
+       IPCT_HELPER,            /* new helper has been set */
+       IPCT_MARK,              /* new mark has been set */
+       IPCT_NATSEQADJ,         /* NAT is doing sequence adjustment */
+       IPCT_SECMARK,           /* new security mark has been set */
+};
+
+enum ip_conntrack_expect_events {
+       IPEXP_NEW,              /* new expectation */
+       IPEXP_DESTROY,          /* destroyed expectation */
+};
+
+/* expectation flags */
+#define NF_CT_EXPECT_PERMANENT         0x1
+#define NF_CT_EXPECT_INACTIVE          0x2
+#define NF_CT_EXPECT_USERSPACE         0x4
+
+
+#endif /* _UAPI_NF_CONNTRACK_COMMON_H */
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
new file mode 100644 (file)
index 0000000..4a4efaf
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _UAPI_NFNETLINK_H
+#define _UAPI_NFNETLINK_H
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink_compat.h>
+
+enum nfnetlink_groups {
+       NFNLGRP_NONE,
+#define NFNLGRP_NONE                   NFNLGRP_NONE
+       NFNLGRP_CONNTRACK_NEW,
+#define NFNLGRP_CONNTRACK_NEW          NFNLGRP_CONNTRACK_NEW
+       NFNLGRP_CONNTRACK_UPDATE,
+#define NFNLGRP_CONNTRACK_UPDATE       NFNLGRP_CONNTRACK_UPDATE
+       NFNLGRP_CONNTRACK_DESTROY,
+#define NFNLGRP_CONNTRACK_DESTROY      NFNLGRP_CONNTRACK_DESTROY
+       NFNLGRP_CONNTRACK_EXP_NEW,
+#define        NFNLGRP_CONNTRACK_EXP_NEW       NFNLGRP_CONNTRACK_EXP_NEW
+       NFNLGRP_CONNTRACK_EXP_UPDATE,
+#define NFNLGRP_CONNTRACK_EXP_UPDATE   NFNLGRP_CONNTRACK_EXP_UPDATE
+       NFNLGRP_CONNTRACK_EXP_DESTROY,
+#define NFNLGRP_CONNTRACK_EXP_DESTROY  NFNLGRP_CONNTRACK_EXP_DESTROY
+       __NFNLGRP_MAX,
+};
+#define NFNLGRP_MAX    (__NFNLGRP_MAX - 1)
+
+/* General form of address family dependent message.
+ */
+struct nfgenmsg {
+       __u8  nfgen_family;             /* AF_xxx */
+       __u8  version;          /* nfnetlink version */
+       __be16    res_id;               /* resource id */
+};
+
+#define NFNETLINK_V0   0
+
+/* netfilter netlink message types are split in two pieces:
+ * 8 bit subsystem, 8bit operation.
+ */
+
+#define NFNL_SUBSYS_ID(x)      ((x & 0xff00) >> 8)
+#define NFNL_MSG_TYPE(x)       (x & 0x00ff)
+
+/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
+ * won't work anymore */
+#define NFNL_SUBSYS_NONE               0
+#define NFNL_SUBSYS_CTNETLINK          1
+#define NFNL_SUBSYS_CTNETLINK_EXP      2
+#define NFNL_SUBSYS_QUEUE              3
+#define NFNL_SUBSYS_ULOG               4
+#define NFNL_SUBSYS_OSF                        5
+#define NFNL_SUBSYS_IPSET              6
+#define NFNL_SUBSYS_ACCT               7
+#define NFNL_SUBSYS_CTNETLINK_TIMEOUT  8
+#define NFNL_SUBSYS_CTHELPER           9
+#define NFNL_SUBSYS_COUNT              10
+
+#endif /* _UAPI_NFNETLINK_H */
diff --git a/include/linux/netfilter/nfnetlink_compat.h b/include/linux/netfilter/nfnetlink_compat.h
new file mode 100644 (file)
index 0000000..ffb9503
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _NFNETLINK_COMPAT_H
+#define _NFNETLINK_COMPAT_H
+
+#include <linux/types.h>
+
+#ifndef __KERNEL__
+/* Old nfnetlink macros for userspace */
+
+/* nfnetlink groups: Up to 32 maximum */
+#define NF_NETLINK_CONNTRACK_NEW               0x00000001
+#define NF_NETLINK_CONNTRACK_UPDATE            0x00000002
+#define NF_NETLINK_CONNTRACK_DESTROY           0x00000004
+#define NF_NETLINK_CONNTRACK_EXP_NEW           0x00000008
+#define NF_NETLINK_CONNTRACK_EXP_UPDATE                0x00000010
+#define NF_NETLINK_CONNTRACK_EXP_DESTROY       0x00000020
+
+/* Generic structure for encapsulation optional netfilter information.
+ * It is reminiscent of sockaddr, but with sa_family replaced
+ * with attribute type.
+ * ! This should someday be put somewhere generic as now rtnetlink and
+ * ! nfnetlink use the same attributes methods. - J. Schulist.
+ */
+
+struct nfattr {
+       __u16 nfa_len;
+       __u16 nfa_type; /* we use 15 bits for the type, and the highest
+                                * bit to indicate whether the payload is nested */
+};
+
+/* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from
+ * rtnetlink.h, it's time to put this in a generic file */
+
+#define NFNL_NFA_NEST  0x8000
+#define NFA_TYPE(attr)         ((attr)->nfa_type & 0x7fff)
+
+#define NFA_ALIGNTO     4
+#define NFA_ALIGN(len) (((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1))
+#define NFA_OK(nfa,len)        ((len) > 0 && (nfa)->nfa_len >= sizeof(struct nfattr) \
+       && (nfa)->nfa_len <= (len))
+#define NFA_NEXT(nfa,attrlen)  ((attrlen) -= NFA_ALIGN((nfa)->nfa_len), \
+       (struct nfattr *)(((char *)(nfa)) + NFA_ALIGN((nfa)->nfa_len)))
+#define NFA_LENGTH(len)        (NFA_ALIGN(sizeof(struct nfattr)) + (len))
+#define NFA_SPACE(len) NFA_ALIGN(NFA_LENGTH(len))
+#define NFA_DATA(nfa)   ((void *)(((char *)(nfa)) + NFA_LENGTH(0)))
+#define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0))
+#define NFA_NEST(skb, type) \
+({     struct nfattr *__start = (struct nfattr *)skb_tail_pointer(skb); \
+       NFA_PUT(skb, (NFNL_NFA_NEST | type), 0, NULL); \
+       __start;  })
+#define NFA_NEST_END(skb, start) \
+({      (start)->nfa_len = skb_tail_pointer(skb) - (unsigned char *)(start); \
+        (skb)->len; })
+#define NFA_NEST_CANCEL(skb, start) \
+({      if (start) \
+                skb_trim(skb, (unsigned char *) (start) - (skb)->data); \
+        -1; })
+
+#define NFM_NFA(n)      ((struct nfattr *)(((char *)(n)) \
+        + NLMSG_ALIGN(sizeof(struct nfgenmsg))))
+#define NFM_PAYLOAD(n)  NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg))
+
+#endif /* ! __KERNEL__ */
+#endif /* _NFNETLINK_COMPAT_H */
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
new file mode 100644 (file)
index 0000000..43bfe3e
--- /dev/null
@@ -0,0 +1,248 @@
+#ifndef _IPCONNTRACK_NETLINK_H
+#define _IPCONNTRACK_NETLINK_H
+#include <linux/netfilter/nfnetlink.h>
+
+enum cntl_msg_types {
+       IPCTNL_MSG_CT_NEW,
+       IPCTNL_MSG_CT_GET,
+       IPCTNL_MSG_CT_DELETE,
+       IPCTNL_MSG_CT_GET_CTRZERO,
+       IPCTNL_MSG_CT_GET_STATS_CPU,
+       IPCTNL_MSG_CT_GET_STATS,
+
+       IPCTNL_MSG_MAX
+};
+
+enum ctnl_exp_msg_types {
+       IPCTNL_MSG_EXP_NEW,
+       IPCTNL_MSG_EXP_GET,
+       IPCTNL_MSG_EXP_DELETE,
+       IPCTNL_MSG_EXP_GET_STATS_CPU,
+
+       IPCTNL_MSG_EXP_MAX
+};
+
+
+enum ctattr_type {
+       CTA_UNSPEC,
+       CTA_TUPLE_ORIG,
+       CTA_TUPLE_REPLY,
+       CTA_STATUS,
+       CTA_PROTOINFO,
+       CTA_HELP,
+       CTA_NAT_SRC,
+#define CTA_NAT        CTA_NAT_SRC     /* backwards compatibility */
+       CTA_TIMEOUT,
+       CTA_MARK,
+       CTA_COUNTERS_ORIG,
+       CTA_COUNTERS_REPLY,
+       CTA_USE,
+       CTA_ID,
+       CTA_NAT_DST,
+       CTA_TUPLE_MASTER,
+       CTA_NAT_SEQ_ADJ_ORIG,
+       CTA_NAT_SEQ_ADJ_REPLY,
+       CTA_SECMARK,            /* obsolete */
+       CTA_ZONE,
+       CTA_SECCTX,
+       CTA_TIMESTAMP,
+       CTA_MARK_MASK,
+       __CTA_MAX
+};
+#define CTA_MAX (__CTA_MAX - 1)
+
+enum ctattr_tuple {
+       CTA_TUPLE_UNSPEC,
+       CTA_TUPLE_IP,
+       CTA_TUPLE_PROTO,
+       __CTA_TUPLE_MAX
+};
+#define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1)
+
+enum ctattr_ip {
+       CTA_IP_UNSPEC,
+       CTA_IP_V4_SRC,
+       CTA_IP_V4_DST,
+       CTA_IP_V6_SRC,
+       CTA_IP_V6_DST,
+       __CTA_IP_MAX
+};
+#define CTA_IP_MAX (__CTA_IP_MAX - 1)
+
+enum ctattr_l4proto {
+       CTA_PROTO_UNSPEC,
+       CTA_PROTO_NUM,
+       CTA_PROTO_SRC_PORT,
+       CTA_PROTO_DST_PORT,
+       CTA_PROTO_ICMP_ID,
+       CTA_PROTO_ICMP_TYPE,
+       CTA_PROTO_ICMP_CODE,
+       CTA_PROTO_ICMPV6_ID,
+       CTA_PROTO_ICMPV6_TYPE,
+       CTA_PROTO_ICMPV6_CODE,
+       __CTA_PROTO_MAX
+};
+#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1)
+
+enum ctattr_protoinfo {
+       CTA_PROTOINFO_UNSPEC,
+       CTA_PROTOINFO_TCP,
+       CTA_PROTOINFO_DCCP,
+       CTA_PROTOINFO_SCTP,
+       __CTA_PROTOINFO_MAX
+};
+#define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
+
+enum ctattr_protoinfo_tcp {
+       CTA_PROTOINFO_TCP_UNSPEC,
+       CTA_PROTOINFO_TCP_STATE,
+       CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
+       CTA_PROTOINFO_TCP_WSCALE_REPLY,
+       CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
+       CTA_PROTOINFO_TCP_FLAGS_REPLY,
+       __CTA_PROTOINFO_TCP_MAX
+};
+#define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1)
+
+enum ctattr_protoinfo_dccp {
+       CTA_PROTOINFO_DCCP_UNSPEC,
+       CTA_PROTOINFO_DCCP_STATE,
+       CTA_PROTOINFO_DCCP_ROLE,
+       CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
+       __CTA_PROTOINFO_DCCP_MAX,
+};
+#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1)
+
+enum ctattr_protoinfo_sctp {
+       CTA_PROTOINFO_SCTP_UNSPEC,
+       CTA_PROTOINFO_SCTP_STATE,
+       CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+       CTA_PROTOINFO_SCTP_VTAG_REPLY,
+       __CTA_PROTOINFO_SCTP_MAX
+};
+#define CTA_PROTOINFO_SCTP_MAX (__CTA_PROTOINFO_SCTP_MAX - 1)
+
+enum ctattr_counters {
+       CTA_COUNTERS_UNSPEC,
+       CTA_COUNTERS_PACKETS,           /* 64bit counters */
+       CTA_COUNTERS_BYTES,             /* 64bit counters */
+       CTA_COUNTERS32_PACKETS,         /* old 32bit counters, unused */
+       CTA_COUNTERS32_BYTES,           /* old 32bit counters, unused */
+       __CTA_COUNTERS_MAX
+};
+#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
+
+enum ctattr_tstamp {
+       CTA_TIMESTAMP_UNSPEC,
+       CTA_TIMESTAMP_START,
+       CTA_TIMESTAMP_STOP,
+       __CTA_TIMESTAMP_MAX
+};
+#define CTA_TIMESTAMP_MAX (__CTA_TIMESTAMP_MAX - 1)
+
+enum ctattr_nat {
+       CTA_NAT_UNSPEC,
+       CTA_NAT_V4_MINIP,
+#define CTA_NAT_MINIP CTA_NAT_V4_MINIP
+       CTA_NAT_V4_MAXIP,
+#define CTA_NAT_MAXIP CTA_NAT_V4_MAXIP
+       CTA_NAT_PROTO,
+       CTA_NAT_V6_MINIP,
+       CTA_NAT_V6_MAXIP,
+       __CTA_NAT_MAX
+};
+#define CTA_NAT_MAX (__CTA_NAT_MAX - 1)
+
+enum ctattr_protonat {
+       CTA_PROTONAT_UNSPEC,
+       CTA_PROTONAT_PORT_MIN,
+       CTA_PROTONAT_PORT_MAX,
+       __CTA_PROTONAT_MAX
+};
+#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1)
+
+enum ctattr_natseq {
+       CTA_NAT_SEQ_UNSPEC,
+       CTA_NAT_SEQ_CORRECTION_POS,
+       CTA_NAT_SEQ_OFFSET_BEFORE,
+       CTA_NAT_SEQ_OFFSET_AFTER,
+       __CTA_NAT_SEQ_MAX
+};
+#define CTA_NAT_SEQ_MAX (__CTA_NAT_SEQ_MAX - 1)
+
+enum ctattr_expect {
+       CTA_EXPECT_UNSPEC,
+       CTA_EXPECT_MASTER,
+       CTA_EXPECT_TUPLE,
+       CTA_EXPECT_MASK,
+       CTA_EXPECT_TIMEOUT,
+       CTA_EXPECT_ID,
+       CTA_EXPECT_HELP_NAME,
+       CTA_EXPECT_ZONE,
+       CTA_EXPECT_FLAGS,
+       CTA_EXPECT_CLASS,
+       CTA_EXPECT_NAT,
+       CTA_EXPECT_FN,
+       __CTA_EXPECT_MAX
+};
+#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
+
+enum ctattr_expect_nat {
+       CTA_EXPECT_NAT_UNSPEC,
+       CTA_EXPECT_NAT_DIR,
+       CTA_EXPECT_NAT_TUPLE,
+       __CTA_EXPECT_NAT_MAX
+};
+#define CTA_EXPECT_NAT_MAX (__CTA_EXPECT_NAT_MAX - 1)
+
+enum ctattr_help {
+       CTA_HELP_UNSPEC,
+       CTA_HELP_NAME,
+       CTA_HELP_INFO,
+       __CTA_HELP_MAX
+};
+#define CTA_HELP_MAX (__CTA_HELP_MAX - 1)
+
+enum ctattr_secctx {
+       CTA_SECCTX_UNSPEC,
+       CTA_SECCTX_NAME,
+       __CTA_SECCTX_MAX
+};
+#define CTA_SECCTX_MAX (__CTA_SECCTX_MAX - 1)
+
+enum ctattr_stats_cpu {
+       CTA_STATS_UNSPEC,
+       CTA_STATS_SEARCHED,
+       CTA_STATS_FOUND,
+       CTA_STATS_NEW,
+       CTA_STATS_INVALID,
+       CTA_STATS_IGNORE,
+       CTA_STATS_DELETE,
+       CTA_STATS_DELETE_LIST,
+       CTA_STATS_INSERT,
+       CTA_STATS_INSERT_FAILED,
+       CTA_STATS_DROP,
+       CTA_STATS_EARLY_DROP,
+       CTA_STATS_ERROR,
+       CTA_STATS_SEARCH_RESTART,
+       __CTA_STATS_MAX,
+};
+#define CTA_STATS_MAX (__CTA_STATS_MAX - 1)
+
+enum ctattr_stats_global {
+       CTA_STATS_GLOBAL_UNSPEC,
+       CTA_STATS_GLOBAL_ENTRIES,
+       __CTA_STATS_GLOBAL_MAX,
+};
+#define CTA_STATS_GLOBAL_MAX (__CTA_STATS_GLOBAL_MAX - 1)
+
+enum ctattr_expect_stats {
+       CTA_STATS_EXP_UNSPEC,
+       CTA_STATS_EXP_NEW,
+       CTA_STATS_EXP_CREATE,
+       CTA_STATS_EXP_DELETE,
+       __CTA_STATS_EXP_MAX,
+};
+#define CTA_STATS_EXP_MAX (__CTA_STATS_EXP_MAX - 1)
+
+#endif /* _IPCONNTRACK_NETLINK_H */
diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h
new file mode 100644 (file)
index 0000000..2cfbf13
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef _NFNETLINK_LOG_H
+#define _NFNETLINK_LOG_H
+
+/* This file describes the netlink messages (i.e. 'protocol packets'),
+ * and not any kind of function definitions.  It is shared between kernel and
+ * userspace.  Don't put kernel specific stuff in here */
+
+#ifndef __aligned_be64
+#define __aligned_be64 u_int64_t __attribute__((aligned(8)))
+#endif
+
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
+
+enum nfulnl_msg_types {
+       NFULNL_MSG_PACKET,              /* packet from kernel to userspace */
+       NFULNL_MSG_CONFIG,              /* connect to a particular queue */
+
+       NFULNL_MSG_MAX
+};
+
+struct nfulnl_msg_packet_hdr {
+       __be16          hw_protocol;    /* hw protocol (network order) */
+       __u8    hook;           /* netfilter hook */
+       __u8    _pad;
+};
+
+struct nfulnl_msg_packet_hw {
+       __be16          hw_addrlen;
+       __u16   _pad;
+       __u8    hw_addr[8];
+};
+
+struct nfulnl_msg_packet_timestamp {
+       __aligned_be64  sec;
+       __aligned_be64  usec;
+};
+
+enum nfulnl_attr_type {
+       NFULA_UNSPEC,
+       NFULA_PACKET_HDR,
+       NFULA_MARK,                     /* __u32 nfmark */
+       NFULA_TIMESTAMP,                /* nfulnl_msg_packet_timestamp */
+       NFULA_IFINDEX_INDEV,            /* __u32 ifindex */
+       NFULA_IFINDEX_OUTDEV,           /* __u32 ifindex */
+       NFULA_IFINDEX_PHYSINDEV,        /* __u32 ifindex */
+       NFULA_IFINDEX_PHYSOUTDEV,       /* __u32 ifindex */
+       NFULA_HWADDR,                   /* nfulnl_msg_packet_hw */
+       NFULA_PAYLOAD,                  /* opaque data payload */
+       NFULA_PREFIX,                   /* string prefix */
+       NFULA_UID,                      /* user id of socket */
+       NFULA_SEQ,                      /* instance-local sequence number */
+       NFULA_SEQ_GLOBAL,               /* global sequence number */
+       NFULA_GID,                      /* group id of socket */
+       NFULA_HWTYPE,                   /* hardware type */
+       NFULA_HWHEADER,                 /* hardware header */
+       NFULA_HWLEN,                    /* hardware header length */
+
+       __NFULA_MAX
+};
+#define NFULA_MAX (__NFULA_MAX - 1)
+
+enum nfulnl_msg_config_cmds {
+       NFULNL_CFG_CMD_NONE,
+       NFULNL_CFG_CMD_BIND,
+       NFULNL_CFG_CMD_UNBIND,
+       NFULNL_CFG_CMD_PF_BIND,
+       NFULNL_CFG_CMD_PF_UNBIND,
+};
+
+struct nfulnl_msg_config_cmd {
+       __u8    command;        /* nfulnl_msg_config_cmds */
+} __attribute__ ((packed));
+
+struct nfulnl_msg_config_mode {
+       __be32          copy_range;
+       __u8    copy_mode;
+       __u8    _pad;
+} __attribute__ ((packed));
+
+enum nfulnl_attr_config {
+       NFULA_CFG_UNSPEC,
+       NFULA_CFG_CMD,                  /* nfulnl_msg_config_cmd */
+       NFULA_CFG_MODE,                 /* nfulnl_msg_config_mode */
+       NFULA_CFG_NLBUFSIZ,             /* __u32 buffer size */
+       NFULA_CFG_TIMEOUT,              /* __u32 in 1/100 s */
+       NFULA_CFG_QTHRESH,              /* __u32 */
+       NFULA_CFG_FLAGS,                /* __u16 */
+       __NFULA_CFG_MAX
+};
+#define NFULA_CFG_MAX (__NFULA_CFG_MAX -1)
+
+#define NFULNL_COPY_NONE       0x00
+#define NFULNL_COPY_META       0x01
+#define NFULNL_COPY_PACKET     0x02
+/* 0xff is reserved, don't use it for new copy modes. */
+
+#define NFULNL_CFG_F_SEQ       0x0001
+#define NFULNL_CFG_F_SEQ_GLOBAL        0x0002
+
+#endif /* _NFNETLINK_LOG_H */
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h
new file mode 100644 (file)
index 0000000..95af967
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef _NFNETLINK_QUEUE_H
+#define _NFNETLINK_QUEUE_H
+
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
+
+#ifndef __aligned_be64
+#define __aligned_be64 u_int64_t __attribute__((aligned(8)))
+#endif
+
+enum nfqnl_msg_types {
+       NFQNL_MSG_PACKET,               /* packet from kernel to userspace */
+       NFQNL_MSG_VERDICT,              /* verdict from userspace to kernel */
+       NFQNL_MSG_CONFIG,               /* connect to a particular queue */
+       NFQNL_MSG_VERDICT_BATCH,        /* batchv from userspace to kernel */
+
+       NFQNL_MSG_MAX
+};
+
+struct nfqnl_msg_packet_hdr {
+       __be32          packet_id;      /* unique ID of packet in queue */
+       __be16          hw_protocol;    /* hw protocol (network order) */
+       __u8    hook;           /* netfilter hook */
+} __attribute__ ((packed));
+
+struct nfqnl_msg_packet_hw {
+       __be16          hw_addrlen;
+       __u16   _pad;
+       __u8    hw_addr[8];
+};
+
+struct nfqnl_msg_packet_timestamp {
+       __aligned_be64  sec;
+       __aligned_be64  usec;
+};
+
+enum nfqnl_attr_type {
+       NFQA_UNSPEC,
+       NFQA_PACKET_HDR,
+       NFQA_VERDICT_HDR,               /* nfqnl_msg_verdict_hrd */
+       NFQA_MARK,                      /* __u32 nfmark */
+       NFQA_TIMESTAMP,                 /* nfqnl_msg_packet_timestamp */
+       NFQA_IFINDEX_INDEV,             /* __u32 ifindex */
+       NFQA_IFINDEX_OUTDEV,            /* __u32 ifindex */
+       NFQA_IFINDEX_PHYSINDEV,         /* __u32 ifindex */
+       NFQA_IFINDEX_PHYSOUTDEV,        /* __u32 ifindex */
+       NFQA_HWADDR,                    /* nfqnl_msg_packet_hw */
+       NFQA_PAYLOAD,                   /* opaque data payload */
+       NFQA_CT,                        /* nf_conntrack_netlink.h */
+       NFQA_CT_INFO,                   /* enum ip_conntrack_info */
+       NFQA_CAP_LEN,                   /* __u32 length of captured packet */
+
+       __NFQA_MAX
+};
+#define NFQA_MAX (__NFQA_MAX - 1)
+
+struct nfqnl_msg_verdict_hdr {
+       __be32 verdict;
+       __be32 id;
+};
+
+
+enum nfqnl_msg_config_cmds {
+       NFQNL_CFG_CMD_NONE,
+       NFQNL_CFG_CMD_BIND,
+       NFQNL_CFG_CMD_UNBIND,
+       NFQNL_CFG_CMD_PF_BIND,
+       NFQNL_CFG_CMD_PF_UNBIND,
+};
+
+struct nfqnl_msg_config_cmd {
+       __u8    command;        /* nfqnl_msg_config_cmds */
+       __u8    _pad;
+       __be16          pf;             /* AF_xxx for PF_[UN]BIND */
+};
+
+enum nfqnl_config_mode {
+       NFQNL_COPY_NONE,
+       NFQNL_COPY_META,
+       NFQNL_COPY_PACKET,
+};
+
+struct nfqnl_msg_config_params {
+       __be32          copy_range;
+       __u8    copy_mode;      /* enum nfqnl_config_mode */
+} __attribute__ ((packed));
+
+
+enum nfqnl_attr_config {
+       NFQA_CFG_UNSPEC,
+       NFQA_CFG_CMD,                   /* nfqnl_msg_config_cmd */
+       NFQA_CFG_PARAMS,                /* nfqnl_msg_config_params */
+       NFQA_CFG_QUEUE_MAXLEN,          /* __u32 */
+       NFQA_CFG_MASK,                  /* identify which flags to change */
+       NFQA_CFG_FLAGS,                 /* value of these flags (__u32) */
+       __NFQA_CFG_MAX
+};
+#define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
+
+/* Flags for NFQA_CFG_FLAGS */
+#define NFQA_CFG_F_FAIL_OPEN                   (1 << 0)
+#define NFQA_CFG_F_CONNTRACK                   (1 << 1)
+#define NFQA_CFG_F_MAX                         (1 << 2)
+
+#endif /* _NFNETLINK_QUEUE_H */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
new file mode 100644 (file)
index 0000000..3925254
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <linux/socket.h> /* for sa_family_t */
+#include <linux/types.h>
+
+#define NETLINK_ROUTE          0       /* Routing/device hook                          */
+#define NETLINK_UNUSED         1       /* Unused number                                */
+#define NETLINK_USERSOCK       2       /* Reserved for user mode socket protocols      */
+#define NETLINK_FIREWALL       3       /* Firewalling hook                             */
+#define NETLINK_INET_DIAG      4       /* INET socket monitoring                       */
+#define NETLINK_NFLOG          5       /* netfilter/iptables ULOG */
+#define NETLINK_XFRM           6       /* ipsec */
+#define NETLINK_SELINUX                7       /* SELinux event notifications */
+#define NETLINK_ISCSI          8       /* Open-iSCSI */
+#define NETLINK_AUDIT          9       /* auditing */
+#define NETLINK_FIB_LOOKUP     10      
+#define NETLINK_CONNECTOR      11
+#define NETLINK_NETFILTER      12      /* netfilter subsystem */
+#define NETLINK_IP6_FW         13
+#define NETLINK_DNRTMSG                14      /* DECnet routing messages */
+#define NETLINK_KOBJECT_UEVENT 15      /* Kernel messages to userspace */
+#define NETLINK_GENERIC                16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT  18      /* SCSI Transports */
+#define NETLINK_ECRYPTFS       19
+#define NETLINK_RDMA           20
+
+#define MAX_LINKS 32           
+
+struct sockaddr_nl {
+       sa_family_t     nl_family;      /* AF_NETLINK   */
+       unsigned short  nl_pad;         /* zero         */
+       __u32           nl_pid;         /* port ID      */
+               __u32           nl_groups;      /* multicast groups mask */
+};
+
+struct nlmsghdr {
+       __u32           nlmsg_len;      /* Length of message including header */
+       __u16           nlmsg_type;     /* Message content */
+       __u16           nlmsg_flags;    /* Additional flags */
+       __u32           nlmsg_seq;      /* Sequence number */
+       __u32           nlmsg_pid;      /* Sending process port ID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST          1       /* It is request message.       */
+#define NLM_F_MULTI            2       /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK              4       /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO             8       /* Echo this request            */
+#define NLM_F_DUMP_INTR                16      /* Dump was inconsistent due to sequence change */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT     0x100   /* specify tree root    */
+#define NLM_F_MATCH    0x200   /* return all matching  */
+#define NLM_F_ATOMIC   0x400   /* atomic GET           */
+#define NLM_F_DUMP     (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE  0x100   /* Override existing            */
+#define NLM_F_EXCL     0x200   /* Do not touch, if it exists   */
+#define NLM_F_CREATE   0x400   /* Create, if it does not exist */
+#define NLM_F_APPEND   0x800   /* Add to end of list           */
+
+/*
+   4.4BSD ADD          NLM_F_CREATE|NLM_F_EXCL
+   4.4BSD CHANGE       NLM_F_REPLACE
+
+   True CHANGE         NLM_F_CREATE|NLM_F_REPLACE
+   Append              NLM_F_CREATE
+   Check               NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO  4U
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_HDRLEN    ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len)     ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+                                 (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
+                          (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+                          (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP             0x1     /* Nothing.             */
+#define NLMSG_ERROR            0x2     /* Error                */
+#define NLMSG_DONE             0x3     /* End of a dump        */
+#define NLMSG_OVERRUN          0x4     /* Data lost            */
+
+#define NLMSG_MIN_TYPE         0x10    /* < 0x10: reserved control messages */
+
+struct nlmsgerr {
+       int             error;
+       struct nlmsghdr msg;
+};
+
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP        2
+#define NETLINK_PKTINFO                3
+#define NETLINK_BROADCAST_ERROR        4
+#define NETLINK_NO_ENOBUFS     5
+
+struct nl_pktinfo {
+       __u32   group;
+};
+
+#define NET_MAJOR 36           /* Major 36 is reserved for networking                                          */
+
+enum {
+       NETLINK_UNCONNECTED = 0,
+       NETLINK_CONNECTED,
+};
+
+/*
+ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * |        Header       | Pad |     Payload       | Pad |
+ * |   (struct nlattr)   | ing |                   | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ *  <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr {
+       __u16           nla_len;
+       __u16           nla_type;
+};
+
+/*
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+#define NLA_F_NESTED           (1 << 15)
+#define NLA_F_NET_BYTEORDER    (1 << 14)
+#define NLA_TYPE_MASK          ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+#define NLA_ALIGNTO            4
+#define NLA_ALIGN(len)         (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN             ((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+#endif /* __LINUX_NETLINK_H */
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
new file mode 100644 (file)
index 0000000..defbde2
--- /dev/null
@@ -0,0 +1,467 @@
+#ifndef __LINUX_PKT_CLS_H
+#define __LINUX_PKT_CLS_H
+
+#include <linux/types.h>
+#include <linux/pkt_sched.h>
+
+/* I think i could have done better macros ; for now this is stolen from
+ * some arch/mips code - jhs
+*/
+#define _TC_MAKE32(x) ((x))
+
+#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n))
+#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n))
+#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n))
+#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n))
+
+/* verdict bit breakdown 
+ *
+bit 0: when set -> this packet has been munged already
+
+bit 1: when set -> It is ok to munge this packet
+
+bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded
+assume loop
+
+bit 6,7: Where this packet was last seen 
+0: Above the transmit example at the socket level
+1: on the Ingress
+2: on the Egress
+
+bit 8: when set --> Request not to classify on ingress. 
+
+bits 9,10,11: redirect counter -  redirect TTL. Loop avoidance
+
+ *
+ * */
+
+#define TC_MUNGED          _TC_MAKEMASK1(0)
+#define SET_TC_MUNGED(v)   ( TC_MUNGED | (v & ~TC_MUNGED))
+#define CLR_TC_MUNGED(v)   ( v & ~TC_MUNGED)
+
+#define TC_OK2MUNGE        _TC_MAKEMASK1(1)
+#define SET_TC_OK2MUNGE(v)   ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE))
+#define CLR_TC_OK2MUNGE(v)   ( v & ~TC_OK2MUNGE)
+
+#define S_TC_VERD          _TC_MAKE32(2)
+#define M_TC_VERD          _TC_MAKEMASK(4,S_TC_VERD)
+#define G_TC_VERD(x)       _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD)
+#define V_TC_VERD(x)       _TC_MAKEVALUE(x,S_TC_VERD)
+#define SET_TC_VERD(v,n)   ((V_TC_VERD(n)) | (v & ~M_TC_VERD))
+
+#define S_TC_FROM          _TC_MAKE32(6)
+#define M_TC_FROM          _TC_MAKEMASK(2,S_TC_FROM)
+#define G_TC_FROM(x)       _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM)
+#define V_TC_FROM(x)       _TC_MAKEVALUE(x,S_TC_FROM)
+#define SET_TC_FROM(v,n)   ((V_TC_FROM(n)) | (v & ~M_TC_FROM))
+#define AT_STACK       0x0
+#define AT_INGRESS     0x1
+#define AT_EGRESS      0x2
+
+#define TC_NCLS          _TC_MAKEMASK1(8)
+#define SET_TC_NCLS(v)   ( TC_NCLS | (v & ~TC_NCLS))
+#define CLR_TC_NCLS(v)   ( v & ~TC_NCLS)
+
+#define S_TC_RTTL          _TC_MAKE32(9)
+#define M_TC_RTTL          _TC_MAKEMASK(3,S_TC_RTTL)
+#define G_TC_RTTL(x)       _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL)
+#define V_TC_RTTL(x)       _TC_MAKEVALUE(x,S_TC_RTTL)
+#define SET_TC_RTTL(v,n)   ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL))
+
+#define S_TC_AT          _TC_MAKE32(12)
+#define M_TC_AT          _TC_MAKEMASK(2,S_TC_AT)
+#define G_TC_AT(x)       _TC_GETVALUE(x,S_TC_AT,M_TC_AT)
+#define V_TC_AT(x)       _TC_MAKEVALUE(x,S_TC_AT)
+#define SET_TC_AT(v,n)   ((V_TC_AT(n)) | (v & ~M_TC_AT))
+
+/* Action attributes */
+enum {
+       TCA_ACT_UNSPEC,
+       TCA_ACT_KIND,
+       TCA_ACT_OPTIONS,
+       TCA_ACT_INDEX,
+       TCA_ACT_STATS,
+       __TCA_ACT_MAX
+};
+
+#define TCA_ACT_MAX __TCA_ACT_MAX
+#define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
+#define TCA_ACT_MAX_PRIO 32
+#define TCA_ACT_BIND   1
+#define TCA_ACT_NOBIND 0
+#define TCA_ACT_UNBIND 1
+#define TCA_ACT_NOUNBIND       0
+#define TCA_ACT_REPLACE                1
+#define TCA_ACT_NOREPLACE      0
+#define MAX_REC_LOOP 4
+#define MAX_RED_LOOP 4
+
+#define TC_ACT_UNSPEC  (-1)
+#define TC_ACT_OK              0
+#define TC_ACT_RECLASSIFY      1
+#define TC_ACT_SHOT            2
+#define TC_ACT_PIPE            3
+#define TC_ACT_STOLEN          4
+#define TC_ACT_QUEUED          5
+#define TC_ACT_REPEAT          6
+#define TC_ACT_JUMP            0x10000000
+
+/* Action type identifiers*/
+enum {
+       TCA_ID_UNSPEC=0,
+       TCA_ID_POLICE=1,
+       /* other actions go here */
+       __TCA_ID_MAX=255
+};
+
+#define TCA_ID_MAX __TCA_ID_MAX
+
+struct tc_police {
+       __u32                   index;
+       int                     action;
+#define TC_POLICE_UNSPEC       TC_ACT_UNSPEC
+#define TC_POLICE_OK           TC_ACT_OK
+#define TC_POLICE_RECLASSIFY   TC_ACT_RECLASSIFY
+#define TC_POLICE_SHOT         TC_ACT_SHOT
+#define TC_POLICE_PIPE         TC_ACT_PIPE
+
+       __u32                   limit;
+       __u32                   burst;
+       __u32                   mtu;
+       struct tc_ratespec      rate;
+       struct tc_ratespec      peakrate;
+       int                     refcnt;
+       int                     bindcnt;
+       __u32                   capab;
+};
+
+struct tcf_t {
+       __u64   install;
+       __u64   lastuse;
+       __u64   expires;
+};
+
+struct tc_cnt {
+       int                   refcnt; 
+       int                   bindcnt;
+};
+
+#define tc_gen \
+       __u32                 index; \
+       __u32                 capab; \
+       int                   action; \
+       int                   refcnt; \
+       int                   bindcnt
+
+enum {
+       TCA_POLICE_UNSPEC,
+       TCA_POLICE_TBF,
+       TCA_POLICE_RATE,
+       TCA_POLICE_PEAKRATE,
+       TCA_POLICE_AVRATE,
+       TCA_POLICE_RESULT,
+       __TCA_POLICE_MAX
+#define TCA_POLICE_RESULT TCA_POLICE_RESULT
+};
+
+#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1)
+
+/* U32 filters */
+
+#define TC_U32_HTID(h) ((h)&0xFFF00000)
+#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20)
+#define TC_U32_HASH(h) (((h)>>12)&0xFF)
+#define TC_U32_NODE(h) ((h)&0xFFF)
+#define TC_U32_KEY(h) ((h)&0xFFFFF)
+#define TC_U32_UNSPEC  0
+#define TC_U32_ROOT    (0xFFF00000)
+
+enum {
+       TCA_U32_UNSPEC,
+       TCA_U32_CLASSID,
+       TCA_U32_HASH,
+       TCA_U32_LINK,
+       TCA_U32_DIVISOR,
+       TCA_U32_SEL,
+       TCA_U32_POLICE,
+       TCA_U32_ACT,   
+       TCA_U32_INDEV,
+       TCA_U32_PCNT,
+       TCA_U32_MARK,
+       __TCA_U32_MAX
+};
+
+#define TCA_U32_MAX (__TCA_U32_MAX - 1)
+
+struct tc_u32_key {
+       __be32          mask;
+       __be32          val;
+       int             off;
+       int             offmask;
+};
+
+struct tc_u32_sel {
+       unsigned char           flags;
+       unsigned char           offshift;
+       unsigned char           nkeys;
+
+       __be16                  offmask;
+       __u16                   off;
+       short                   offoff;
+
+       short                   hoff;
+       __be32                  hmask;
+       struct tc_u32_key       keys[0];
+};
+
+struct tc_u32_mark {
+       __u32           val;
+       __u32           mask;
+       __u32           success;
+};
+
+struct tc_u32_pcnt {
+       __u64 rcnt;
+       __u64 rhit;
+       __u64 kcnts[0];
+};
+
+/* Flags */
+
+#define TC_U32_TERMINAL                1
+#define TC_U32_OFFSET          2
+#define TC_U32_VAROFFSET       4
+#define TC_U32_EAT             8
+
+#define TC_U32_MAXDEPTH 8
+
+
+/* RSVP filter */
+
+enum {
+       TCA_RSVP_UNSPEC,
+       TCA_RSVP_CLASSID,
+       TCA_RSVP_DST,
+       TCA_RSVP_SRC,
+       TCA_RSVP_PINFO,
+       TCA_RSVP_POLICE,
+       TCA_RSVP_ACT,
+       __TCA_RSVP_MAX
+};
+
+#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 )
+
+struct tc_rsvp_gpi {
+       __u32   key;
+       __u32   mask;
+       int     offset;
+};
+
+struct tc_rsvp_pinfo {
+       struct tc_rsvp_gpi dpi;
+       struct tc_rsvp_gpi spi;
+       __u8    protocol;
+       __u8    tunnelid;
+       __u8    tunnelhdr;
+       __u8    pad;
+};
+
+/* ROUTE filter */
+
+enum {
+       TCA_ROUTE4_UNSPEC,
+       TCA_ROUTE4_CLASSID,
+       TCA_ROUTE4_TO,
+       TCA_ROUTE4_FROM,
+       TCA_ROUTE4_IIF,
+       TCA_ROUTE4_POLICE,
+       TCA_ROUTE4_ACT,
+       __TCA_ROUTE4_MAX
+};
+
+#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1)
+
+
+/* FW filter */
+
+enum {
+       TCA_FW_UNSPEC,
+       TCA_FW_CLASSID,
+       TCA_FW_POLICE,
+       TCA_FW_INDEV, /*  used by CONFIG_NET_CLS_IND */
+       TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */
+       TCA_FW_MASK,
+       __TCA_FW_MAX
+};
+
+#define TCA_FW_MAX (__TCA_FW_MAX - 1)
+
+/* TC index filter */
+
+enum {
+       TCA_TCINDEX_UNSPEC,
+       TCA_TCINDEX_HASH,
+       TCA_TCINDEX_MASK,
+       TCA_TCINDEX_SHIFT,
+       TCA_TCINDEX_FALL_THROUGH,
+       TCA_TCINDEX_CLASSID,
+       TCA_TCINDEX_POLICE,
+       TCA_TCINDEX_ACT,
+       __TCA_TCINDEX_MAX
+};
+
+#define TCA_TCINDEX_MAX     (__TCA_TCINDEX_MAX - 1)
+
+/* Flow filter */
+
+enum {
+       FLOW_KEY_SRC,
+       FLOW_KEY_DST,
+       FLOW_KEY_PROTO,
+       FLOW_KEY_PROTO_SRC,
+       FLOW_KEY_PROTO_DST,
+       FLOW_KEY_IIF,
+       FLOW_KEY_PRIORITY,
+       FLOW_KEY_MARK,
+       FLOW_KEY_NFCT,
+       FLOW_KEY_NFCT_SRC,
+       FLOW_KEY_NFCT_DST,
+       FLOW_KEY_NFCT_PROTO_SRC,
+       FLOW_KEY_NFCT_PROTO_DST,
+       FLOW_KEY_RTCLASSID,
+       FLOW_KEY_SKUID,
+       FLOW_KEY_SKGID,
+       FLOW_KEY_VLAN_TAG,
+       FLOW_KEY_RXHASH,
+       __FLOW_KEY_MAX,
+};
+
+#define FLOW_KEY_MAX   (__FLOW_KEY_MAX - 1)
+
+enum {
+       FLOW_MODE_MAP,
+       FLOW_MODE_HASH,
+};
+
+enum {
+       TCA_FLOW_UNSPEC,
+       TCA_FLOW_KEYS,
+       TCA_FLOW_MODE,
+       TCA_FLOW_BASECLASS,
+       TCA_FLOW_RSHIFT,
+       TCA_FLOW_ADDEND,
+       TCA_FLOW_MASK,
+       TCA_FLOW_XOR,
+       TCA_FLOW_DIVISOR,
+       TCA_FLOW_ACT,
+       TCA_FLOW_POLICE,
+       TCA_FLOW_EMATCHES,
+       TCA_FLOW_PERTURB,
+       __TCA_FLOW_MAX
+};
+
+#define TCA_FLOW_MAX   (__TCA_FLOW_MAX - 1)
+
+/* Basic filter */
+
+enum {
+       TCA_BASIC_UNSPEC,
+       TCA_BASIC_CLASSID,
+       TCA_BASIC_EMATCHES,
+       TCA_BASIC_ACT,
+       TCA_BASIC_POLICE,
+       __TCA_BASIC_MAX
+};
+
+#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1)
+
+
+/* Cgroup classifier */
+
+enum {
+       TCA_CGROUP_UNSPEC,
+       TCA_CGROUP_ACT,
+       TCA_CGROUP_POLICE,
+       TCA_CGROUP_EMATCHES,
+       __TCA_CGROUP_MAX,
+};
+
+#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
+
+/* Extended Matches */
+
+struct tcf_ematch_tree_hdr {
+       __u16           nmatches;
+       __u16           progid;
+};
+
+enum {
+       TCA_EMATCH_TREE_UNSPEC,
+       TCA_EMATCH_TREE_HDR,
+       TCA_EMATCH_TREE_LIST,
+       __TCA_EMATCH_TREE_MAX
+};
+#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1)
+
+struct tcf_ematch_hdr {
+       __u16           matchid;
+       __u16           kind;
+       __u16           flags;
+       __u16           pad; /* currently unused */
+};
+
+/*  0                   1
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 
+ * +-----------------------+-+-+---+
+ * |         Unused        |S|I| R |
+ * +-----------------------+-+-+---+
+ *
+ * R(2) ::= relation to next ematch
+ *          where: 0 0 END (last ematch)
+ *                 0 1 AND
+ *                 1 0 OR
+ *                 1 1 Unused (invalid)
+ * I(1) ::= invert result
+ * S(1) ::= simple payload
+ */
+#define TCF_EM_REL_END 0
+#define TCF_EM_REL_AND (1<<0)
+#define TCF_EM_REL_OR  (1<<1)
+#define TCF_EM_INVERT  (1<<2)
+#define TCF_EM_SIMPLE  (1<<3)
+
+#define TCF_EM_REL_MASK        3
+#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK)
+
+enum {
+       TCF_LAYER_LINK,
+       TCF_LAYER_NETWORK,
+       TCF_LAYER_TRANSPORT,
+       __TCF_LAYER_MAX
+};
+#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1)
+
+/* Ematch type assignments
+ *   1..32767          Reserved for ematches inside kernel tree
+ *   32768..65535      Free to use, not reliable
+ */
+#define        TCF_EM_CONTAINER        0
+#define        TCF_EM_CMP              1
+#define        TCF_EM_NBYTE            2
+#define        TCF_EM_U32              3
+#define        TCF_EM_META             4
+#define        TCF_EM_TEXT             5
+#define        TCF_EM_VLAN             6
+#define        TCF_EM_MAX              6
+
+enum {
+       TCF_EM_PROG_TC
+};
+
+enum {
+       TCF_EM_OPND_EQ,
+       TCF_EM_OPND_GT,
+       TCF_EM_OPND_LT
+};
+
+#endif
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
new file mode 100644 (file)
index 0000000..7ccc1fd
--- /dev/null
@@ -0,0 +1,627 @@
+#ifndef __LINUX_PKT_SCHED_H
+#define __LINUX_PKT_SCHED_H
+
+#include <linux/types.h>
+
+/* Logical priority bands not depending on specific packet scheduler.
+   Every scheduler will map them to real traffic classes, if it has
+   no more precise mechanism to classify packets.
+
+   These numbers have no special meaning, though their coincidence
+   with obsolete IPv6 values is not occasional :-). New IPv6 drafts
+   preferred full anarchy inspired by diffserv group.
+
+   Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy
+   class, actually, as rule it will be handled with more care than
+   filler or even bulk.
+ */
+
+#define TC_PRIO_BESTEFFORT             0
+#define TC_PRIO_FILLER                 1
+#define TC_PRIO_BULK                   2
+#define TC_PRIO_INTERACTIVE_BULK       4
+#define TC_PRIO_INTERACTIVE            6
+#define TC_PRIO_CONTROL                        7
+
+#define TC_PRIO_MAX                    15
+
+/* Generic queue statistics, available for all the elements.
+   Particular schedulers may have also their private records.
+ */
+
+struct tc_stats {
+       __u64   bytes;                  /* NUmber of enqueues bytes */
+       __u32   packets;                /* Number of enqueued packets   */
+       __u32   drops;                  /* Packets dropped because of lack of resources */
+       __u32   overlimits;             /* Number of throttle events when this
+                                        * flow goes out of allocated bandwidth */
+       __u32   bps;                    /* Current flow byte rate */
+       __u32   pps;                    /* Current flow packet rate */
+       __u32   qlen;
+       __u32   backlog;
+};
+
+struct tc_estimator {
+       signed char     interval;
+       unsigned char   ewma_log;
+};
+
+/* "Handles"
+   ---------
+
+    All the traffic control objects have 32bit identifiers, or "handles".
+
+    They can be considered as opaque numbers from user API viewpoint,
+    but actually they always consist of two fields: major and
+    minor numbers, which are interpreted by kernel specially,
+    that may be used by applications, though not recommended.
+
+    F.e. qdisc handles always have minor number equal to zero,
+    classes (or flows) have major equal to parent qdisc major, and
+    minor uniquely identifying class inside qdisc.
+
+    Macros to manipulate handles:
+ */
+
+#define TC_H_MAJ_MASK (0xFFFF0000U)
+#define TC_H_MIN_MASK (0x0000FFFFU)
+#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK)
+#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK)
+#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK))
+
+#define TC_H_UNSPEC    (0U)
+#define TC_H_ROOT      (0xFFFFFFFFU)
+#define TC_H_INGRESS    (0xFFFFFFF1U)
+
+struct tc_ratespec {
+       unsigned char   cell_log;
+       unsigned char   __reserved;
+       unsigned short  overhead;
+       short           cell_align;
+       unsigned short  mpu;
+       __u32           rate;
+};
+
+#define TC_RTAB_SIZE   1024
+
+struct tc_sizespec {
+       unsigned char   cell_log;
+       unsigned char   size_log;
+       short           cell_align;
+       int             overhead;
+       unsigned int    linklayer;
+       unsigned int    mpu;
+       unsigned int    mtu;
+       unsigned int    tsize;
+};
+
+enum {
+       TCA_STAB_UNSPEC,
+       TCA_STAB_BASE,
+       TCA_STAB_DATA,
+       __TCA_STAB_MAX
+};
+
+#define TCA_STAB_MAX (__TCA_STAB_MAX - 1)
+
+/* FIFO section */
+
+struct tc_fifo_qopt {
+       __u32   limit;  /* Queue length: bytes for bfifo, packets for pfifo */
+};
+
+/* PRIO section */
+
+#define TCQ_PRIO_BANDS 16
+#define TCQ_MIN_PRIO_BANDS 2
+
+struct tc_prio_qopt {
+       int     bands;                  /* Number of bands */
+       __u8    priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
+};
+
+/* MULTIQ section */
+
+struct tc_multiq_qopt {
+       __u16   bands;                  /* Number of bands */
+       __u16   max_bands;              /* Maximum number of queues */
+};
+
+/* PLUG section */
+
+#define TCQ_PLUG_BUFFER                0
+#define TCQ_PLUG_RELEASE_ONE           1
+#define TCQ_PLUG_RELEASE_INDEFINITE    2
+#define TCQ_PLUG_LIMIT                 3
+
+struct tc_plug_qopt {
+        /* TCQ_PLUG_BUFFER: Inset a plug into the queue and
+         *  buffer any incoming packets
+         * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head
+         *   to beginning of the next plug.
+         * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue.
+         *   Stop buffering packets until the next TCQ_PLUG_BUFFER
+         *   command is received (just act as a pass-thru queue).
+         * TCQ_PLUG_LIMIT: Increase/decrease queue size
+         */
+        int             action;
+        __u32           limit;
+};
+
+/* TBF section */
+
+struct tc_tbf_qopt {
+       struct tc_ratespec rate;
+       struct tc_ratespec peakrate;
+       __u32           limit;
+       __u32           buffer;
+       __u32           mtu;
+};
+
+enum {
+       TCA_TBF_UNSPEC,
+       TCA_TBF_PARMS,
+       TCA_TBF_RTAB,
+       TCA_TBF_PTAB,
+       __TCA_TBF_MAX,
+};
+
+#define TCA_TBF_MAX (__TCA_TBF_MAX - 1)
+
+
+/* TEQL section */
+
+/* TEQL does not require any parameters */
+
+/* SFQ section */
+
+struct tc_sfq_qopt {
+       unsigned        quantum;        /* Bytes per round allocated to flow */
+       int             perturb_period; /* Period of hash perturbation */
+       __u32           limit;          /* Maximal packets in queue */
+       unsigned        divisor;        /* Hash divisor  */
+       unsigned        flows;          /* Maximal number of flows  */
+};
+
+struct tc_sfq_xstats {
+       __s32           allot;
+};
+
+/*
+ *  NOTE: limit, divisor and flows are hardwired to code at the moment.
+ *
+ *     limit=flows=128, divisor=1024;
+ *
+ *     The only reason for this is efficiency, it is possible
+ *     to change these parameters in compile time.
+ */
+
+/* RED section */
+
+enum {
+       TCA_RED_UNSPEC,
+       TCA_RED_PARMS,
+       TCA_RED_STAB,
+       __TCA_RED_MAX,
+};
+
+#define TCA_RED_MAX (__TCA_RED_MAX - 1)
+
+struct tc_red_qopt {
+       __u32           limit;          /* HARD maximal queue length (bytes)    */
+       __u32           qth_min;        /* Min average length threshold (bytes) */
+       __u32           qth_max;        /* Max average length threshold (bytes) */
+       unsigned char   Wlog;           /* log(W)               */
+       unsigned char   Plog;           /* log(P_max/(qth_max-qth_min)) */
+       unsigned char   Scell_log;      /* cell size for idle damping */
+       unsigned char   flags;
+#define TC_RED_ECN     1
+#define TC_RED_HARDDROP        2
+};
+
+struct tc_red_xstats {
+       __u32           early;          /* Early drops */
+       __u32           pdrop;          /* Drops due to queue limits */
+       __u32           other;          /* Drops due to drop() calls */
+       __u32           marked;         /* Marked packets */
+};
+
+/* GRED section */
+
+#define MAX_DPs 16
+
+enum {
+       TCA_GRED_UNSPEC,
+       TCA_GRED_PARMS,
+       TCA_GRED_STAB,
+       TCA_GRED_DPS,
+          __TCA_GRED_MAX,
+};
+
+#define TCA_GRED_MAX (__TCA_GRED_MAX - 1)
+
+struct tc_gred_qopt {
+       __u32           limit;        /* HARD maximal queue length (bytes)    */
+       __u32           qth_min;      /* Min average length threshold (bytes) */
+       __u32           qth_max;      /* Max average length threshold (bytes) */
+       __u32           DP;           /* up to 2^32 DPs */
+       __u32           backlog;
+       __u32           qave;
+       __u32           forced;
+       __u32           early;
+       __u32           other;
+       __u32           pdrop;
+       __u8            Wlog;         /* log(W)               */
+       __u8            Plog;         /* log(P_max/(qth_max-qth_min)) */
+       __u8            Scell_log;    /* cell size for idle damping */
+       __u8            prio;         /* prio of this VQ */
+       __u32           packets;
+       __u32           bytesin;
+};
+
+/* gred setup */
+struct tc_gred_sopt {
+       __u32           DPs;
+       __u32           def_DP;
+       __u8            grio;
+       __u8            flags;
+       __u16           pad1;
+};
+
+/* CHOKe section */
+
+enum {
+       TCA_CHOKE_UNSPEC,
+       TCA_CHOKE_PARMS,
+       TCA_CHOKE_STAB,
+       __TCA_CHOKE_MAX,
+};
+
+#define TCA_CHOKE_MAX (__TCA_CHOKE_MAX - 1)
+
+struct tc_choke_qopt {
+       __u32           limit;          /* Hard queue length (packets)  */
+       __u32           qth_min;        /* Min average threshold (packets) */
+       __u32           qth_max;        /* Max average threshold (packets) */
+       unsigned char   Wlog;           /* log(W)               */
+       unsigned char   Plog;           /* log(P_max/(qth_max-qth_min)) */
+       unsigned char   Scell_log;      /* cell size for idle damping */
+       unsigned char   flags;          /* see RED flags */
+};
+
+struct tc_choke_xstats {
+       __u32           early;          /* Early drops */
+       __u32           pdrop;          /* Drops due to queue limits */
+       __u32           other;          /* Drops due to drop() calls */
+       __u32           marked;         /* Marked packets */
+       __u32           matched;        /* Drops due to flow match */
+};
+
+/* HTB section */
+#define TC_HTB_NUMPRIO         8
+#define TC_HTB_MAXDEPTH                8
+#define TC_HTB_PROTOVER                3 /* the same as HTB and TC's major */
+
+struct tc_htb_opt {
+       struct tc_ratespec      rate;
+       struct tc_ratespec      ceil;
+       __u32   buffer;
+       __u32   cbuffer;
+       __u32   quantum;
+       __u32   level;          /* out only */
+       __u32   prio;
+};
+struct tc_htb_glob {
+       __u32 version;          /* to match HTB/TC */
+       __u32 rate2quantum;     /* bps->quantum divisor */
+       __u32 defcls;           /* default class number */
+       __u32 debug;            /* debug flags */
+
+       /* stats */
+       __u32 direct_pkts; /* count of non shapped packets */
+};
+enum {
+       TCA_HTB_UNSPEC,
+       TCA_HTB_PARMS,
+       TCA_HTB_INIT,
+       TCA_HTB_CTAB,
+       TCA_HTB_RTAB,
+       __TCA_HTB_MAX,
+};
+
+#define TCA_HTB_MAX (__TCA_HTB_MAX - 1)
+
+struct tc_htb_xstats {
+       __u32 lends;
+       __u32 borrows;
+       __u32 giants;   /* too big packets (rate will not be accurate) */
+       __u32 tokens;
+       __u32 ctokens;
+};
+
+/* HFSC section */
+
+struct tc_hfsc_qopt {
+       __u16   defcls;         /* default class */
+};
+
+struct tc_service_curve {
+       __u32   m1;             /* slope of the first segment in bps */
+       __u32   d;              /* x-projection of the first segment in us */
+       __u32   m2;             /* slope of the second segment in bps */
+};
+
+struct tc_hfsc_stats {
+       __u64   work;           /* total work done */
+       __u64   rtwork;         /* work done by real-time criteria */
+       __u32   period;         /* current period */
+       __u32   level;          /* class level in hierarchy */
+};
+
+enum {
+       TCA_HFSC_UNSPEC,
+       TCA_HFSC_RSC,
+       TCA_HFSC_FSC,
+       TCA_HFSC_USC,
+       __TCA_HFSC_MAX,
+};
+
+#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1)
+
+
+/* CBQ section */
+
+#define TC_CBQ_MAXPRIO         8
+#define TC_CBQ_MAXLEVEL                8
+#define TC_CBQ_DEF_EWMA                5
+
+struct tc_cbq_lssopt {
+       unsigned char   change;
+       unsigned char   flags;
+#define TCF_CBQ_LSS_BOUNDED    1
+#define TCF_CBQ_LSS_ISOLATED   2
+       unsigned char   ewma_log;
+       unsigned char   level;
+#define TCF_CBQ_LSS_FLAGS      1
+#define TCF_CBQ_LSS_EWMA       2
+#define TCF_CBQ_LSS_MAXIDLE    4
+#define TCF_CBQ_LSS_MINIDLE    8
+#define TCF_CBQ_LSS_OFFTIME    0x10
+#define TCF_CBQ_LSS_AVPKT      0x20
+       __u32           maxidle;
+       __u32           minidle;
+       __u32           offtime;
+       __u32           avpkt;
+};
+
+struct tc_cbq_wrropt {
+       unsigned char   flags;
+       unsigned char   priority;
+       unsigned char   cpriority;
+       unsigned char   __reserved;
+       __u32           allot;
+       __u32           weight;
+};
+
+struct tc_cbq_ovl {
+       unsigned char   strategy;
+#define        TC_CBQ_OVL_CLASSIC      0
+#define        TC_CBQ_OVL_DELAY        1
+#define        TC_CBQ_OVL_LOWPRIO      2
+#define        TC_CBQ_OVL_DROP         3
+#define        TC_CBQ_OVL_RCLASSIC     4
+       unsigned char   priority2;
+       __u16           pad;
+       __u32           penalty;
+};
+
+struct tc_cbq_police {
+       unsigned char   police;
+       unsigned char   __res1;
+       unsigned short  __res2;
+};
+
+struct tc_cbq_fopt {
+       __u32           split;
+       __u32           defmap;
+       __u32           defchange;
+};
+
+struct tc_cbq_xstats {
+       __u32           borrows;
+       __u32           overactions;
+       __s32           avgidle;
+       __s32           undertime;
+};
+
+enum {
+       TCA_CBQ_UNSPEC,
+       TCA_CBQ_LSSOPT,
+       TCA_CBQ_WRROPT,
+       TCA_CBQ_FOPT,
+       TCA_CBQ_OVL_STRATEGY,
+       TCA_CBQ_RATE,
+       TCA_CBQ_RTAB,
+       TCA_CBQ_POLICE,
+       __TCA_CBQ_MAX,
+};
+
+#define TCA_CBQ_MAX    (__TCA_CBQ_MAX - 1)
+
+/* dsmark section */
+
+enum {
+       TCA_DSMARK_UNSPEC,
+       TCA_DSMARK_INDICES,
+       TCA_DSMARK_DEFAULT_INDEX,
+       TCA_DSMARK_SET_TC_INDEX,
+       TCA_DSMARK_MASK,
+       TCA_DSMARK_VALUE,
+       __TCA_DSMARK_MAX,
+};
+
+#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1)
+
+/* ATM  section */
+
+enum {
+       TCA_ATM_UNSPEC,
+       TCA_ATM_FD,             /* file/socket descriptor */
+       TCA_ATM_PTR,            /* pointer to descriptor - later */
+       TCA_ATM_HDR,            /* LL header */
+       TCA_ATM_EXCESS,         /* excess traffic class (0 for CLP)  */
+       TCA_ATM_ADDR,           /* PVC address (for output only) */
+       TCA_ATM_STATE,          /* VC state (ATM_VS_*; for output only) */
+       __TCA_ATM_MAX,
+};
+
+#define TCA_ATM_MAX    (__TCA_ATM_MAX - 1)
+
+/* Network emulator */
+
+enum {
+       TCA_NETEM_UNSPEC,
+       TCA_NETEM_CORR,
+       TCA_NETEM_DELAY_DIST,
+       TCA_NETEM_REORDER,
+       TCA_NETEM_CORRUPT,
+       TCA_NETEM_LOSS,
+       __TCA_NETEM_MAX,
+};
+
+#define TCA_NETEM_MAX (__TCA_NETEM_MAX - 1)
+
+struct tc_netem_qopt {
+       __u32   latency;        /* added delay (us) */
+       __u32   limit;          /* fifo limit (packets) */
+       __u32   loss;           /* random packet loss (0=none ~0=100%) */
+       __u32   gap;            /* re-ordering gap (0 for none) */
+       __u32   duplicate;      /* random packet dup  (0=none ~0=100%) */
+       __u32   jitter;         /* random jitter in latency (us) */
+};
+
+struct tc_netem_corr {
+       __u32   delay_corr;     /* delay correlation */
+       __u32   loss_corr;      /* packet loss correlation */
+       __u32   dup_corr;       /* duplicate correlation  */
+};
+
+struct tc_netem_reorder {
+       __u32   probability;
+       __u32   correlation;
+};
+
+struct tc_netem_corrupt {
+       __u32   probability;
+       __u32   correlation;
+};
+
+enum {
+       NETEM_LOSS_UNSPEC,
+       NETEM_LOSS_GI,          /* General Intuitive - 4 state model */
+       NETEM_LOSS_GE,          /* Gilbert Elliot models */
+       __NETEM_LOSS_MAX
+};
+#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1)
+
+/* State transition probablities for 4 state model */
+struct tc_netem_gimodel {
+       __u32   p13;
+       __u32   p31;
+       __u32   p32;
+       __u32   p14;
+       __u32   p23;
+};
+
+/* Gilbert-Elliot models */
+struct tc_netem_gemodel {
+       __u32 p;
+       __u32 r;
+       __u32 h;
+       __u32 k1;
+};
+
+#define NETEM_DIST_SCALE       8192
+#define NETEM_DIST_MAX         16384
+
+/* DRR */
+
+enum {
+       TCA_DRR_UNSPEC,
+       TCA_DRR_QUANTUM,
+       __TCA_DRR_MAX
+};
+
+#define TCA_DRR_MAX    (__TCA_DRR_MAX - 1)
+
+struct tc_drr_stats {
+       __u32   deficit;
+};
+
+/* MQPRIO */
+#define TC_QOPT_BITMASK 15
+#define TC_QOPT_MAX_QUEUE 16
+
+struct tc_mqprio_qopt {
+       __u8    num_tc;
+       __u8    prio_tc_map[TC_QOPT_BITMASK + 1];
+       __u8    hw;
+       __u16   count[TC_QOPT_MAX_QUEUE];
+       __u16   offset[TC_QOPT_MAX_QUEUE];
+};
+
+/* SFB */
+
+enum {
+       TCA_SFB_UNSPEC,
+       TCA_SFB_PARMS,
+       __TCA_SFB_MAX,
+};
+
+#define TCA_SFB_MAX (__TCA_SFB_MAX - 1)
+
+/*
+ * Note: increment, decrement are Q0.16 fixed-point values.
+ */
+struct tc_sfb_qopt {
+       __u32 rehash_interval;  /* delay between hash move, in ms */
+       __u32 warmup_time;      /* double buffering warmup time in ms (warmup_time < rehash_interval) */
+       __u32 max;              /* max len of qlen_min */
+       __u32 bin_size;         /* maximum queue length per bin */
+       __u32 increment;        /* probability increment, (d1 in Blue) */
+       __u32 decrement;        /* probability decrement, (d2 in Blue) */
+       __u32 limit;            /* max SFB queue length */
+       __u32 penalty_rate;     /* inelastic flows are rate limited to 'rate' pps */
+       __u32 penalty_burst;
+};
+
+struct tc_sfb_xstats {
+       __u32 earlydrop;
+       __u32 penaltydrop;
+       __u32 bucketdrop;
+       __u32 queuedrop;
+       __u32 childdrop; /* drops in child qdisc */
+       __u32 marked;
+       __u32 maxqlen;
+       __u32 maxprob;
+       __u32 avgprob;
+};
+
+#define SFB_MAX_PROB 0xFFFF
+
+/* QFQ */
+enum {
+       TCA_QFQ_UNSPEC,
+       TCA_QFQ_WEIGHT,
+       TCA_QFQ_LMAX,
+       __TCA_QFQ_MAX
+};
+
+#define TCA_QFQ_MAX    (__TCA_QFQ_MAX - 1)
+
+struct tc_qfq_stats {
+       __u32 weight;
+       __u32 lmax;
+};
+
+#endif
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
new file mode 100644 (file)
index 0000000..2363c18
--- /dev/null
@@ -0,0 +1,605 @@
+#ifndef __LINUX_RTNETLINK_H
+#define __LINUX_RTNETLINK_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/if_link.h>
+#include <linux/if_addr.h>
+#include <linux/neighbour.h>
+
+/* rtnetlink families. Values up to 127 are reserved for real address
+ * families, values above 128 may be used arbitrarily.
+ */
+#define RTNL_FAMILY_IPMR               128
+#define RTNL_FAMILY_IP6MR              129
+#define RTNL_FAMILY_MAX                        129
+
+/****
+ *             Routing/neighbour discovery messages.
+ ****/
+
+/* Types of messages */
+
+enum {
+       RTM_BASE        = 16,
+#define RTM_BASE       RTM_BASE
+
+       RTM_NEWLINK     = 16,
+#define RTM_NEWLINK    RTM_NEWLINK
+       RTM_DELLINK,
+#define RTM_DELLINK    RTM_DELLINK
+       RTM_GETLINK,
+#define RTM_GETLINK    RTM_GETLINK
+       RTM_SETLINK,
+#define RTM_SETLINK    RTM_SETLINK
+
+       RTM_NEWADDR     = 20,
+#define RTM_NEWADDR    RTM_NEWADDR
+       RTM_DELADDR,
+#define RTM_DELADDR    RTM_DELADDR
+       RTM_GETADDR,
+#define RTM_GETADDR    RTM_GETADDR
+
+       RTM_NEWROUTE    = 24,
+#define RTM_NEWROUTE   RTM_NEWROUTE
+       RTM_DELROUTE,
+#define RTM_DELROUTE   RTM_DELROUTE
+       RTM_GETROUTE,
+#define RTM_GETROUTE   RTM_GETROUTE
+
+       RTM_NEWNEIGH    = 28,
+#define RTM_NEWNEIGH   RTM_NEWNEIGH
+       RTM_DELNEIGH,
+#define RTM_DELNEIGH   RTM_DELNEIGH
+       RTM_GETNEIGH,
+#define RTM_GETNEIGH   RTM_GETNEIGH
+
+       RTM_NEWRULE     = 32,
+#define RTM_NEWRULE    RTM_NEWRULE
+       RTM_DELRULE,
+#define RTM_DELRULE    RTM_DELRULE
+       RTM_GETRULE,
+#define RTM_GETRULE    RTM_GETRULE
+
+       RTM_NEWQDISC    = 36,
+#define RTM_NEWQDISC   RTM_NEWQDISC
+       RTM_DELQDISC,
+#define RTM_DELQDISC   RTM_DELQDISC
+       RTM_GETQDISC,
+#define RTM_GETQDISC   RTM_GETQDISC
+
+       RTM_NEWTCLASS   = 40,
+#define RTM_NEWTCLASS  RTM_NEWTCLASS
+       RTM_DELTCLASS,
+#define RTM_DELTCLASS  RTM_DELTCLASS
+       RTM_GETTCLASS,
+#define RTM_GETTCLASS  RTM_GETTCLASS
+
+       RTM_NEWTFILTER  = 44,
+#define RTM_NEWTFILTER RTM_NEWTFILTER
+       RTM_DELTFILTER,
+#define RTM_DELTFILTER RTM_DELTFILTER
+       RTM_GETTFILTER,
+#define RTM_GETTFILTER RTM_GETTFILTER
+
+       RTM_NEWACTION   = 48,
+#define RTM_NEWACTION   RTM_NEWACTION
+       RTM_DELACTION,
+#define RTM_DELACTION   RTM_DELACTION
+       RTM_GETACTION,
+#define RTM_GETACTION   RTM_GETACTION
+
+       RTM_NEWPREFIX   = 52,
+#define RTM_NEWPREFIX  RTM_NEWPREFIX
+
+       RTM_GETMULTICAST = 58,
+#define RTM_GETMULTICAST RTM_GETMULTICAST
+
+       RTM_GETANYCAST  = 62,
+#define RTM_GETANYCAST RTM_GETANYCAST
+
+       RTM_NEWNEIGHTBL = 64,
+#define RTM_NEWNEIGHTBL        RTM_NEWNEIGHTBL
+       RTM_GETNEIGHTBL = 66,
+#define RTM_GETNEIGHTBL        RTM_GETNEIGHTBL
+       RTM_SETNEIGHTBL,
+#define RTM_SETNEIGHTBL        RTM_SETNEIGHTBL
+
+       RTM_NEWNDUSEROPT = 68,
+#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT
+
+       RTM_NEWADDRLABEL = 72,
+#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL
+       RTM_DELADDRLABEL,
+#define RTM_DELADDRLABEL RTM_DELADDRLABEL
+       RTM_GETADDRLABEL,
+#define RTM_GETADDRLABEL RTM_GETADDRLABEL
+
+       RTM_GETDCB = 78,
+#define RTM_GETDCB RTM_GETDCB
+       RTM_SETDCB,
+#define RTM_SETDCB RTM_SETDCB
+
+       __RTM_MAX,
+#define RTM_MAX                (((__RTM_MAX + 3) & ~3) - 1)
+};
+
+#define RTM_NR_MSGTYPES        (RTM_MAX + 1 - RTM_BASE)
+#define RTM_NR_FAMILIES        (RTM_NR_MSGTYPES >> 2)
+#define RTM_FAM(cmd)   (((cmd) - RTM_BASE) >> 2)
+
+/* 
+   Generic structure for encapsulation of optional route information.
+   It is reminiscent of sockaddr, but with sa_family replaced
+   with attribute type.
+ */
+
+struct rtattr {
+       unsigned short  rta_len;
+       unsigned short  rta_type;
+};
+
+/* Macros to handle rtattributes */
+
+#define RTA_ALIGNTO    4
+#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
+#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \
+                        (rta)->rta_len >= sizeof(struct rtattr) && \
+                        (rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen)  ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+                                (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len)        (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
+#define RTA_DATA(rta)   ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
+
+
+
+
+/******************************************************************************
+ *             Definitions used in routing table administration.
+ ****/
+
+struct rtmsg {
+       unsigned char           rtm_family;
+       unsigned char           rtm_dst_len;
+       unsigned char           rtm_src_len;
+       unsigned char           rtm_tos;
+
+       unsigned char           rtm_table;      /* Routing table id */
+       unsigned char           rtm_protocol;   /* Routing protocol; see below  */
+       unsigned char           rtm_scope;      /* See below */ 
+       unsigned char           rtm_type;       /* See below    */
+
+       unsigned                rtm_flags;
+};
+
+/* rtm_type */
+
+enum {
+       RTN_UNSPEC,
+       RTN_UNICAST,            /* Gateway or direct route      */
+       RTN_LOCAL,              /* Accept locally               */
+       RTN_BROADCAST,          /* Accept locally as broadcast,
+                                  send as broadcast */
+       RTN_ANYCAST,            /* Accept locally as broadcast,
+                                  but send as unicast */
+       RTN_MULTICAST,          /* Multicast route              */
+       RTN_BLACKHOLE,          /* Drop                         */
+       RTN_UNREACHABLE,        /* Destination is unreachable   */
+       RTN_PROHIBIT,           /* Administratively prohibited  */
+       RTN_THROW,              /* Not in this table            */
+       RTN_NAT,                /* Translate this address       */
+       RTN_XRESOLVE,           /* Use external resolver        */
+       __RTN_MAX
+};
+
+#define RTN_MAX (__RTN_MAX - 1)
+
+
+/* rtm_protocol */
+
+#define RTPROT_UNSPEC  0
+#define RTPROT_REDIRECT        1       /* Route installed by ICMP redirects;
+                                  not used by current IPv4 */
+#define RTPROT_KERNEL  2       /* Route installed by kernel            */
+#define RTPROT_BOOT    3       /* Route installed during boot          */
+#define RTPROT_STATIC  4       /* Route installed by administrator     */
+
+/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
+   they are just passed from user and back as is.
+   It will be used by hypothetical multiple routing daemons.
+   Note that protocol values should be standardized in order to
+   avoid conflicts.
+ */
+
+#define RTPROT_GATED   8       /* Apparently, GateD */
+#define RTPROT_RA      9       /* RDISC/ND router advertisements */
+#define RTPROT_MRT     10      /* Merit MRT */
+#define RTPROT_ZEBRA   11      /* Zebra */
+#define RTPROT_BIRD    12      /* BIRD */
+#define RTPROT_DNROUTED        13      /* DECnet routing daemon */
+#define RTPROT_XORP    14      /* XORP */
+#define RTPROT_NTK     15      /* Netsukuku */
+#define RTPROT_DHCP    16      /* DHCP client */
+
+/* rtm_scope
+
+   Really it is not scope, but sort of distance to the destination.
+   NOWHERE are reserved for not existing destinations, HOST is our
+   local addresses, LINK are destinations, located on directly attached
+   link and UNIVERSE is everywhere in the Universe.
+
+   Intermediate values are also possible f.e. interior routes
+   could be assigned a value between UNIVERSE and LINK.
+*/
+
+enum rt_scope_t {
+       RT_SCOPE_UNIVERSE=0,
+/* User defined values  */
+       RT_SCOPE_SITE=200,
+       RT_SCOPE_LINK=253,
+       RT_SCOPE_HOST=254,
+       RT_SCOPE_NOWHERE=255
+};
+
+/* rtm_flags */
+
+#define RTM_F_NOTIFY           0x100   /* Notify user of route change  */
+#define RTM_F_CLONED           0x200   /* This route is cloned         */
+#define RTM_F_EQUALIZE         0x400   /* Multipath equalizer: NI      */
+#define RTM_F_PREFIX           0x800   /* Prefix addresses             */
+
+/* Reserved table identifiers */
+
+enum rt_class_t {
+       RT_TABLE_UNSPEC=0,
+/* User defined values */
+       RT_TABLE_COMPAT=252,
+       RT_TABLE_DEFAULT=253,
+       RT_TABLE_MAIN=254,
+       RT_TABLE_LOCAL=255,
+       RT_TABLE_MAX=0xFFFFFFFF
+};
+
+
+/* Routing message attributes */
+
+enum rtattr_type_t {
+       RTA_UNSPEC,
+       RTA_DST,
+       RTA_SRC,
+       RTA_IIF,
+       RTA_OIF,
+       RTA_GATEWAY,
+       RTA_PRIORITY,
+       RTA_PREFSRC,
+       RTA_METRICS,
+       RTA_MULTIPATH,
+       RTA_PROTOINFO, /* no longer used */
+       RTA_FLOW,
+       RTA_CACHEINFO,
+       RTA_SESSION, /* no longer used */
+       RTA_MP_ALGO, /* no longer used */
+       RTA_TABLE,
+       RTA_MARK,
+       __RTA_MAX
+};
+
+#define RTA_MAX (__RTA_MAX - 1)
+
+#define RTM_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
+#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
+
+/* RTM_MULTIPATH --- array of struct rtnexthop.
+ *
+ * "struct rtnexthop" describes all necessary nexthop information,
+ * i.e. parameters of path to a destination via this nexthop.
+ *
+ * At the moment it is impossible to set different prefsrc, mtu, window
+ * and rtt for different paths from multipath.
+ */
+
+struct rtnexthop {
+       unsigned short          rtnh_len;
+       unsigned char           rtnh_flags;
+       unsigned char           rtnh_hops;
+       int                     rtnh_ifindex;
+};
+
+/* rtnh_flags */
+
+#define RTNH_F_DEAD            1       /* Nexthop is dead (used by multipath)  */
+#define RTNH_F_PERVASIVE       2       /* Do recursive gateway lookup  */
+#define RTNH_F_ONLINK          4       /* Gateway is forced on link    */
+
+/* Macros to handle hexthops */
+
+#define RTNH_ALIGNTO   4
+#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) )
+#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \
+                          ((int)(rtnh)->rtnh_len) <= (len))
+#define RTNH_NEXT(rtnh)        ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len)))
+#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len))
+#define RTNH_SPACE(len)        RTNH_ALIGN(RTNH_LENGTH(len))
+#define RTNH_DATA(rtnh)   ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+
+/* RTM_CACHEINFO */
+
+struct rta_cacheinfo {
+       __u32   rta_clntref;
+       __u32   rta_lastuse;
+       __s32   rta_expires;
+       __u32   rta_error;
+       __u32   rta_used;
+
+#define RTNETLINK_HAVE_PEERINFO 1
+       __u32   rta_id;
+       __u32   rta_ts;
+       __u32   rta_tsage;
+};
+
+/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
+
+enum {
+       RTAX_UNSPEC,
+#define RTAX_UNSPEC RTAX_UNSPEC
+       RTAX_LOCK,
+#define RTAX_LOCK RTAX_LOCK
+       RTAX_MTU,
+#define RTAX_MTU RTAX_MTU
+       RTAX_WINDOW,
+#define RTAX_WINDOW RTAX_WINDOW
+       RTAX_RTT,
+#define RTAX_RTT RTAX_RTT
+       RTAX_RTTVAR,
+#define RTAX_RTTVAR RTAX_RTTVAR
+       RTAX_SSTHRESH,
+#define RTAX_SSTHRESH RTAX_SSTHRESH
+       RTAX_CWND,
+#define RTAX_CWND RTAX_CWND
+       RTAX_ADVMSS,
+#define RTAX_ADVMSS RTAX_ADVMSS
+       RTAX_REORDERING,
+#define RTAX_REORDERING RTAX_REORDERING
+       RTAX_HOPLIMIT,
+#define RTAX_HOPLIMIT RTAX_HOPLIMIT
+       RTAX_INITCWND,
+#define RTAX_INITCWND RTAX_INITCWND
+       RTAX_FEATURES,
+#define RTAX_FEATURES RTAX_FEATURES
+       RTAX_RTO_MIN,
+#define RTAX_RTO_MIN RTAX_RTO_MIN
+       RTAX_INITRWND,
+#define RTAX_INITRWND RTAX_INITRWND
+       __RTAX_MAX
+};
+
+#define RTAX_MAX (__RTAX_MAX - 1)
+
+#define RTAX_FEATURE_ECN       0x00000001
+#define RTAX_FEATURE_SACK      0x00000002
+#define RTAX_FEATURE_TIMESTAMP 0x00000004
+#define RTAX_FEATURE_ALLFRAG   0x00000008
+
+struct rta_session {
+       __u8    proto;
+       __u8    pad1;
+       __u16   pad2;
+
+       union {
+               struct {
+                       __u16   sport;
+                       __u16   dport;
+               } ports;
+
+               struct {
+                       __u8    type;
+                       __u8    code;
+                       __u16   ident;
+               } icmpt;
+
+               __u32           spi;
+       } u;
+};
+
+/****
+ *             General form of address family dependent message.
+ ****/
+
+struct rtgenmsg {
+       unsigned char           rtgen_family;
+};
+
+/*****************************************************************
+ *             Link layer specific messages.
+ ****/
+
+/* struct ifinfomsg
+ * passes link level specific information, not dependent
+ * on network protocol.
+ */
+
+struct ifinfomsg {
+       unsigned char   ifi_family;
+       unsigned char   __ifi_pad;
+       unsigned short  ifi_type;               /* ARPHRD_* */
+       int             ifi_index;              /* Link index   */
+       unsigned        ifi_flags;              /* IFF_* flags  */
+       unsigned        ifi_change;             /* IFF_* change mask */
+};
+
+/********************************************************************
+ *             prefix information 
+ ****/
+
+struct prefixmsg {
+       unsigned char   prefix_family;
+       unsigned char   prefix_pad1;
+       unsigned short  prefix_pad2;
+       int             prefix_ifindex;
+       unsigned char   prefix_type;
+       unsigned char   prefix_len;
+       unsigned char   prefix_flags;
+       unsigned char   prefix_pad3;
+};
+
+enum 
+{
+       PREFIX_UNSPEC,
+       PREFIX_ADDRESS,
+       PREFIX_CACHEINFO,
+       __PREFIX_MAX
+};
+
+#define PREFIX_MAX     (__PREFIX_MAX - 1)
+
+struct prefix_cacheinfo {
+       __u32   preferred_time;
+       __u32   valid_time;
+};
+
+
+/*****************************************************************
+ *             Traffic control messages.
+ ****/
+
+struct tcmsg {
+       unsigned char   tcm_family;
+       unsigned char   tcm__pad1;
+       unsigned short  tcm__pad2;
+       int             tcm_ifindex;
+       __u32           tcm_handle;
+       __u32           tcm_parent;
+       __u32           tcm_info;
+};
+
+enum {
+       TCA_UNSPEC,
+       TCA_KIND,
+       TCA_OPTIONS,
+       TCA_STATS,
+       TCA_XSTATS,
+       TCA_RATE,
+       TCA_FCNT,
+       TCA_STATS2,
+       TCA_STAB,
+       __TCA_MAX
+};
+
+#define TCA_MAX (__TCA_MAX - 1)
+
+#define TCA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
+#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
+
+/********************************************************************
+ *             Neighbor Discovery userland options
+ ****/
+
+struct nduseroptmsg {
+       unsigned char   nduseropt_family;
+       unsigned char   nduseropt_pad1;
+       unsigned short  nduseropt_opts_len;     /* Total length of options */
+       int             nduseropt_ifindex;
+       __u8            nduseropt_icmp_type;
+       __u8            nduseropt_icmp_code;
+       unsigned short  nduseropt_pad2;
+       unsigned int    nduseropt_pad3;
+       /* Followed by one or more ND options */
+};
+
+enum {
+       NDUSEROPT_UNSPEC,
+       NDUSEROPT_SRCADDR,
+       __NDUSEROPT_MAX
+};
+
+#define NDUSEROPT_MAX  (__NDUSEROPT_MAX - 1)
+
+#ifndef __KERNEL__
+/* RTnetlink multicast groups - backwards compatibility for userspace */
+#define RTMGRP_LINK            1
+#define RTMGRP_NOTIFY          2
+#define RTMGRP_NEIGH           4
+#define RTMGRP_TC              8
+
+#define RTMGRP_IPV4_IFADDR     0x10
+#define RTMGRP_IPV4_MROUTE     0x20
+#define RTMGRP_IPV4_ROUTE      0x40
+#define RTMGRP_IPV4_RULE       0x80
+
+#define RTMGRP_IPV6_IFADDR     0x100
+#define RTMGRP_IPV6_MROUTE     0x200
+#define RTMGRP_IPV6_ROUTE      0x400
+#define RTMGRP_IPV6_IFINFO     0x800
+
+#define RTMGRP_DECnet_IFADDR    0x1000
+#define RTMGRP_DECnet_ROUTE     0x4000
+
+#define RTMGRP_IPV6_PREFIX     0x20000
+#endif
+
+/* RTnetlink multicast groups */
+enum rtnetlink_groups {
+       RTNLGRP_NONE,
+#define RTNLGRP_NONE           RTNLGRP_NONE
+       RTNLGRP_LINK,
+#define RTNLGRP_LINK           RTNLGRP_LINK
+       RTNLGRP_NOTIFY,
+#define RTNLGRP_NOTIFY         RTNLGRP_NOTIFY
+       RTNLGRP_NEIGH,
+#define RTNLGRP_NEIGH          RTNLGRP_NEIGH
+       RTNLGRP_TC,
+#define RTNLGRP_TC             RTNLGRP_TC
+       RTNLGRP_IPV4_IFADDR,
+#define RTNLGRP_IPV4_IFADDR    RTNLGRP_IPV4_IFADDR
+       RTNLGRP_IPV4_MROUTE,
+#define        RTNLGRP_IPV4_MROUTE     RTNLGRP_IPV4_MROUTE
+       RTNLGRP_IPV4_ROUTE,
+#define RTNLGRP_IPV4_ROUTE     RTNLGRP_IPV4_ROUTE
+       RTNLGRP_IPV4_RULE,
+#define RTNLGRP_IPV4_RULE      RTNLGRP_IPV4_RULE
+       RTNLGRP_IPV6_IFADDR,
+#define RTNLGRP_IPV6_IFADDR    RTNLGRP_IPV6_IFADDR
+       RTNLGRP_IPV6_MROUTE,
+#define RTNLGRP_IPV6_MROUTE    RTNLGRP_IPV6_MROUTE
+       RTNLGRP_IPV6_ROUTE,
+#define RTNLGRP_IPV6_ROUTE     RTNLGRP_IPV6_ROUTE
+       RTNLGRP_IPV6_IFINFO,
+#define RTNLGRP_IPV6_IFINFO    RTNLGRP_IPV6_IFINFO
+       RTNLGRP_DECnet_IFADDR,
+#define RTNLGRP_DECnet_IFADDR  RTNLGRP_DECnet_IFADDR
+       RTNLGRP_NOP2,
+       RTNLGRP_DECnet_ROUTE,
+#define RTNLGRP_DECnet_ROUTE   RTNLGRP_DECnet_ROUTE
+       RTNLGRP_DECnet_RULE,
+#define RTNLGRP_DECnet_RULE    RTNLGRP_DECnet_RULE
+       RTNLGRP_NOP4,
+       RTNLGRP_IPV6_PREFIX,
+#define RTNLGRP_IPV6_PREFIX    RTNLGRP_IPV6_PREFIX
+       RTNLGRP_IPV6_RULE,
+#define RTNLGRP_IPV6_RULE      RTNLGRP_IPV6_RULE
+       RTNLGRP_ND_USEROPT,
+#define RTNLGRP_ND_USEROPT     RTNLGRP_ND_USEROPT
+       RTNLGRP_PHONET_IFADDR,
+#define RTNLGRP_PHONET_IFADDR  RTNLGRP_PHONET_IFADDR
+       RTNLGRP_PHONET_ROUTE,
+#define RTNLGRP_PHONET_ROUTE   RTNLGRP_PHONET_ROUTE
+       __RTNLGRP_MAX
+};
+#define RTNLGRP_MAX    (__RTNLGRP_MAX - 1)
+
+/* TC action piece */
+struct tcamsg {
+       unsigned char   tca_family;
+       unsigned char   tca__pad1;
+       unsigned short  tca__pad2;
+};
+#define TA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg))))
+#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg))
+#define TCA_ACT_TAB 1 /* attr type must be >=1 */      
+#define TCAA_MAX 1
+
+/* End of information exported to user level */
+
+#endif /* __LINUX_RTNETLINK_H */
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
new file mode 100644 (file)
index 0000000..12b2b18
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Definitions for MIBs
+ *
+ * Author: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
+ */
+
+#ifndef _LINUX_SNMP_H
+#define _LINUX_SNMP_H
+
+/* ipstats mib definitions */
+/*
+ * RFC 1213:  MIB-II
+ * RFC 2011 (updates 1213):  SNMPv2-MIB-IP
+ * RFC 2863:  Interfaces Group MIB
+ * RFC 2465:  IPv6 MIB: General Group
+ * draft-ietf-ipv6-rfc2011-update-10.txt: MIB for IP: IP Statistics Tables
+ */
+enum
+{
+       IPSTATS_MIB_NUM = 0,
+       IPSTATS_MIB_INPKTS,                     /* InReceives */
+       IPSTATS_MIB_INHDRERRORS,                /* InHdrErrors */
+       IPSTATS_MIB_INTOOBIGERRORS,             /* InTooBigErrors */
+       IPSTATS_MIB_INNOROUTES,                 /* InNoRoutes */
+       IPSTATS_MIB_INADDRERRORS,               /* InAddrErrors */
+       IPSTATS_MIB_INUNKNOWNPROTOS,            /* InUnknownProtos */
+       IPSTATS_MIB_INTRUNCATEDPKTS,            /* InTruncatedPkts */
+       IPSTATS_MIB_INDISCARDS,                 /* InDiscards */
+       IPSTATS_MIB_INDELIVERS,                 /* InDelivers */
+       IPSTATS_MIB_OUTFORWDATAGRAMS,           /* OutForwDatagrams */
+       IPSTATS_MIB_OUTPKTS,                    /* OutRequests */
+       IPSTATS_MIB_OUTDISCARDS,                /* OutDiscards */
+       IPSTATS_MIB_OUTNOROUTES,                /* OutNoRoutes */
+       IPSTATS_MIB_REASMTIMEOUT,               /* ReasmTimeout */
+       IPSTATS_MIB_REASMREQDS,                 /* ReasmReqds */
+       IPSTATS_MIB_REASMOKS,                   /* ReasmOKs */
+       IPSTATS_MIB_REASMFAILS,                 /* ReasmFails */
+       IPSTATS_MIB_FRAGOKS,                    /* FragOKs */
+       IPSTATS_MIB_FRAGFAILS,                  /* FragFails */
+       IPSTATS_MIB_FRAGCREATES,                /* FragCreates */
+       IPSTATS_MIB_INMCASTPKTS,                /* InMcastPkts */
+       IPSTATS_MIB_OUTMCASTPKTS,               /* OutMcastPkts */
+       IPSTATS_MIB_INBCASTPKTS,                /* InBcastPkts */
+       IPSTATS_MIB_OUTBCASTPKTS,               /* OutBcastPkts */
+       IPSTATS_MIB_INOCTETS,                   /* InOctets */
+       IPSTATS_MIB_OUTOCTETS,                  /* OutOctets */
+       IPSTATS_MIB_INMCASTOCTETS,              /* InMcastOctets */
+       IPSTATS_MIB_OUTMCASTOCTETS,             /* OutMcastOctets */
+       IPSTATS_MIB_INBCASTOCTETS,              /* InBcastOctets */
+       IPSTATS_MIB_OUTBCASTOCTETS,             /* OutBcastOctets */
+       __IPSTATS_MIB_MAX
+};
+
+/* icmp mib definitions */
+/*
+ * RFC 1213:  MIB-II ICMP Group
+ * RFC 2011 (updates 1213):  SNMPv2 MIB for IP: ICMP group
+ */
+enum
+{
+       ICMP_MIB_NUM = 0,
+       ICMP_MIB_INMSGS,                        /* InMsgs */
+       ICMP_MIB_INERRORS,                      /* InErrors */
+       ICMP_MIB_INDESTUNREACHS,                /* InDestUnreachs */
+       ICMP_MIB_INTIMEEXCDS,                   /* InTimeExcds */
+       ICMP_MIB_INPARMPROBS,                   /* InParmProbs */
+       ICMP_MIB_INSRCQUENCHS,                  /* InSrcQuenchs */
+       ICMP_MIB_INREDIRECTS,                   /* InRedirects */
+       ICMP_MIB_INECHOS,                       /* InEchos */
+       ICMP_MIB_INECHOREPS,                    /* InEchoReps */
+       ICMP_MIB_INTIMESTAMPS,                  /* InTimestamps */
+       ICMP_MIB_INTIMESTAMPREPS,               /* InTimestampReps */
+       ICMP_MIB_INADDRMASKS,                   /* InAddrMasks */
+       ICMP_MIB_INADDRMASKREPS,                /* InAddrMaskReps */
+       ICMP_MIB_OUTMSGS,                       /* OutMsgs */
+       ICMP_MIB_OUTERRORS,                     /* OutErrors */
+       ICMP_MIB_OUTDESTUNREACHS,               /* OutDestUnreachs */
+       ICMP_MIB_OUTTIMEEXCDS,                  /* OutTimeExcds */
+       ICMP_MIB_OUTPARMPROBS,                  /* OutParmProbs */
+       ICMP_MIB_OUTSRCQUENCHS,                 /* OutSrcQuenchs */
+       ICMP_MIB_OUTREDIRECTS,                  /* OutRedirects */
+       ICMP_MIB_OUTECHOS,                      /* OutEchos */
+       ICMP_MIB_OUTECHOREPS,                   /* OutEchoReps */
+       ICMP_MIB_OUTTIMESTAMPS,                 /* OutTimestamps */
+       ICMP_MIB_OUTTIMESTAMPREPS,              /* OutTimestampReps */
+       ICMP_MIB_OUTADDRMASKS,                  /* OutAddrMasks */
+       ICMP_MIB_OUTADDRMASKREPS,               /* OutAddrMaskReps */
+       __ICMP_MIB_MAX
+};
+
+#define __ICMPMSG_MIB_MAX 512  /* Out+In for all 8-bit ICMP types */
+
+/* icmp6 mib definitions */
+/*
+ * RFC 2466:  ICMPv6-MIB
+ */
+enum
+{
+       ICMP6_MIB_NUM = 0,
+       ICMP6_MIB_INMSGS,                       /* InMsgs */
+       ICMP6_MIB_INERRORS,                     /* InErrors */
+       ICMP6_MIB_OUTMSGS,                      /* OutMsgs */
+       ICMP6_MIB_OUTERRORS,                    /* OutErrors */
+       __ICMP6_MIB_MAX
+};
+
+#define __ICMP6MSG_MIB_MAX 512 /* Out+In for all 8-bit ICMPv6 types */
+
+/* tcp mib definitions */
+/*
+ * RFC 1213:  MIB-II TCP group
+ * RFC 2012 (updates 1213):  SNMPv2-MIB-TCP
+ */
+enum
+{
+       TCP_MIB_NUM = 0,
+       TCP_MIB_RTOALGORITHM,                   /* RtoAlgorithm */
+       TCP_MIB_RTOMIN,                         /* RtoMin */
+       TCP_MIB_RTOMAX,                         /* RtoMax */
+       TCP_MIB_MAXCONN,                        /* MaxConn */
+       TCP_MIB_ACTIVEOPENS,                    /* ActiveOpens */
+       TCP_MIB_PASSIVEOPENS,                   /* PassiveOpens */
+       TCP_MIB_ATTEMPTFAILS,                   /* AttemptFails */
+       TCP_MIB_ESTABRESETS,                    /* EstabResets */
+       TCP_MIB_CURRESTAB,                      /* CurrEstab */
+       TCP_MIB_INSEGS,                         /* InSegs */
+       TCP_MIB_OUTSEGS,                        /* OutSegs */
+       TCP_MIB_RETRANSSEGS,                    /* RetransSegs */
+       TCP_MIB_INERRS,                         /* InErrs */
+       TCP_MIB_OUTRSTS,                        /* OutRsts */
+       __TCP_MIB_MAX
+};
+
+/* udp mib definitions */
+/*
+ * RFC 1213:  MIB-II UDP group
+ * RFC 2013 (updates 1213):  SNMPv2-MIB-UDP
+ */
+enum
+{
+       UDP_MIB_NUM = 0,
+       UDP_MIB_INDATAGRAMS,                    /* InDatagrams */
+       UDP_MIB_NOPORTS,                        /* NoPorts */
+       UDP_MIB_INERRORS,                       /* InErrors */
+       UDP_MIB_OUTDATAGRAMS,                   /* OutDatagrams */
+       UDP_MIB_RCVBUFERRORS,                   /* RcvbufErrors */
+       UDP_MIB_SNDBUFERRORS,                   /* SndbufErrors */
+       __UDP_MIB_MAX
+};
+
+/* linux mib definitions */
+enum
+{
+       LINUX_MIB_NUM = 0,
+       LINUX_MIB_SYNCOOKIESSENT,               /* SyncookiesSent */
+       LINUX_MIB_SYNCOOKIESRECV,               /* SyncookiesRecv */
+       LINUX_MIB_SYNCOOKIESFAILED,             /* SyncookiesFailed */
+       LINUX_MIB_EMBRYONICRSTS,                /* EmbryonicRsts */
+       LINUX_MIB_PRUNECALLED,                  /* PruneCalled */
+       LINUX_MIB_RCVPRUNED,                    /* RcvPruned */
+       LINUX_MIB_OFOPRUNED,                    /* OfoPruned */
+       LINUX_MIB_OUTOFWINDOWICMPS,             /* OutOfWindowIcmps */
+       LINUX_MIB_LOCKDROPPEDICMPS,             /* LockDroppedIcmps */
+       LINUX_MIB_ARPFILTER,                    /* ArpFilter */
+       LINUX_MIB_TIMEWAITED,                   /* TimeWaited */
+       LINUX_MIB_TIMEWAITRECYCLED,             /* TimeWaitRecycled */
+       LINUX_MIB_TIMEWAITKILLED,               /* TimeWaitKilled */
+       LINUX_MIB_PAWSPASSIVEREJECTED,          /* PAWSPassiveRejected */
+       LINUX_MIB_PAWSACTIVEREJECTED,           /* PAWSActiveRejected */
+       LINUX_MIB_PAWSESTABREJECTED,            /* PAWSEstabRejected */
+       LINUX_MIB_DELAYEDACKS,                  /* DelayedACKs */
+       LINUX_MIB_DELAYEDACKLOCKED,             /* DelayedACKLocked */
+       LINUX_MIB_DELAYEDACKLOST,               /* DelayedACKLost */
+       LINUX_MIB_LISTENOVERFLOWS,              /* ListenOverflows */
+       LINUX_MIB_LISTENDROPS,                  /* ListenDrops */
+       LINUX_MIB_TCPPREQUEUED,                 /* TCPPrequeued */
+       LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG,     /* TCPDirectCopyFromBacklog */
+       LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE,    /* TCPDirectCopyFromPrequeue */
+       LINUX_MIB_TCPPREQUEUEDROPPED,           /* TCPPrequeueDropped */
+       LINUX_MIB_TCPHPHITS,                    /* TCPHPHits */
+       LINUX_MIB_TCPHPHITSTOUSER,              /* TCPHPHitsToUser */
+       LINUX_MIB_TCPPUREACKS,                  /* TCPPureAcks */
+       LINUX_MIB_TCPHPACKS,                    /* TCPHPAcks */
+       LINUX_MIB_TCPRENORECOVERY,              /* TCPRenoRecovery */
+       LINUX_MIB_TCPSACKRECOVERY,              /* TCPSackRecovery */
+       LINUX_MIB_TCPSACKRENEGING,              /* TCPSACKReneging */
+       LINUX_MIB_TCPFACKREORDER,               /* TCPFACKReorder */
+       LINUX_MIB_TCPSACKREORDER,               /* TCPSACKReorder */
+       LINUX_MIB_TCPRENOREORDER,               /* TCPRenoReorder */
+       LINUX_MIB_TCPTSREORDER,                 /* TCPTSReorder */
+       LINUX_MIB_TCPFULLUNDO,                  /* TCPFullUndo */
+       LINUX_MIB_TCPPARTIALUNDO,               /* TCPPartialUndo */
+       LINUX_MIB_TCPDSACKUNDO,                 /* TCPDSACKUndo */
+       LINUX_MIB_TCPLOSSUNDO,                  /* TCPLossUndo */
+       LINUX_MIB_TCPLOSS,                      /* TCPLoss */
+       LINUX_MIB_TCPLOSTRETRANSMIT,            /* TCPLostRetransmit */
+       LINUX_MIB_TCPRENOFAILURES,              /* TCPRenoFailures */
+       LINUX_MIB_TCPSACKFAILURES,              /* TCPSackFailures */
+       LINUX_MIB_TCPLOSSFAILURES,              /* TCPLossFailures */
+       LINUX_MIB_TCPFASTRETRANS,               /* TCPFastRetrans */
+       LINUX_MIB_TCPFORWARDRETRANS,            /* TCPForwardRetrans */
+       LINUX_MIB_TCPSLOWSTARTRETRANS,          /* TCPSlowStartRetrans */
+       LINUX_MIB_TCPTIMEOUTS,                  /* TCPTimeouts */
+       LINUX_MIB_TCPRENORECOVERYFAIL,          /* TCPRenoRecoveryFail */
+       LINUX_MIB_TCPSACKRECOVERYFAIL,          /* TCPSackRecoveryFail */
+       LINUX_MIB_TCPSCHEDULERFAILED,           /* TCPSchedulerFailed */
+       LINUX_MIB_TCPRCVCOLLAPSED,              /* TCPRcvCollapsed */
+       LINUX_MIB_TCPDSACKOLDSENT,              /* TCPDSACKOldSent */
+       LINUX_MIB_TCPDSACKOFOSENT,              /* TCPDSACKOfoSent */
+       LINUX_MIB_TCPDSACKRECV,                 /* TCPDSACKRecv */
+       LINUX_MIB_TCPDSACKOFORECV,              /* TCPDSACKOfoRecv */
+       LINUX_MIB_TCPABORTONSYN,                /* TCPAbortOnSyn */
+       LINUX_MIB_TCPABORTONDATA,               /* TCPAbortOnData */
+       LINUX_MIB_TCPABORTONCLOSE,              /* TCPAbortOnClose */
+       LINUX_MIB_TCPABORTONMEMORY,             /* TCPAbortOnMemory */
+       LINUX_MIB_TCPABORTONTIMEOUT,            /* TCPAbortOnTimeout */
+       LINUX_MIB_TCPABORTONLINGER,             /* TCPAbortOnLinger */
+       LINUX_MIB_TCPABORTFAILED,               /* TCPAbortFailed */
+       LINUX_MIB_TCPMEMORYPRESSURES,           /* TCPMemoryPressures */
+       LINUX_MIB_TCPSACKDISCARD,               /* TCPSACKDiscard */
+       LINUX_MIB_TCPDSACKIGNOREDOLD,           /* TCPSACKIgnoredOld */
+       LINUX_MIB_TCPDSACKIGNOREDNOUNDO,        /* TCPSACKIgnoredNoUndo */
+       LINUX_MIB_TCPSPURIOUSRTOS,              /* TCPSpuriousRTOs */
+       LINUX_MIB_TCPMD5NOTFOUND,               /* TCPMD5NotFound */
+       LINUX_MIB_TCPMD5UNEXPECTED,             /* TCPMD5Unexpected */
+       LINUX_MIB_SACKSHIFTED,
+       LINUX_MIB_SACKMERGED,
+       LINUX_MIB_SACKSHIFTFALLBACK,
+       LINUX_MIB_TCPBACKLOGDROP,
+       LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
+       LINUX_MIB_TCPDEFERACCEPTDROP,
+       LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
+       LINUX_MIB_TCPTIMEWAITOVERFLOW,          /* TCPTimeWaitOverflow */
+       __LINUX_MIB_MAX
+};
+
+/* linux Xfrm mib definitions */
+enum
+{
+       LINUX_MIB_XFRMNUM = 0,
+       LINUX_MIB_XFRMINERROR,                  /* XfrmInError */
+       LINUX_MIB_XFRMINBUFFERERROR,            /* XfrmInBufferError */
+       LINUX_MIB_XFRMINHDRERROR,               /* XfrmInHdrError */
+       LINUX_MIB_XFRMINNOSTATES,               /* XfrmInNoStates */
+       LINUX_MIB_XFRMINSTATEPROTOERROR,        /* XfrmInStateProtoError */
+       LINUX_MIB_XFRMINSTATEMODEERROR,         /* XfrmInStateModeError */
+       LINUX_MIB_XFRMINSTATESEQERROR,          /* XfrmInStateSeqError */
+       LINUX_MIB_XFRMINSTATEEXPIRED,           /* XfrmInStateExpired */
+       LINUX_MIB_XFRMINSTATEMISMATCH,          /* XfrmInStateMismatch */
+       LINUX_MIB_XFRMINSTATEINVALID,           /* XfrmInStateInvalid */
+       LINUX_MIB_XFRMINTMPLMISMATCH,           /* XfrmInTmplMismatch */
+       LINUX_MIB_XFRMINNOPOLS,                 /* XfrmInNoPols */
+       LINUX_MIB_XFRMINPOLBLOCK,               /* XfrmInPolBlock */
+       LINUX_MIB_XFRMINPOLERROR,               /* XfrmInPolError */
+       LINUX_MIB_XFRMOUTERROR,                 /* XfrmOutError */
+       LINUX_MIB_XFRMOUTBUNDLEGENERROR,        /* XfrmOutBundleGenError */
+       LINUX_MIB_XFRMOUTBUNDLECHECKERROR,      /* XfrmOutBundleCheckError */
+       LINUX_MIB_XFRMOUTNOSTATES,              /* XfrmOutNoStates */
+       LINUX_MIB_XFRMOUTSTATEPROTOERROR,       /* XfrmOutStateProtoError */
+       LINUX_MIB_XFRMOUTSTATEMODEERROR,        /* XfrmOutStateModeError */
+       LINUX_MIB_XFRMOUTSTATESEQERROR,         /* XfrmOutStateSeqError */
+       LINUX_MIB_XFRMOUTSTATEEXPIRED,          /* XfrmOutStateExpired */
+       LINUX_MIB_XFRMOUTPOLBLOCK,              /* XfrmOutPolBlock */
+       LINUX_MIB_XFRMOUTPOLDEAD,               /* XfrmOutPolDead */
+       LINUX_MIB_XFRMOUTPOLERROR,              /* XfrmOutPolError */
+       LINUX_MIB_XFRMFWDHDRERROR,              /* XfrmFwdHdrError*/
+       __LINUX_MIB_XFRMMAX
+};
+
+#endif /* _LINUX_SNMP_H */
diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h
new file mode 100644 (file)
index 0000000..fe815e2
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef __LINUX_TC_EM_META_H
+#define __LINUX_TC_EM_META_H
+
+enum {
+       TCA_EM_META_UNSPEC,
+       TCA_EM_META_HDR,
+       TCA_EM_META_LVALUE,
+       TCA_EM_META_RVALUE,
+       __TCA_EM_META_MAX
+};
+#define TCA_EM_META_MAX (__TCA_EM_META_MAX - 1)
+
+struct tcf_meta_val {
+       __u16                   kind;
+       __u8                    shift;
+       __u8                    op;
+};
+
+#define TCF_META_TYPE_MASK     (0xf << 12)
+#define TCF_META_TYPE(kind)    (((kind) & TCF_META_TYPE_MASK) >> 12)
+#define TCF_META_ID_MASK       0x7ff
+#define TCF_META_ID(kind)      ((kind) & TCF_META_ID_MASK)
+
+enum {
+       TCF_META_TYPE_VAR,
+       TCF_META_TYPE_INT,
+       __TCF_META_TYPE_MAX
+};
+#define TCF_META_TYPE_MAX (__TCF_META_TYPE_MAX - 1)
+
+enum {
+       TCF_META_ID_VALUE,
+       TCF_META_ID_RANDOM,
+       TCF_META_ID_LOADAVG_0,
+       TCF_META_ID_LOADAVG_1,
+       TCF_META_ID_LOADAVG_2,
+       TCF_META_ID_DEV,
+       TCF_META_ID_PRIORITY,
+       TCF_META_ID_PROTOCOL,
+       TCF_META_ID_PKTTYPE,
+       TCF_META_ID_PKTLEN,
+       TCF_META_ID_DATALEN,
+       TCF_META_ID_MACLEN,
+       TCF_META_ID_NFMARK,
+       TCF_META_ID_TCINDEX,
+       TCF_META_ID_RTCLASSID,
+       TCF_META_ID_RTIIF,
+       TCF_META_ID_SK_FAMILY,
+       TCF_META_ID_SK_STATE,
+       TCF_META_ID_SK_REUSE,
+       TCF_META_ID_SK_BOUND_IF,
+       TCF_META_ID_SK_REFCNT,
+       TCF_META_ID_SK_SHUTDOWN,
+       TCF_META_ID_SK_PROTO,
+       TCF_META_ID_SK_TYPE,
+       TCF_META_ID_SK_RCVBUF,
+       TCF_META_ID_SK_RMEM_ALLOC,
+       TCF_META_ID_SK_WMEM_ALLOC,
+       TCF_META_ID_SK_OMEM_ALLOC,
+       TCF_META_ID_SK_WMEM_QUEUED,
+       TCF_META_ID_SK_RCV_QLEN,
+       TCF_META_ID_SK_SND_QLEN,
+       TCF_META_ID_SK_ERR_QLEN,
+       TCF_META_ID_SK_FORWARD_ALLOCS,
+       TCF_META_ID_SK_SNDBUF,
+       TCF_META_ID_SK_ALLOCS,
+       TCF_META_ID_SK_ROUTE_CAPS,
+       TCF_META_ID_SK_HASH,
+       TCF_META_ID_SK_LINGERTIME,
+       TCF_META_ID_SK_ACK_BACKLOG,
+       TCF_META_ID_SK_MAX_ACK_BACKLOG,
+       TCF_META_ID_SK_PRIO,
+       TCF_META_ID_SK_RCVLOWAT,
+       TCF_META_ID_SK_RCVTIMEO,
+       TCF_META_ID_SK_SNDTIMEO,
+       TCF_META_ID_SK_SENDMSG_OFF,
+       TCF_META_ID_SK_WRITE_PENDING,
+       TCF_META_ID_VLAN_TAG,
+       TCF_META_ID_RXHASH,
+       __TCF_META_ID_MAX
+};
+#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1)
+
+struct tcf_meta_hdr {
+       struct tcf_meta_val     left;
+       struct tcf_meta_val     right;
+};
+
+#endif
diff --git a/include/netlink-private/cache-api.h b/include/netlink-private/cache-api.h
new file mode 100644 (file)
index 0000000..f3d9f01
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * netlink-private/cache-api.h         Caching API
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CACHE_API_H_
+#define NETLINK_CACHE_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup cache
+ * @defgroup cache_api Cache Implementation
+ * @brief
+ *
+ * @par 1) Cache Definition
+ * @code
+ * struct nl_cache_ops my_cache_ops = {
+ *     .co_name                = "route/link",
+ *     .co_protocol            = NETLINK_ROUTE,
+ *     .co_hdrsize             = sizeof(struct ifinfomsg),
+ *     .co_obj_ops             = &my_obj_ops,
+ * };
+ * @endcode
+ *
+ * @par 2) 
+ * @code
+ * // The simplest way to fill a cache is by providing a request-update
+ * // function which must trigger a complete dump on the kernel-side of
+ * // whatever the cache covers.
+ * static int my_request_update(struct nl_cache *cache,
+ *                             struct nl_sock *socket)
+ * {
+ *     // In this example, we request a full dump of the interface table
+ *     return nl_rtgen_request(socket, RTM_GETLINK, AF_UNSPEC, NLM_F_DUMP);
+ * }
+ *
+ * // The resulting netlink messages sent back will be fed into a message
+ * // parser one at a time. The message parser has to extract all relevant
+ * // information from the message and create an object reflecting the
+ * // contents of the message and pass it on to the parser callback function
+ * // provide which will add the object to the cache.
+ * static int my_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ *                         struct nlmsghdr *nlh, struct nl_parser_param *pp)
+ * {
+ *     struct my_obj *obj;
+ *
+ *     obj = my_obj_alloc();
+ *     obj->ce_msgtype = nlh->nlmsg_type;
+ *
+ *     // Parse the netlink message and continue creating the object.
+ *
+ *     err = pp->pp_cb((struct nl_object *) obj, pp);
+ *     if (err < 0)
+ *             goto errout;
+ * }
+ *
+ * struct nl_cache_ops my_cache_ops = {
+ *     ...
+ *     .co_request_update      = my_request_update,
+ *     .co_msg_parser          = my_msg_parser,
+ * };
+ * @endcode
+ *
+ * @par 3) Notification based Updates
+ * @code
+ * // Caches can be kept up-to-date based on notifications if the kernel
+ * // sends out notifications whenever an object is added/removed/changed.
+ * //
+ * // It is trivial to support this, first a list of groups needs to be
+ * // defined which are required to join in order to receive all necessary
+ * // notifications. The groups are separated by address family to support
+ * // the common situation where a separate group is used for each address
+ * // family. If there is only one group, simply specify AF_UNSPEC.
+ * static struct nl_af_group addr_groups[] = {
+ *     { AF_INET,      RTNLGRP_IPV4_IFADDR },
+ *     { AF_INET6,     RTNLGRP_IPV6_IFADDR },
+ *     { END_OF_GROUP_LIST },
+ * };
+ *
+ * // In order for the caching system to know the meaning of each message
+ * // type it requires a table which maps each supported message type to
+ * // a cache action, e.g. RTM_NEWADDR means address has been added or
+ * // updated, RTM_DELADDR means address has been removed.
+ * static struct nl_cache_ops rtnl_addr_ops = {
+ *     ...
+ *     .co_msgtypes            = {
+ *                                     { RTM_NEWADDR, NL_ACT_NEW, "new" },
+ *                                     { RTM_DELADDR, NL_ACT_DEL, "del" },
+ *                                     { RTM_GETADDR, NL_ACT_GET, "get" },
+ *                                     END_OF_MSGTYPES_LIST,
+ *                             },
+ *     .co_groups              = addr_groups,
+ * };
+ *
+ * // It is now possible to keep the cache up-to-date using the cache manager.
+ * @endcode
+ * @{
+ */
+
+#define END_OF_MSGTYPES_LIST   { -1, -1, NULL }
+
+/**
+ * Message type to cache action association
+ */
+struct nl_msgtype
+{
+       /** Netlink message type */
+       int                     mt_id;
+
+       /** Cache action to take */
+       int                     mt_act;
+
+       /** Name of operation for human-readable printing */
+       char *                  mt_name;
+};
+
+/**
+ * Address family to netlink group association
+ */
+struct nl_af_group
+{
+       /** Address family */
+       int                     ag_family;
+
+       /** Netlink group identifier */
+       int                     ag_group;
+};
+
+#define END_OF_GROUP_LIST AF_UNSPEC, 0
+
+/**
+ * Parser parameters
+ *
+ * This structure is used to configure what kind of parser to use
+ * when parsing netlink messages to create objects.
+ */
+struct nl_parser_param
+{
+       /** Function to parse netlink messages into objects */
+       int             (*pp_cb)(struct nl_object *, struct nl_parser_param *);
+
+       /** Arbitary argument to be passed to the parser */
+       void *            pp_arg;
+};
+
+/**
+ * Cache Operations
+ *
+ * This structure defines the characterstics of a cache type. It contains
+ * pointers to functions which implement the specifics of the object type
+ * the cache can hold.
+ */
+struct nl_cache_ops
+{
+       /** Name of cache type (must be unique) */
+       char  *                 co_name;
+
+       /** Size of family specific netlink header */
+       int                     co_hdrsize;
+
+       /** Netlink protocol */
+       int                     co_protocol;
+
+       /** cache object hash size **/
+       int                     co_hash_size;
+
+       /** cache flags */
+       unsigned int            co_flags;
+
+       /** Reference counter */
+       unsigned int            co_refcnt;
+
+       /** Group definition */
+       struct nl_af_group *    co_groups;
+       
+       /**
+        * Called whenever an update of the cache is required. Must send
+        * a request message to the kernel requesting a complete dump.
+        */
+       int   (*co_request_update)(struct nl_cache *, struct nl_sock *);
+
+       /**
+        * Called whenever a message was received that needs to be parsed.
+        * Must parse the message and call the paser callback function
+        * (nl_parser_param) provided via the argument.
+        */
+       int   (*co_msg_parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+                              struct nlmsghdr *, struct nl_parser_param *);
+
+       /**
+        * The function registered under this callback is called after a
+        * netlink notification associated with this cache type has been
+        * parsed into an object and is being considered for inclusio into
+        * the specified cache.
+        *
+        * The purpose of this function is to filter out notifications
+        * which should be ignored when updating caches.
+        *
+        * The function must return NL_SKIP to prevent the object from
+        * being included, or NL_OK to include it.
+        *
+        * @code
+        * int my_filter(struct nl_cache *cache, struct nl_object *obj)
+        * {
+        *      if (reason_to_not_include_obj(obj))
+        *              return NL_SKIP;
+        *
+        *      return NL_OK;
+        * }
+        * @endcode
+        */
+       int   (*co_event_filter)(struct nl_cache *, struct nl_object *obj);
+
+       /**
+        * The function registered under this callback is called when an
+        * object formed from a notification event needs to be included in
+        * a cache.
+        *
+        * For each modified object, the change callback \c change_cb must
+        * be called with the \c data argument provided.
+        *
+        * If no function is registered, the function nl_cache_include()
+        * will be used for this purpose.
+        *
+        * @see nl_cache_include()
+        */
+       int   (*co_include_event)(struct nl_cache *cache, struct nl_object *obj,
+                                 change_func_t change_cb, void *data);
+
+       void (*reserved_1)(void);
+       void (*reserved_2)(void);
+       void (*reserved_3)(void);
+       void (*reserved_4)(void);
+       void (*reserved_5)(void);
+       void (*reserved_6)(void);
+       void (*reserved_7)(void);
+       void (*reserved_8)(void);
+
+       /** Object operations */
+       struct nl_object_ops *  co_obj_ops;
+
+       /** Internal, do not touch! */
+       struct nl_cache_ops *co_next;
+
+       struct nl_cache *co_major_cache;
+       struct genl_ops *       co_genl;
+
+       /* Message type definition */
+       struct nl_msgtype       co_msgtypes[];
+};
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink-private/genl.h b/include/netlink-private/genl.h
new file mode 100644 (file)
index 0000000..5b93db3
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * netlink-private/genl.h      Local Generic Netlink Interface
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_PRIV_H_
+#define NETLINK_GENL_PRIV_H_
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+
+#define GENL_HDRSIZE(hdrlen) (GENL_HDRLEN + (hdrlen))
+
+extern int             genl_resolve_id(struct genl_ops *ops);
+
+#endif
diff --git a/include/netlink-private/netlink.h b/include/netlink-private/netlink.h
new file mode 100644 (file)
index 0000000..2e511bf
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * netlink-private/netlink.h   Local Netlink Interface
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LOCAL_H_
+#define NETLINK_LOCAL_H_
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <limits.h>
+#include <search.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <defs.h>
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+#include <linux/types.h>
+
+/* local header copies */
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/ethtool.h>
+#include <linux/pkt_sched.h>
+#include <linux/pkt_cls.h>
+#include <linux/gen_stats.h>
+#include <linux/ip_mp_alg.h>
+#include <linux/atm.h>
+#include <linux/inetdevice.h>
+#include <linux/ipv6.h>
+#include <linux/snmp.h>
+
+#ifndef DISABLE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include <netlink/netlink.h>
+#include <netlink/handlers.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/cache-api.h>
+#include <netlink-private/types.h>
+
+struct trans_tbl {
+       int i;
+       const char *a;
+};
+
+#define __ADD(id, name) { .i = id, .a = #name },
+
+struct trans_list {
+       int i;
+       char *a;
+       struct nl_list_head list;
+};
+
+#ifdef NL_DEBUG
+#define NL_DBG(LVL,FMT,ARG...)                                         \
+       do {                                                            \
+               if (LVL <= nl_debug)                                    \
+                       fprintf(stderr,                                 \
+                               "DBG<" #LVL ">%20s:%-4u %s: " FMT,      \
+                               __FILE__, __LINE__,                     \
+                               __PRETTY_FUNCTION__, ##ARG);            \
+       } while (0)
+#else /* NL_DEBUG */
+#define NL_DBG(LVL,FMT,ARG...) do { } while(0)
+#endif /* NL_DEBUG */
+
+#define BUG()                                                          \
+       do {                                                            \
+               fprintf(stderr, "BUG at file position %s:%d:%s\n",      \
+                       __FILE__, __LINE__, __PRETTY_FUNCTION__);       \
+               assert(0);                                              \
+       } while (0)
+
+#define APPBUG(msg)                                                    \
+       do {                                                            \
+               fprintf(stderr, "APPLICATION BUG: %s:%d:%s: %s\n",      \
+                       __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);  \
+               assert(0);                                              \
+       } while(0)
+
+extern int __nl_read_num_str_file(const char *path,
+                                 int (*cb)(long, const char *));
+
+extern int __trans_list_add(int, const char *, struct nl_list_head *);
+extern void __trans_list_clear(struct nl_list_head *);
+
+extern char *__type2str(int, char *, size_t, const struct trans_tbl *, size_t);
+extern int __str2type(const char *, const struct trans_tbl *, size_t);
+
+extern char *__list_type2str(int, char *, size_t, struct nl_list_head *);
+extern int __list_str2type(const char *, struct nl_list_head *);
+
+extern char *__flags2str(int, char *, size_t, const struct trans_tbl *, size_t);
+extern int __str2flags(const char *, const struct trans_tbl *, size_t);
+
+extern void dump_from_ops(struct nl_object *, struct nl_dump_params *);
+
+static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
+{
+       return cb->cb_set[type](msg, cb->cb_args[type]);
+}
+
+#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
+
+/* This is also defined in stddef.h */
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#define __init __attribute__ ((constructor))
+#define __exit __attribute__ ((destructor))
+#undef __deprecated
+#define __deprecated __attribute__ ((deprecated))
+
+#define min(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+       typeof(x) _x = (x);     \
+       typeof(y) _y = (y);     \
+       (void) (&_x == &_y);            \
+       _x > _y ? _x : _y; })
+
+#define min_t(type,x,y) \
+       ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+       ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *,
+                         struct nlmsghdr *, struct nl_parser_param *);
+
+
+static inline void rtnl_copy_ratespec(struct rtnl_ratespec *dst,
+                                     struct tc_ratespec *src)
+{
+       dst->rs_cell_log = src->cell_log;
+       dst->rs_overhead = src->overhead;
+       dst->rs_cell_align = src->cell_align;
+       dst->rs_mpu = src->mpu;
+       dst->rs_rate = src->rate;
+}
+
+static inline void rtnl_rcopy_ratespec(struct tc_ratespec *dst,
+                                      struct rtnl_ratespec *src)
+{
+       dst->cell_log = src->rs_cell_log;
+       dst->overhead = src->rs_overhead;
+       dst->cell_align = src->rs_cell_align;
+       dst->mpu = src->rs_mpu;
+       dst->rate = src->rs_rate;
+}
+
+static inline char *nl_cache_name(struct nl_cache *cache)
+{
+       return cache->c_ops ? cache->c_ops->co_name : "unknown";
+}
+
+#define GENL_FAMILY(id, name) \
+       { \
+               { id, NL_ACT_UNSPEC, name }, \
+               END_OF_MSGTYPES_LIST, \
+       }
+
+static inline int wait_for_ack(struct nl_sock *sk)
+{
+       if (sk->s_flags & NL_NO_AUTO_ACK)
+               return 0;
+       else
+               return nl_wait_for_ack(sk);
+}
+
+static inline int build_sysconf_path(char **strp, const char *filename)
+{
+       char *sysconfdir;
+
+       sysconfdir = getenv("NLSYSCONFDIR");
+
+       if (!sysconfdir)
+               sysconfdir = SYSCONFDIR;
+
+       return asprintf(strp, "%s/%s", sysconfdir, filename);
+}
+
+#ifndef DISABLE_PTHREADS
+#define NL_LOCK(NAME) pthread_mutex_t (NAME) = PTHREAD_MUTEX_INITIALIZER
+#define NL_RW_LOCK(NAME) pthread_rwlock_t (NAME) = PTHREAD_RWLOCK_INITIALIZER
+
+static inline void nl_lock(pthread_mutex_t *lock)
+{
+       pthread_mutex_lock(lock);
+}
+
+static inline void nl_unlock(pthread_mutex_t *lock)
+{
+       pthread_mutex_unlock(lock);
+}
+
+static inline void nl_read_lock(pthread_rwlock_t *lock)
+{
+       pthread_rwlock_rdlock(lock);
+}
+
+static inline void nl_read_unlock(pthread_rwlock_t *lock)
+{
+       pthread_rwlock_unlock(lock);
+}
+
+static inline void nl_write_lock(pthread_rwlock_t *lock)
+{
+       pthread_rwlock_wrlock(lock);
+}
+
+static inline void nl_write_unlock(pthread_rwlock_t *lock)
+{
+       pthread_rwlock_unlock(lock);
+}
+
+#else
+#define NL_LOCK(NAME) int __unused_lock_ ##NAME __attribute__((unused))
+#define NL_RW_LOCK(NAME) int __unused_lock_ ##NAME __attribute__((unused))
+
+#define nl_lock(LOCK) do { } while(0)
+#define nl_unlock(LOCK) do { } while(0)
+#define nl_read_lock(LOCK) do { } while(0)
+#define nl_read_unlock(LOCK) do { } while(0)
+#define nl_write_lock(LOCK) do { } while(0)
+#define nl_write_unlock(LOCK) do { } while(0)
+#endif
+
+#endif
diff --git a/include/netlink-private/object-api.h b/include/netlink-private/object-api.h
new file mode 100644 (file)
index 0000000..f4fd71e
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * netlink-private/object-api.c                Object API
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_OBJECT_API_H_
+#define NETLINK_OBJECT_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup object
+ * @defgroup object_api Object API
+ * @brief
+ *
+ * @par 1) Object Definition
+ * @code
+ * // Define your object starting with the common object header
+ * struct my_obj {
+ *     NLHDR_COMMON
+ *     int             my_data;
+ * };
+ *
+ * // Fill out the object operations structure
+ * struct nl_object_ops my_ops = {
+ *     .oo_name        = "my_obj",
+ *     .oo_size        = sizeof(struct my_obj),
+ * };
+ *
+ * // At this point the object can be allocated, you may want to provide a
+ * // separate _alloc() function to ease allocting objects of this kind.
+ * struct nl_object *obj = nl_object_alloc(&my_ops);
+ *
+ * // And release it again...
+ * nl_object_put(obj);
+ * @endcode
+ *
+ * @par 2) Allocating additional data
+ * @code
+ * // You may require to allocate additional data and store it inside
+ * // object, f.e. assuming there is a field `ptr'.
+ * struct my_obj {
+ *     NLHDR_COMMON
+ *     void *          ptr;
+ * };
+ *
+ * // And at some point you may assign allocated data to this field:
+ * my_obj->ptr = calloc(1, ...);
+ *
+ * // In order to not introduce any memory leaks you have to release
+ * // this data again when the last reference is given back.
+ * static void my_obj_free_data(struct nl_object *obj)
+ * {
+ *     struct my_obj *my_obj = nl_object_priv(obj);
+ *
+ *     free(my_obj->ptr);
+ * }
+ *
+ * // Also when the object is cloned, you must ensure for your pointer
+ * // stay valid even if one of the clones is freed by either making
+ * // a clone as well or increase the reference count.
+ * static int my_obj_clone(struct nl_object *src, struct nl_object *dst)
+ * {
+ *     struct my_obj *my_src = nl_object_priv(src);
+ *     struct my_obj *my_dst = nl_object_priv(dst);
+ *
+ *     if (src->ptr) {
+ *             dst->ptr = calloc(1, ...);
+ *             memcpy(dst->ptr, src->ptr, ...);
+ *     }
+ * }
+ *
+ * struct nl_object_ops my_ops = {
+ *     ...
+ *     .oo_free_data   = my_obj_free_data,
+ *     .oo_clone       = my_obj_clone,
+ * };
+ * @endcode
+ *
+ * @par 3) Object Dumping
+ * @code
+ * static int my_obj_dump_detailed(struct nl_object *obj,
+ *                                struct nl_dump_params *params)
+ * {
+ *     struct my_obj *my_obj = nl_object_priv(obj);
+ *
+ *     // It is absolutely essential to use nl_dump() when printing
+ *     // any text to make sure the dumping parameters are respected.
+ *     nl_dump(params, "Obj Integer: %d\n", my_obj->my_int);
+ *
+ *     // Before we can dump the next line, make sure to prefix
+ *     // this line correctly.
+ *     nl_new_line(params);
+ *
+ *     // You may also split a line into multiple nl_dump() calls.
+ *     nl_dump(params, "String: %s ", my_obj->my_string);
+ *     nl_dump(params, "String-2: %s\n", my_obj->another_string);
+ * }
+ *
+ * struct nl_object_ops my_ops = {
+ *     ...
+ *     .oo_dump[NL_DUMP_FULL]  = my_obj_dump_detailed,
+ * };
+ * @endcode
+ *
+ * @par 4) Object Attributes
+ * @code
+ * // The concept of object attributes is optional but can ease the typical
+ * // case of objects that have optional attributes, e.g. a route may have a
+ * // nexthop assigned but it is not required to.
+ *
+ * // The first step to define your object specific bitmask listing all
+ * // attributes
+ * #define MY_ATTR_FOO         (1<<0)
+ * #define MY_ATTR_BAR         (1<<1)
+ *
+ * // When assigning an optional attribute to the object, make sure
+ * // to mark its availability.
+ * my_obj->foo = 123123;
+ * my_obj->ce_mask |= MY_ATTR_FOO;
+ *
+ * // At any time you may use this mask to check for the availability
+ * // of the attribute, e.g. while dumping
+ * if (my_obj->ce_mask & MY_ATTR_FOO)
+ *     nl_dump(params, "foo %d ", my_obj->foo);
+ *
+ * // One of the big advantages of this concept is that it allows for
+ * // standardized comparisons which make it trivial for caches to
+ * // identify unique objects by use of unified comparison functions.
+ * // In order for it to work, your object implementation must provide
+ * // a comparison function and define a list of attributes which
+ * // combined together make an object unique.
+ *
+ * static int my_obj_compare(struct nl_object *_a, struct nl_object *_b,
+ *                          uint32_t attrs, int flags)
+ * {
+ *     struct my_obj *a = nl_object_priv(_a):
+ *     struct my_obj *b = nl_object_priv(_b):
+ *     int diff = 0;
+ *
+ *     // We help ourselves in defining our own DIFF macro which will
+ *     // call ATTR_DIFF() on both objects which will make sure to only
+ *     // compare the attributes if required.
+ *     #define MY_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MY_ATTR_##ATTR, a, b, EXPR)
+ *
+ *     // Call our own diff macro for each attribute to build a bitmask
+ *     // representing the attributes which mismatch.
+ *     diff |= MY_DIFF(FOO, a->foo != b->foo)
+ *     diff |= MY_DIFF(BAR, strcmp(a->bar, b->bar))
+ *
+ *     return diff;
+ * }
+ *
+ * // In order to identify identical objects with differing attributes
+ * // you must specify the attributes required to uniquely identify
+ * // your object. Make sure to not include too many attributes, this
+ * // list is used when caches look for an old version of an object.
+ * struct nl_object_ops my_ops = {
+ *     ...
+ *     .oo_id_attrs            = MY_ATTR_FOO,
+ *     .oo_compare             = my_obj_compare,
+ * };
+ * @endcode
+ * @{
+ */
+
+/**
+ * Common Object Header
+ *
+ * This macro must be included as first member in every object
+ * definition to allow objects to be cached.
+ */
+#define NLHDR_COMMON                           \
+       int                     ce_refcnt;      \
+       struct nl_object_ops *  ce_ops;         \
+       struct nl_cache *       ce_cache;       \
+       struct nl_list_head     ce_list;        \
+       int                     ce_msgtype;     \
+       int                     ce_flags;       \
+       uint32_t                ce_mask;
+
+struct nl_object
+{
+       NLHDR_COMMON
+};
+
+
+/**
+ * Return true if attribute is available in both objects
+ * @arg A              an object
+ * @arg B              another object
+ * @arg ATTR           attribute bit
+ *
+ * @return True if the attribute is available, otherwise false is returned.
+ */
+#define AVAILABLE(A, B, ATTR)          (((A)->ce_mask & (B)->ce_mask) & (ATTR))
+
+/**
+ * Return true if attribute is available in only one of both objects
+ * @arg A              an object
+ * @arg B              another object
+ * @arg ATTR           attribute bit
+ *
+ * @return True if the attribute is available in only one of both objects,
+ * otherwise false is returned.
+ */
+#define AVAILABLE_MISMATCH(A, B, ATTR) (((A)->ce_mask ^ (B)->ce_mask) & (ATTR))
+
+/**
+ * Return true if attributes mismatch
+ * @arg A              an object
+ * @arg B              another object
+ * @arg ATTR           attribute bit
+ * @arg EXPR           Comparison expression
+ *
+ * This function will check if the attribute in question is available
+ * in both objects, if not this will count as a mismatch.
+ *
+ * If available the function will execute the expression which must
+ * return true if the attributes mismatch.
+ *
+ * @return True if the attribute mismatch, or false if they match.
+ */
+#define ATTR_MISMATCH(A, B, ATTR, EXPR)        (AVAILABLE_MISMATCH(A, B, ATTR) || \
+                                        (AVAILABLE(A, B, ATTR) && (EXPR)))
+
+/**
+ * Return attribute bit if attribute does not match
+ * @arg LIST           list of attributes to be compared
+ * @arg ATTR           attribute bit
+ * @arg A              an object
+ * @arg B              another object
+ * @arg EXPR           Comparison expression
+ *
+ * This function will check if the attribute in question is available
+ * in both objects, if not this will count as a mismatch.
+ *
+ * If available the function will execute the expression which must
+ * return true if the attributes mismatch.
+ *
+ * In case the attributes mismatch, the attribute is returned, otherwise
+ * 0 is returned.
+ *
+ * @code
+ * diff |= ATTR_DIFF(attrs, MY_ATTR_FOO, a, b, a->foo != b->foo);
+ * @endcode
+ */
+#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \
+({     int diff = 0; \
+       if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \
+               diff = ATTR; \
+       diff; })
+
+/**
+ * Object Operations
+ */
+struct nl_object_ops
+{
+       /**
+        * Unique name of object type
+        *
+        * Must be in the form family/name, e.g. "route/addr"
+        */
+       char *          oo_name;
+
+       /** Size of object including its header */
+       size_t          oo_size;
+
+       /* List of attributes needed to uniquely identify the object */
+       uint32_t        oo_id_attrs;
+
+       /**
+        * Constructor function
+        *
+        * Will be called when a new object of this type is allocated.
+        * Can be used to initialize members such as lists etc.
+        */
+       void  (*oo_constructor)(struct nl_object *);
+
+       /**
+        * Destructor function
+        *
+        * Will be called when an object is freed. Must free all
+        * resources which may have been allocated as part of this
+        * object.
+        */
+       void  (*oo_free_data)(struct nl_object *);
+
+       /**
+        * Cloning function
+        *
+        * Will be called when an object needs to be cloned. Please
+        * note that the generic object code will make an exact
+        * copy of the object first, therefore you only need to take
+        * care of members which require reference counting etc.
+        *
+        * May return a negative error code to abort cloning.
+        */
+       int  (*oo_clone)(struct nl_object *, struct nl_object *);
+
+       /**
+        * Dumping functions
+        *
+        * Will be called when an object is dumped. The implementations
+        * have to use nl_dump(), nl_dump_line(), and nl_new_line() to
+        * dump objects.
+        *
+        * The functions must return the number of lines printed.
+        */
+       void (*oo_dump[NL_DUMP_MAX+1])(struct nl_object *,
+                                      struct nl_dump_params *);
+
+       /**
+        * Comparison function
+        *
+        * Will be called when two objects of the same type are
+        * compared. It takes the two objects in question, an object
+        * specific bitmask defining which attributes should be
+        * compared and flags to control the behaviour.
+        *
+        * The function must return a bitmask with the relevant bit
+        * set for each attribute that mismatches.
+        */
+       int   (*oo_compare)(struct nl_object *, struct nl_object *,
+                           uint32_t, int);
+
+
+       /**
+        * update function
+        *
+        * Will be called when the object given by first argument
+        * needs to be updated with the contents of the second object
+        *
+        * The function must return 0 for success and error for failure
+        * to update. In case of failure its assumed that the original
+        * object is not touched
+        */
+       int   (*oo_update)(struct nl_object *, struct nl_object *);
+
+       /**
+        * Hash Key generator function
+        *
+        * When called returns a hash key for the object being
+        * referenced. This key will be used by higher level hash functions
+        * to build association lists. Each object type gets to specify
+        * it's own key formulation
+        */
+       void   (*oo_keygen)(struct nl_object *, uint32_t *, uint32_t);
+
+       char *(*oo_attrs2str)(int, char *, size_t);
+
+       /**
+        * Get key attributes by family function
+        */
+       uint32_t   (*oo_id_attrs_get)(struct nl_object *);
+};
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink-private/route/link/api.h b/include/netlink-private/route/link/api.h
new file mode 100644 (file)
index 0000000..bb98ccc
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * netlink-private/route/link/api.h    Link Modules API
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_API_H_
+#define NETLINK_LINK_API_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup link_api
+ *
+ * Available operations to modules implementing a link info type.
+ */
+struct rtnl_link_info_ops
+{
+       /** Name of link info type, must match name on kernel side */
+       char *          io_name;
+
+       /** Reference count, DO NOT MODIFY */
+       int             io_refcnt;
+
+       /** Called to assign an info type to a link.
+        * Has to allocate enough resources to hold attributes. Can
+        * use link->l_info to store a pointer. */
+       int           (*io_alloc)(struct rtnl_link *);
+
+       /** Called to parse the link info attribute.
+        * Must parse the attribute and assign all values to the link.
+        */
+       int           (*io_parse)(struct rtnl_link *,
+                                 struct nlattr *,
+                                 struct nlattr *);
+
+       /** Called when the link object is dumped.
+        * Must dump the info type specific attributes. */
+       void          (*io_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
+                                               struct nl_dump_params *);
+
+       /** Called when a link object is cloned.
+        * Must clone all info type specific attributes. */
+       int           (*io_clone)(struct rtnl_link *, struct rtnl_link *);
+
+       /** Called when construction a link netlink message.
+        * Must append all info type specific attributes to the message. */
+       int           (*io_put_attrs)(struct nl_msg *, struct rtnl_link *);
+
+       /** Called to release all resources previously allocated
+        * in either io_alloc() or io_parse(). */
+       void          (*io_free)(struct rtnl_link *);
+
+       struct nl_list_head             io_list;
+};
+
+extern struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *);
+extern void                    rtnl_link_info_ops_put(struct rtnl_link_info_ops *);
+extern int                     rtnl_link_register_info(struct rtnl_link_info_ops *);
+extern int                     rtnl_link_unregister_info(struct rtnl_link_info_ops *);
+
+
+/**
+ * @ingroup link_api
+ *
+ * Available operations to modules implementing a link address family.
+ */
+struct rtnl_link_af_ops
+{
+       /** The address family this operations set implements */
+       const unsigned int      ao_family;
+
+       /** Number of users of this operations, DO NOT MODIFY. */
+       int                     ao_refcnt;
+
+       /** Validation policy for IFLA_PROTINFO attribute. This pointer
+        * can be set to a nla_policy structure describing the minimal
+        * requirements the attribute must meet. Failure of meeting these
+        * requirements will result in a parsing error. */
+       const struct nla_policy *ao_protinfo_policy;
+
+       /** Called after address family has been assigned to link. Must
+        * allocate data buffer to hold address family specific data and
+        * store it in link->l_af_data. */
+       void *                (*ao_alloc)(struct rtnl_link *);
+
+       /** Called when the link is cloned, must allocate a clone of the
+        * address family specific buffer and return it. */
+       void *                (*ao_clone)(struct rtnl_link *, void *);
+
+       /** Called when the link gets freed. Must free all allocated data */
+       void                  (*ao_free)(struct rtnl_link *, void *);
+
+       /** Called if a IFLA_PROTINFO attribute needs to be parsed. Typically
+        * stores the parsed data in the address family specific buffer. */
+       int                   (*ao_parse_protinfo)(struct rtnl_link *,
+                                                  struct nlattr *, void *);
+
+       /** Called if a IFLA_AF_SPEC attribute needs to be parsed. Typically
+        * stores the parsed data in the address family specific buffer. */
+       int                   (*ao_parse_af)(struct rtnl_link *,
+                                            struct nlattr *, void *);
+
+       /** Called if a link message is sent to the kernel. Must append the
+        * link address family specific attributes to the message. */
+       int                   (*ao_fill_af)(struct rtnl_link *,
+                                           struct nl_msg *msg, void *);
+
+       /** Dump address family specific link attributes */
+       void                  (*ao_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
+                                                       struct nl_dump_params *,
+                                                       void *);
+
+       /** Comparison function
+        *
+        * Will be called when two links are compared for their af data. It
+        * takes two link objects in question, an object specific bitmask
+        * defining which attributes should be compared and flags to control
+        * the behaviour
+        *
+        * The function must return a bitmask with the relevant bit set for
+        * each attribute that mismatches
+        */
+       int                   (*ao_compare)(struct rtnl_link *,
+                                           struct rtnl_link *, int, uint32_t, int);
+};
+
+extern struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(unsigned int);
+extern void                    rtnl_link_af_ops_put(struct rtnl_link_af_ops *);
+extern void *                  rtnl_link_af_alloc(struct rtnl_link *,
+                                               const struct rtnl_link_af_ops *);
+extern void *                  rtnl_link_af_data(const struct rtnl_link *,
+                                               const struct rtnl_link_af_ops *);
+extern int                     rtnl_link_af_register(struct rtnl_link_af_ops *);
+extern int                     rtnl_link_af_unregister(struct rtnl_link_af_ops *);
+extern int                     rtnl_link_af_data_compare(struct rtnl_link *a,
+                                                         struct rtnl_link *b,
+                                                         int family);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink-private/route/tc-api.h b/include/netlink-private/route/tc-api.h
new file mode 100644 (file)
index 0000000..bf0c8a3
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * netlink-private/route/tc-api.h      Traffic Control API
+ *
+ *     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) 2011-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_TC_API_H_
+#define NETLINK_TC_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Traffic control object operations
+ * @ingroup tc
+ *
+ * This structure holds function pointers and settings implementing
+ * the features of each traffic control object implementation.
+ */
+struct rtnl_tc_ops
+{
+       /**
+        * Name of traffic control module
+        */
+       char *to_kind;
+
+       /**
+        * Type of traffic control object
+        */
+       enum rtnl_tc_type to_type;
+
+
+       /**
+        * Size of private data
+        */
+       size_t to_size;
+
+       /**
+        * Dump callbacks
+        */
+       void (*to_dump[NL_DUMP_MAX+1])(struct rtnl_tc *, void *,
+                                      struct nl_dump_params *);
+       /**
+        * Used to fill the contents of TCA_OPTIONS
+        */
+       int (*to_msg_fill)(struct rtnl_tc *, void *, struct nl_msg *);
+
+       /**
+        * Uesd to to fill tc related messages, unlike with to_msg_fill,
+        * the contents is not encapsulated with a TCA_OPTIONS nested
+        * attribute.
+        */
+       int (*to_msg_fill_raw)(struct rtnl_tc *, void *, struct nl_msg *);
+
+       /**
+        * TCA_OPTIONS message parser
+        */
+       int (*to_msg_parser)(struct rtnl_tc *, void *);
+
+       /**
+        * Called before a tc object is destroyed
+        */
+       void (*to_free_data)(struct rtnl_tc *, void *);
+
+       /**
+        * Called whenever a classifier object needs to be cloned
+        */
+       int (*to_clone)(void *, void *);
+
+       /**
+        * Internal, don't touch
+        */
+       struct nl_list_head to_list;
+};
+
+struct rtnl_tc_type_ops
+{
+       enum rtnl_tc_type tt_type;
+
+       char *tt_dump_prefix;
+
+       /**
+        * Dump callbacks
+        */
+       void (*tt_dump[NL_DUMP_MAX+1])(struct rtnl_tc *,
+                                       struct nl_dump_params *);
+};
+
+extern int                     rtnl_tc_msg_parse(struct nlmsghdr *,
+                                                 struct rtnl_tc *);
+extern int                     rtnl_tc_msg_build(struct rtnl_tc *, int,
+                                                 int, struct nl_msg **);
+
+extern void                    rtnl_tc_free_data(struct nl_object *);
+extern int                     rtnl_tc_clone(struct nl_object *,
+                                             struct nl_object *);
+extern void                    rtnl_tc_dump_line(struct nl_object *,
+                                                 struct nl_dump_params *);
+extern void                    rtnl_tc_dump_details(struct nl_object *,
+                                                    struct nl_dump_params *);
+extern void                    rtnl_tc_dump_stats(struct nl_object *,
+                                                  struct nl_dump_params *);
+extern int                     rtnl_tc_compare(struct nl_object *,
+                                               struct nl_object *,
+                                               uint32_t, int);
+
+extern void *                  rtnl_tc_data(struct rtnl_tc *);
+extern void *                  rtnl_tc_data_check(struct rtnl_tc *,
+                                                  struct rtnl_tc_ops *);
+
+extern struct rtnl_tc_ops *    rtnl_tc_lookup_ops(enum rtnl_tc_type,
+                                                  const char *);
+extern struct rtnl_tc_ops *    rtnl_tc_get_ops(struct rtnl_tc *);
+extern int                     rtnl_tc_register(struct rtnl_tc_ops *);
+extern void                    rtnl_tc_unregister(struct rtnl_tc_ops *);
+
+extern void                    rtnl_tc_type_register(struct rtnl_tc_type_ops *);
+extern void                    rtnl_tc_type_unregister(struct rtnl_tc_type_ops *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink-private/tc.h b/include/netlink-private/tc.h
new file mode 100644 (file)
index 0000000..182adaa
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * netlink-private/tc.h                Local Traffic Control Interface
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_TC_PRIV_H_
+#define NETLINK_TC_PRIV_H_
+
+#include <netlink-private/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TCA_ATTR_HANDLE                0x0001
+#define TCA_ATTR_PARENT                0x0002
+#define TCA_ATTR_IFINDEX       0x0004
+#define TCA_ATTR_KIND          0x0008
+#define TCA_ATTR_FAMILY                0x0010
+#define TCA_ATTR_INFO          0x0020
+#define TCA_ATTR_OPTS          0x0040
+#define TCA_ATTR_STATS         0x0080
+#define TCA_ATTR_XSTATS                0x0100
+#define TCA_ATTR_LINK          0x0200
+#define TCA_ATTR_MTU           0x0400
+#define TCA_ATTR_MPU           0x0800
+#define TCA_ATTR_OVERHEAD      0x1000
+#define TCA_ATTR_LINKTYPE      0x2000
+#define TCA_ATTR_MAX           TCA_ATTR_LINKTYPE
+
+extern int tca_parse(struct nlattr **, int, struct rtnl_tc *,
+                    struct nla_policy *);
+
+#define RTNL_TC_RTABLE_SIZE    256
+
+extern int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *,
+                                   uint32_t *);
+
+
+static inline void *tca_xstats(struct rtnl_tc *tca)
+{
+       return tca->tc_xstats->d_data;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
new file mode 100644 (file)
index 0000000..89f6418
--- /dev/null
@@ -0,0 +1,912 @@
+/*
+ * netlink-private/types.h     Netlink Types (Private)
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LOCAL_TYPES_H_
+#define NETLINK_LOCAL_TYPES_H_
+
+#include <netlink/list.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink-private/route/tc-api.h>
+
+#define NL_SOCK_BUFSIZE_SET    (1<<0)
+#define NL_SOCK_PASSCRED       (1<<1)
+#define NL_OWN_PORT            (1<<2)
+#define NL_MSG_PEEK            (1<<3)
+#define NL_NO_AUTO_ACK         (1<<4)
+
+#define NL_MSG_CRED_PRESENT 1
+
+struct nl_cache_ops;
+struct nl_sock;
+struct nl_object;
+struct nl_hash_table;
+
+struct nl_cb
+{
+       nl_recvmsg_msg_cb_t     cb_set[NL_CB_TYPE_MAX+1];
+       void *                  cb_args[NL_CB_TYPE_MAX+1];
+       
+       nl_recvmsg_err_cb_t     cb_err;
+       void *                  cb_err_arg;
+
+       /** May be used to replace nl_recvmsgs with your own implementation
+        * in all internal calls to nl_recvmsgs. */
+       int                     (*cb_recvmsgs_ow)(struct nl_sock *,
+                                                 struct nl_cb *);
+
+       /** Overwrite internal calls to nl_recv, must return the number of
+        * octets read and allocate a buffer for the received data. */
+       int                     (*cb_recv_ow)(struct nl_sock *,
+                                             struct sockaddr_nl *,
+                                             unsigned char **,
+                                             struct ucred **);
+
+       /** Overwrites internal calls to nl_send, must send the netlink
+        * message. */
+       int                     (*cb_send_ow)(struct nl_sock *,
+                                             struct nl_msg *);
+
+       int                     cb_refcnt;
+};
+
+struct nl_sock
+{
+       struct sockaddr_nl      s_local;
+       struct sockaddr_nl      s_peer;
+       int                     s_fd;
+       int                     s_proto;
+       unsigned int            s_seq_next;
+       unsigned int            s_seq_expect;
+       int                     s_flags;
+       struct nl_cb *          s_cb;
+       size_t                  s_bufsize;
+};
+
+struct nl_cache
+{
+       struct nl_list_head     c_items;
+       int                     c_nitems;
+       int                     c_iarg1;
+       int                     c_iarg2;
+       int                     c_refcnt;
+       unsigned int            c_flags;
+       struct nl_hash_table *  hashtable;
+       struct nl_cache_ops *   c_ops;
+};
+
+struct nl_cache_assoc
+{
+       struct nl_cache *       ca_cache;
+       change_func_t           ca_change;
+       void *                  ca_change_data;
+};
+
+struct nl_cache_mngr
+{
+       int                     cm_protocol;
+       int                     cm_flags;
+       int                     cm_nassocs;
+       struct nl_sock *        cm_sock;
+       struct nl_sock *        cm_sync_sock;
+       struct nl_cache_assoc * cm_assocs;
+};
+
+struct nl_parser_param;
+
+#define LOOSE_COMPARISON       1
+
+#define NL_OBJ_MARK            1
+
+struct nl_data
+{
+       size_t                  d_size;
+       void *                  d_data;
+};
+
+struct nl_addr
+{
+       int                     a_family;
+       unsigned int            a_maxsize;
+       unsigned int            a_len;
+       int                     a_prefixlen;
+       int                     a_refcnt;
+       char                    a_addr[0];
+};
+
+struct nl_msg
+{
+       int                     nm_protocol;
+       int                     nm_flags;
+       struct sockaddr_nl      nm_src;
+       struct sockaddr_nl      nm_dst;
+       struct ucred            nm_creds;
+       struct nlmsghdr *       nm_nlh;
+       size_t                  nm_size;
+       int                     nm_refcnt;
+};
+
+struct rtnl_link_map
+{
+       uint64_t lm_mem_start;
+       uint64_t lm_mem_end;
+       uint64_t lm_base_addr;
+       uint16_t lm_irq;
+       uint8_t  lm_dma;
+       uint8_t  lm_port;
+};
+
+#define IFQDISCSIZ     32
+
+struct rtnl_link
+{
+       NLHDR_COMMON
+
+       char                            l_name[IFNAMSIZ];
+       uint32_t                        l_family;
+       uint32_t                        l_arptype;
+       uint32_t                        l_index;
+       uint32_t                        l_flags;
+       uint32_t                        l_change;
+       uint32_t                        l_mtu;
+       uint32_t                        l_link;
+       uint32_t                        l_txqlen;
+       uint32_t                        l_weight;
+       uint32_t                        l_master;
+       struct nl_addr *                l_addr; 
+       struct nl_addr *                l_bcast;
+       char                            l_qdisc[IFQDISCSIZ];
+       struct rtnl_link_map            l_map;
+       uint64_t                        l_stats[RTNL_LINK_STATS_MAX+1];
+       uint32_t                        l_flag_mask;
+       uint32_t                        l_num_vf;
+       uint8_t                         l_operstate;
+       uint8_t                         l_linkmode;
+       /* 2 byte hole */
+       char *                          l_info_kind;
+       struct rtnl_link_info_ops *     l_info_ops;
+       void *                          l_af_data[AF_MAX];
+       void *                          l_info;
+       char *                          l_ifalias;
+       uint32_t                        l_promiscuity;
+       uint32_t                        l_num_tx_queues;
+       uint32_t                        l_num_rx_queues;
+       uint32_t                        l_group;
+       uint8_t                         l_carrier;
+       /* 3 byte hole */
+       struct rtnl_link_af_ops *       l_af_ops;
+};
+
+struct rtnl_ncacheinfo
+{
+       uint32_t nci_confirmed; /**< Time since neighbour validty was last confirmed */
+       uint32_t nci_used;      /**< Time since neighbour entry was last ued */
+       uint32_t nci_updated;   /**< Time since last update */
+       uint32_t nci_refcnt;    /**< Reference counter */
+};
+
+
+struct rtnl_neigh
+{
+       NLHDR_COMMON
+       uint32_t        n_family;
+       uint32_t        n_ifindex;
+       uint16_t        n_state;
+       uint8_t         n_flags;
+       uint8_t         n_type; 
+       struct nl_addr *n_lladdr;
+       struct nl_addr *n_dst;  
+       uint32_t        n_probes;
+       struct rtnl_ncacheinfo n_cacheinfo;
+       uint32_t                n_state_mask;
+       uint32_t                n_flag_mask;
+       uint32_t                n_master;
+};
+
+
+struct rtnl_addr_cacheinfo
+{
+       /* Preferred lifetime in seconds */
+       uint32_t aci_prefered;
+
+       /* Valid lifetime in seconds */
+       uint32_t aci_valid;
+
+       /* Timestamp of creation in 1/100s seince boottime */
+       uint32_t aci_cstamp;
+
+       /* Timestamp of last update in 1/100s since boottime */
+       uint32_t aci_tstamp;
+};
+
+struct rtnl_addr
+{
+       NLHDR_COMMON
+
+       uint8_t         a_family;
+       uint8_t         a_prefixlen;
+       uint8_t         a_flags;
+       uint8_t         a_scope;
+       uint32_t        a_ifindex;
+
+       struct nl_addr *a_peer; 
+       struct nl_addr *a_local;
+       struct nl_addr *a_bcast;
+       struct nl_addr *a_anycast;
+       struct nl_addr *a_multicast;
+
+       struct rtnl_addr_cacheinfo a_cacheinfo;
+       
+       char a_label[IFNAMSIZ];
+       uint32_t a_flag_mask;
+       struct rtnl_link *a_link;
+};
+
+struct rtnl_nexthop
+{
+       uint8_t                 rtnh_flags;
+       uint8_t                 rtnh_flag_mask;
+       uint8_t                 rtnh_weight;
+       /* 1 byte spare */
+       uint32_t                rtnh_ifindex;
+       struct nl_addr *        rtnh_gateway;
+       uint32_t                ce_mask; /* HACK to support attr macros */
+       struct nl_list_head     rtnh_list;
+       uint32_t                rtnh_realms;
+};
+
+struct rtnl_route
+{
+       NLHDR_COMMON
+
+       uint8_t                 rt_family;
+       uint8_t                 rt_dst_len;
+       uint8_t                 rt_src_len;
+       uint8_t                 rt_tos;
+       uint8_t                 rt_protocol;
+       uint8_t                 rt_scope;
+       uint8_t                 rt_type;
+       uint8_t                 rt_nmetrics;
+       uint32_t                rt_flags;
+       struct nl_addr *        rt_dst;
+       struct nl_addr *        rt_src;
+       uint32_t                rt_table;
+       uint32_t                rt_iif;
+       uint32_t                rt_prio;
+       uint32_t                rt_metrics[RTAX_MAX];
+       uint32_t                rt_metrics_mask;
+       uint32_t                rt_nr_nh;
+       struct nl_addr *        rt_pref_src;
+       struct nl_list_head     rt_nexthops;
+       struct rtnl_rtcacheinfo rt_cacheinfo;
+       uint32_t                rt_flag_mask;
+};
+
+struct rtnl_rule
+{
+       NLHDR_COMMON
+       uint8_t         r_family;
+       uint8_t         r_action;
+       uint8_t         r_dsfield; /* ipv4 only */
+       uint8_t         r_unused;
+       uint32_t        r_table;
+       uint32_t        r_flags;
+       uint32_t        r_prio;
+       uint32_t        r_mark;
+       uint32_t        r_mask;
+       uint32_t        r_goto;
+       uint32_t        r_flow; /* ipv4 only */
+       struct nl_addr *r_src;
+       struct nl_addr *r_dst;
+       char            r_iifname[IFNAMSIZ];
+       char            r_oifname[IFNAMSIZ];
+};
+
+struct rtnl_neightbl_parms
+{
+       /**
+        * Interface index of the device this parameter set is assigned
+        * to or 0 for the default set.
+        */
+       uint32_t                ntp_ifindex;
+
+       /**
+        * Number of references to this parameter set.
+        */
+       uint32_t                ntp_refcnt;
+
+       /**
+        * Queue length for pending arp requests, i.e. the number of
+        * packets which are accepted from other layers while the
+        * neighbour address is still being resolved
+        */
+       uint32_t                ntp_queue_len;
+
+       /**
+        * Number of requests to send to the user level ARP daemon.
+        * Specify 0 to disable.
+        */
+       uint32_t                ntp_app_probes;
+
+       /**
+        * Maximum number of retries for unicast solicitation.
+        */
+       uint32_t                ntp_ucast_probes;
+
+       /**
+        * Maximum number of retries for multicast solicitation.
+        */
+       uint32_t                ntp_mcast_probes;
+
+       /**
+        * Base value in milliseconds to ompute reachable time, see RFC2461.
+        */
+       uint64_t                ntp_base_reachable_time;
+
+       /**
+        * Actual reachable time (read-only)
+        */
+       uint64_t                ntp_reachable_time;     /* secs */
+
+       /**
+        * The time in milliseconds between retransmitted Neighbor
+        * Solicitation messages.
+        */
+       uint64_t                ntp_retrans_time;
+
+       /**
+        * Interval in milliseconds to check for stale neighbour
+        * entries.
+        */
+       uint64_t                ntp_gc_stale_time;      /* secs */
+
+       /**
+        * Delay in milliseconds for the first time probe if
+        * the neighbour is reachable.
+        */
+       uint64_t                ntp_probe_delay;        /* secs */
+
+       /**
+        * Maximum delay in milliseconds of an answer to a neighbour
+        * solicitation message.
+        */
+       uint64_t                ntp_anycast_delay;
+
+       /**
+        * Minimum age in milliseconds before a neighbour entry
+        * may be replaced.
+        */
+       uint64_t                ntp_locktime;
+
+       /**
+        * Delay in milliseconds before answering to an ARP request
+        * for which a proxy ARP entry exists.
+        */
+       uint64_t                ntp_proxy_delay;
+
+       /**
+        * Queue length for the delayed proxy arp requests.
+        */
+       uint32_t                ntp_proxy_qlen;
+       
+       /**
+        * Mask of available parameter attributes
+        */
+       uint32_t                ntp_mask;
+};
+
+#define NTBLNAMSIZ     32
+
+/**
+ * Neighbour table
+ * @ingroup neightbl
+ */
+struct rtnl_neightbl
+{
+       NLHDR_COMMON
+
+       char                    nt_name[NTBLNAMSIZ];
+       uint32_t                nt_family;
+       uint32_t                nt_gc_thresh1;
+       uint32_t                nt_gc_thresh2;
+       uint32_t                nt_gc_thresh3;
+       uint64_t                nt_gc_interval;
+       struct ndt_config       nt_config;
+       struct rtnl_neightbl_parms nt_parms;
+       struct ndt_stats        nt_stats;
+};
+
+struct rtnl_ratespec
+{
+       uint8_t                 rs_cell_log;
+       uint16_t                rs_overhead;
+       int16_t                 rs_cell_align;
+       uint16_t                rs_mpu;
+       uint32_t                rs_rate;
+};
+
+struct rtnl_tstats
+{
+       struct {
+               uint64_t            bytes;
+               uint64_t            packets;
+       } tcs_basic;
+
+       struct {
+               uint32_t            bps;
+               uint32_t            pps;
+       } tcs_rate_est;
+
+       struct {
+               uint32_t            qlen;
+               uint32_t            backlog;
+               uint32_t            drops;
+               uint32_t            requeues;
+               uint32_t            overlimits;
+       } tcs_queue;
+};
+
+#define TCKINDSIZ      32
+
+#define NL_TC_GENERIC(pre)                             \
+       NLHDR_COMMON                                    \
+       uint32_t                pre ##_family;          \
+       uint32_t                pre ##_ifindex;         \
+       uint32_t                pre ##_handle;          \
+       uint32_t                pre ##_parent;          \
+       uint32_t                pre ##_info;            \
+       uint32_t                pre ##_mtu;             \
+       uint32_t                pre ##_mpu;             \
+       uint32_t                pre ##_overhead;        \
+       uint32_t                pre ##_linktype;        \
+       char                    pre ##_kind[TCKINDSIZ]; \
+       struct nl_data *        pre ##_opts;            \
+       uint64_t                pre ##_stats[RTNL_TC_STATS_MAX+1]; \
+       struct nl_data *        pre ##_xstats;          \
+       struct nl_data *        pre ##_subdata;         \
+       struct rtnl_link *      pre ##_link;            \
+       struct rtnl_tc_ops *    pre ##_ops;             \
+       enum rtnl_tc_type       pre ##_type
+
+struct rtnl_tc
+{
+       NL_TC_GENERIC(tc);
+};
+
+struct rtnl_qdisc
+{
+       NL_TC_GENERIC(q);
+};
+
+struct rtnl_class
+{
+       NL_TC_GENERIC(c);
+};
+
+struct rtnl_cls
+{
+       NL_TC_GENERIC(c);
+       uint16_t                c_prio;
+       uint16_t                c_protocol;
+};
+
+struct rtnl_u32
+{
+       uint32_t                cu_divisor;
+       uint32_t                cu_hash;
+       uint32_t                cu_classid;
+       uint32_t                cu_link;
+       struct nl_data *        cu_pcnt;
+       struct nl_data *        cu_selector;
+       struct nl_data *        cu_act;
+       struct nl_data *        cu_police;
+       char                    cu_indev[IFNAMSIZ];
+       int                     cu_mask;
+};
+
+struct rtnl_cgroup
+{
+       struct rtnl_ematch_tree *cg_ematch;
+       int                     cg_mask;
+};
+
+struct rtnl_fw
+{
+       uint32_t                cf_classid;
+       struct nl_data *        cf_act;
+       struct nl_data *        cf_police;
+       char                    cf_indev[IFNAMSIZ];
+       uint32_t                cf_fwmask;
+       int                     cf_mask;
+};
+
+struct rtnl_ematch
+{
+       uint16_t                e_id;
+       uint16_t                e_kind;
+       uint16_t                e_flags;
+       uint16_t                e_index;
+       size_t                  e_datalen;
+
+       struct nl_list_head     e_childs;
+       struct nl_list_head     e_list;
+       struct rtnl_ematch_ops *e_ops;
+
+       void *                  e_data;
+};
+
+struct rtnl_ematch_tree
+{
+       uint16_t                et_progid;
+       struct nl_list_head     et_list;
+
+};
+
+struct rtnl_dsmark_qdisc
+{
+       uint16_t        qdm_indices;
+       uint16_t        qdm_default_index;
+       uint32_t        qdm_set_tc_index;
+       uint32_t        qdm_mask;
+};
+
+struct rtnl_dsmark_class
+{
+       uint8_t         cdm_bmask;
+       uint8_t         cdm_value;
+       uint32_t        cdm_mask;
+};
+
+struct rtnl_fifo
+{
+       uint32_t        qf_limit;
+       uint32_t        qf_mask;
+};
+
+struct rtnl_prio
+{
+       uint32_t        qp_bands;
+       uint8_t         qp_priomap[TC_PRIO_MAX+1];
+       uint32_t        qp_mask;
+};
+
+struct rtnl_tbf
+{
+       uint32_t                qt_limit;
+       struct rtnl_ratespec    qt_rate;
+       uint32_t                qt_rate_bucket;
+       uint32_t                qt_rate_txtime;
+       struct rtnl_ratespec    qt_peakrate;
+       uint32_t                qt_peakrate_bucket;
+       uint32_t                qt_peakrate_txtime;
+       uint32_t                qt_mask;
+};
+
+struct rtnl_sfq
+{
+       uint32_t        qs_quantum;
+       uint32_t        qs_perturb;
+       uint32_t        qs_limit;
+       uint32_t        qs_divisor;
+       uint32_t        qs_flows;
+       uint32_t        qs_mask;
+};
+
+struct rtnl_netem_corr
+{
+       uint32_t        nmc_delay;
+       uint32_t        nmc_loss;
+       uint32_t        nmc_duplicate;
+};
+
+struct rtnl_netem_reo
+{
+       uint32_t        nmro_probability;
+       uint32_t        nmro_correlation;
+};
+
+struct rtnl_netem_crpt
+{
+       uint32_t        nmcr_probability;
+       uint32_t        nmcr_correlation;
+};
+
+struct rtnl_netem_dist
+{
+       int16_t *       dist_data;
+       size_t          dist_size;
+};
+
+struct rtnl_netem
+{
+       uint32_t                qnm_latency;
+       uint32_t                qnm_limit;
+       uint32_t                qnm_loss;
+       uint32_t                qnm_gap;
+       uint32_t                qnm_duplicate;
+       uint32_t                qnm_jitter;
+       uint32_t                qnm_mask;
+       struct rtnl_netem_corr  qnm_corr;
+       struct rtnl_netem_reo   qnm_ro;
+       struct rtnl_netem_crpt  qnm_crpt;
+       struct rtnl_netem_dist  qnm_dist;
+};
+
+struct rtnl_htb_qdisc
+{
+       uint32_t                qh_rate2quantum;
+       uint32_t                qh_defcls;
+       uint32_t                qh_mask;
+       uint32_t                qh_direct_pkts;
+};
+
+struct rtnl_htb_class
+{
+       uint32_t                ch_prio;
+       struct rtnl_ratespec    ch_rate;
+       struct rtnl_ratespec    ch_ceil;
+       uint32_t                ch_rbuffer;
+       uint32_t                ch_cbuffer;
+       uint32_t                ch_quantum;
+       uint32_t                ch_mask;
+       uint32_t                ch_level;
+};
+
+struct rtnl_cbq
+{
+       struct tc_cbq_lssopt    cbq_lss;
+       struct tc_ratespec      cbq_rate;
+       struct tc_cbq_wrropt    cbq_wrr;
+       struct tc_cbq_ovl       cbq_ovl;
+       struct tc_cbq_fopt      cbq_fopt;
+       struct tc_cbq_police    cbq_police;
+};
+
+struct rtnl_red
+{
+       uint32_t        qr_limit;
+       uint32_t        qr_qth_min;
+       uint32_t        qr_qth_max;
+       uint8_t         qr_flags;
+       uint8_t         qr_wlog;
+       uint8_t         qr_plog;
+       uint8_t         qr_scell_log;
+       uint32_t        qr_mask;
+};
+
+struct rtnl_plug
+{
+       int             action;
+       uint32_t        limit;
+};
+
+struct flnl_request
+{
+       NLHDR_COMMON
+
+       struct nl_addr *        lr_addr;
+       uint32_t                lr_fwmark;
+       uint8_t                 lr_tos;
+       uint8_t                 lr_scope;
+       uint8_t                 lr_table;
+};
+
+
+struct flnl_result
+{
+       NLHDR_COMMON
+
+       struct flnl_request *   fr_req;
+       uint8_t                 fr_table_id;
+       uint8_t                 fr_prefixlen;
+       uint8_t                 fr_nh_sel;
+       uint8_t                 fr_type;
+       uint8_t                 fr_scope;
+       uint32_t                fr_error;
+};
+
+#define GENL_OP_HAS_POLICY     1
+#define GENL_OP_HAS_DOIT       2
+#define GENL_OP_HAS_DUMPIT     4
+
+struct genl_family_op
+{
+       uint32_t                o_id;
+       uint32_t                o_flags;
+
+       struct nl_list_head     o_list;
+};
+
+struct genl_family_grp {
+        struct genl_family      *family;        /* private */
+        struct nl_list_head     list;           /* private */
+        char                    name[GENL_NAMSIZ];
+        u_int32_t               id;
+};
+
+struct genl_family
+{
+       NLHDR_COMMON
+
+       uint16_t                gf_id;
+       char                    gf_name[GENL_NAMSIZ];
+       uint32_t                gf_version;
+       uint32_t                gf_hdrsize;
+       uint32_t                gf_maxattr;
+
+       struct nl_list_head     gf_ops;
+       struct nl_list_head     gf_mc_grps;
+};
+
+union nfnl_ct_proto
+{
+       struct {
+               uint16_t        src;
+               uint16_t        dst;
+       } port;
+       struct {
+               uint16_t        id;
+               uint8_t         type;
+               uint8_t         code;
+       } icmp;
+};
+
+struct nfnl_ct_dir {
+       struct nl_addr *        src;
+       struct nl_addr *        dst;
+       union nfnl_ct_proto     proto;
+       uint64_t                packets;
+       uint64_t                bytes;
+};
+
+union nfnl_ct_protoinfo {
+       struct {
+               uint8_t         state;
+       } tcp;
+};
+
+struct nfnl_ct {
+       NLHDR_COMMON
+
+       uint8_t                 ct_family;
+       uint8_t                 ct_proto;
+       union nfnl_ct_protoinfo ct_protoinfo;
+
+       uint32_t                ct_status;
+       uint32_t                ct_status_mask;
+       uint32_t                ct_timeout;
+       uint32_t                ct_mark;
+       uint32_t                ct_use;
+       uint32_t                ct_id;
+
+       struct nfnl_ct_dir      ct_orig;
+       struct nfnl_ct_dir      ct_repl;
+};
+
+union nfnl_exp_protodata {
+       struct {
+               uint16_t        src;
+               uint16_t        dst;
+       } port;
+       struct {
+               uint16_t        id;
+               uint8_t         type;
+               uint8_t         code;
+       } icmp;
+};
+
+// Allow for different master/expect l4 protocols
+struct nfnl_exp_proto
+{
+       uint8_t                                         l4protonum;
+       union nfnl_exp_protodata        l4protodata;
+};
+
+struct nfnl_exp_dir {
+       struct nl_addr *                src;
+       struct nl_addr *                dst;
+       struct nfnl_exp_proto   proto;
+};
+
+struct nfnl_exp {
+       NLHDR_COMMON
+
+       uint8_t                 exp_family;
+       uint32_t                exp_timeout;
+       uint32_t                exp_id;
+       uint16_t                exp_zone;
+       uint32_t                exp_class;
+       uint32_t                exp_flags;
+       char *                  exp_helper_name;
+       char *                  exp_fn;
+       uint8_t                 exp_nat_dir;
+
+       struct nfnl_exp_dir             exp_expect;
+       struct nfnl_exp_dir             exp_master;
+       struct nfnl_exp_dir             exp_mask;
+       struct nfnl_exp_dir             exp_nat;
+};
+
+struct nfnl_log {
+       NLHDR_COMMON
+
+       uint16_t                log_group;
+       uint8_t                 log_copy_mode;
+       uint32_t                log_copy_range;
+       uint32_t                log_flush_timeout;
+       uint32_t                log_alloc_size;
+       uint32_t                log_queue_threshold;
+       uint32_t                log_flags;
+       uint32_t                log_flag_mask;
+};
+
+struct nfnl_log_msg {
+       NLHDR_COMMON
+
+       uint8_t                 log_msg_family;
+       uint8_t                 log_msg_hook;
+       uint16_t                log_msg_hwproto;
+       uint32_t                log_msg_mark;
+       struct timeval          log_msg_timestamp;
+       uint32_t                log_msg_indev;
+       uint32_t                log_msg_outdev;
+       uint32_t                log_msg_physindev;
+       uint32_t                log_msg_physoutdev;
+       uint8_t                 log_msg_hwaddr[8];
+       int                     log_msg_hwaddr_len;
+       void *                  log_msg_payload;
+       int                     log_msg_payload_len;
+       char *                  log_msg_prefix;
+       uint32_t                log_msg_uid;
+       uint32_t                log_msg_gid;
+       uint32_t                log_msg_seq;
+       uint32_t                log_msg_seq_global;
+};
+
+struct nfnl_queue {
+       NLHDR_COMMON
+
+       uint16_t                queue_group;
+       uint32_t                queue_maxlen;
+       uint32_t                queue_copy_range;
+       uint8_t                 queue_copy_mode;
+};
+
+struct nfnl_queue_msg {
+       NLHDR_COMMON
+
+       uint16_t                queue_msg_group;
+       uint8_t                 queue_msg_family;
+       uint8_t                 queue_msg_hook;
+       uint16_t                queue_msg_hwproto;
+       uint32_t                queue_msg_packetid;
+       uint32_t                queue_msg_mark;
+       struct timeval          queue_msg_timestamp;
+       uint32_t                queue_msg_indev;
+       uint32_t                queue_msg_outdev;
+       uint32_t                queue_msg_physindev;
+       uint32_t                queue_msg_physoutdev;
+       uint8_t                 queue_msg_hwaddr[8];
+       int                     queue_msg_hwaddr_len;
+       void *                  queue_msg_payload;
+       int                     queue_msg_payload_len;
+       uint32_t                queue_msg_verdict;
+};
+
+struct ematch_quoted {
+       char *  data;
+       size_t  len;
+       int     index;
+};
+
+#endif
diff --git a/include/netlink/addr.h b/include/netlink/addr.h
new file mode 100644 (file)
index 0000000..db3e4c2
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * netlink/addr.h              Abstract Address
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ADDR_H_
+#define NETLINK_ADDR_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_addr;
+
+/* Creation */
+extern struct nl_addr *        nl_addr_alloc(size_t);
+extern struct nl_addr *        nl_addr_alloc_attr(struct nlattr *, int);
+extern struct nl_addr *        nl_addr_build(int, void *, size_t);
+extern int             nl_addr_parse(const char *, int, struct nl_addr **);
+extern struct nl_addr *        nl_addr_clone(struct nl_addr *);
+
+/* Usage Management */
+extern struct nl_addr *        nl_addr_get(struct nl_addr *);
+extern void            nl_addr_put(struct nl_addr *);
+extern int             nl_addr_shared(struct nl_addr *);
+
+extern int             nl_addr_cmp(struct nl_addr *, struct nl_addr *);
+extern int             nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
+extern int             nl_addr_iszero(struct nl_addr *);
+extern int             nl_addr_valid(char *, int);
+extern int             nl_addr_guess_family(struct nl_addr *);
+extern int             nl_addr_fill_sockaddr(struct nl_addr *,
+                                             struct sockaddr *, socklen_t *);
+extern int             nl_addr_info(struct nl_addr *, struct addrinfo **);
+extern int             nl_addr_resolve(struct nl_addr *, char *, size_t);
+
+/* Access Functions */
+extern void            nl_addr_set_family(struct nl_addr *, int);
+extern int             nl_addr_get_family(struct nl_addr *);
+extern int             nl_addr_set_binary_addr(struct nl_addr *, void *,
+                                               size_t);
+extern void *          nl_addr_get_binary_addr(struct nl_addr *);
+extern unsigned int    nl_addr_get_len(struct nl_addr *);
+extern void            nl_addr_set_prefixlen(struct nl_addr *, int);
+extern unsigned int    nl_addr_get_prefixlen(struct nl_addr *);
+
+/* Address Family Translations */
+extern char *          nl_af2str(int, char *, size_t);
+extern int             nl_str2af(const char *);
+
+/* Translations to Strings */
+extern char *          nl_addr2str(struct nl_addr *, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/attr.h b/include/netlink/attr.h
new file mode 100644 (file)
index 0000000..0ed3da3
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * netlink/attr.h              Netlink Attributes
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ATTR_H_
+#define NETLINK_ATTR_H_
+
+#include <netlink/netlink.h>
+#include <netlink/object.h>
+#include <netlink/addr.h>
+#include <netlink/data.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_msg;
+
+/**
+ * @name Basic Attribute Data Types
+ * @{
+ */
+
+/**
+ * @ingroup attr
+ * Basic attribute data types
+ *
+ * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
+ */
+enum {
+       NLA_UNSPEC,     /**< Unspecified type, binary data chunk */
+       NLA_U8,         /**< 8 bit integer */
+       NLA_U16,        /**< 16 bit integer */
+       NLA_U32,        /**< 32 bit integer */
+       NLA_U64,        /**< 64 bit integer */
+       NLA_STRING,     /**< NUL terminated character string */
+       NLA_FLAG,       /**< Flag */
+       NLA_MSECS,      /**< Micro seconds (64bit) */
+       NLA_NESTED,     /**< Nested attributes */
+       __NLA_TYPE_MAX,
+};
+
+#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
+
+/** @} */
+
+/**
+ * @ingroup attr
+ * Attribute validation policy.
+ *
+ * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
+ */
+struct nla_policy {
+       /** Type of attribute or NLA_UNSPEC */
+       uint16_t        type;
+
+       /** Minimal length of payload required */
+       uint16_t        minlen;
+
+       /** Maximal length of payload allowed */
+       uint16_t        maxlen;
+};
+
+/* Size calculations */
+extern int             nla_attr_size(int payload);
+extern int             nla_total_size(int payload);
+extern int             nla_padlen(int payload);
+
+/* Attribute parsing */
+extern int             nla_type(const struct nlattr *);
+extern void *          nla_data(const struct nlattr *);
+extern int             nla_len(const struct nlattr *);
+extern int             nla_ok(const struct nlattr *, int);
+extern struct nlattr * nla_next(const struct nlattr *, int *);
+extern int             nla_parse(struct nlattr **, int, struct nlattr *,
+                                 int, struct nla_policy *);
+extern int             nla_validate(struct nlattr *, int, int,
+                                    struct nla_policy *);
+extern struct nlattr * nla_find(struct nlattr *, int, int);
+
+/* Helper Functions */
+extern int             nla_memcpy(void *, struct nlattr *, int);
+extern size_t          nla_strlcpy(char *, const struct nlattr *, size_t);
+extern int             nla_memcmp(const struct nlattr *, const void *, size_t);
+extern int             nla_strcmp(const struct nlattr *, const char *);
+
+/* Unspecific attribute */
+extern struct nlattr * nla_reserve(struct nl_msg *, int, int);
+extern int             nla_put(struct nl_msg *, int, int, const void *);
+extern int             nla_put_data(struct nl_msg *, int, struct nl_data *);
+extern int             nla_put_addr(struct nl_msg *, int, struct nl_addr *);
+
+/* Integer attribute */
+extern uint8_t         nla_get_u8(struct nlattr *);
+extern int             nla_put_u8(struct nl_msg *, int, uint8_t);
+extern uint16_t                nla_get_u16(struct nlattr *);
+extern int             nla_put_u16(struct nl_msg *, int, uint16_t);
+extern uint32_t                nla_get_u32(struct nlattr *);
+extern int             nla_put_u32(struct nl_msg *, int, uint32_t);
+extern uint64_t                nla_get_u64(struct nlattr *);
+extern int             nla_put_u64(struct nl_msg *, int, uint64_t);
+
+/* String attribute */
+extern char *          nla_get_string(struct nlattr *);
+extern char *          nla_strdup(struct nlattr *);
+extern int             nla_put_string(struct nl_msg *, int, const char *);
+
+/* Flag attribute */
+extern int             nla_get_flag(struct nlattr *);
+extern int             nla_put_flag(struct nl_msg *, int);
+
+/* Msec attribute */
+extern unsigned long   nla_get_msecs(struct nlattr *);
+extern int             nla_put_msecs(struct nl_msg *, int, unsigned long);
+
+/* Attribute nesting */
+extern int             nla_put_nested(struct nl_msg *, int, struct nl_msg *);
+extern struct nlattr * nla_nest_start(struct nl_msg *, int);
+extern int             nla_nest_end(struct nl_msg *, struct nlattr *);
+extern void            nla_nest_cancel(struct nl_msg *, struct nlattr *);
+extern int             nla_parse_nested(struct nlattr **, int, struct nlattr *,
+                                        struct nla_policy *);
+extern int             nla_is_nested(struct nlattr *);
+
+/**
+ * @name Attribute Construction (Exception Based)
+ * @{
+ */
+
+/**
+ * @ingroup attr
+ * Add unspecific attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg attrlen                Length of attribute payload.
+ * @arg data           Head of attribute payload.
+ */
+#define NLA_PUT(msg, attrtype, attrlen, data) \
+       do { \
+               if (nla_put(msg, attrtype, attrlen, data) < 0) \
+                       goto nla_put_failure; \
+       } while(0)
+
+/**
+ * @ingroup attr
+ * Add atomic type attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg type           Atomic type.
+ * @arg attrtype       Attribute type.
+ * @arg value          Head of attribute payload.
+ */
+#define NLA_PUT_TYPE(msg, type, attrtype, value) \
+       do { \
+               type __tmp = value; \
+               NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \
+       } while(0)
+
+/**
+ * Add 8 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value.
+ */
+#define NLA_PUT_U8(msg, attrtype, value) \
+       NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
+
+/**
+ * Add 16 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value.
+ */
+#define NLA_PUT_U16(msg, attrtype, value) \
+       NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
+
+/**
+ * Add 32 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value.
+ */
+#define NLA_PUT_U32(msg, attrtype, value) \
+       NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
+
+/**
+ * Add 64 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value.
+ */
+#define NLA_PUT_U64(msg, attrtype, value) \
+       NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
+
+/**
+ * Add string attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          NUL terminated character string.
+ */
+#define NLA_PUT_STRING(msg, attrtype, value) \
+       NLA_PUT(msg, attrtype, strlen(value) + 1, value)
+
+/**
+ * Add flag attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ */
+#define NLA_PUT_FLAG(msg, attrtype) \
+       NLA_PUT(msg, attrtype, 0, NULL)
+
+/**
+ * Add msecs attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg msecs          Numeric value in micro seconds.
+ */
+#define NLA_PUT_MSECS(msg, attrtype, msecs) \
+       NLA_PUT_U64(msg, attrtype, msecs)
+
+/**
+ * Add address attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg addr           Abstract address object.
+ */
+#define NLA_PUT_ADDR(msg, attrtype, addr) \
+       NLA_PUT(msg, attrtype, nl_addr_get_len(addr), \
+               nl_addr_get_binary_addr(addr))
+
+/**
+ * Add abstract data attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg data           Abstract data object.
+ */
+#define NLA_PUT_DATA(msg, attrtype, data) \
+       NLA_PUT(msg, attrtype, nl_data_get_size(data), \
+               nl_data_get(data))
+
+/** @} */
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * @ingroup attr
+ * Iterate over a stream of attributes
+ * @arg pos    loop counter, set to current attribute
+ * @arg head   head of attribute stream
+ * @arg len    length of attribute stream
+ * @arg rem    initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_attr(pos, head, len, rem) \
+       for (pos = head, rem = len; \
+            nla_ok(pos, rem); \
+            pos = nla_next(pos, &(rem)))
+
+/**
+ * @ingroup attr
+ * Iterate over a stream of nested attributes
+ * @arg pos    loop counter, set to current attribute
+ * @arg nla    attribute containing the nested attributes
+ * @arg rem    initialized to len, holds bytes currently remaining in stream
+ */
+#define nla_for_each_nested(pos, nla, rem) \
+       for (pos = nla_data(nla), rem = nla_len(nla); \
+            nla_ok(pos, rem); \
+            pos = nla_next(pos, &(rem)))
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/cache-api.h b/include/netlink/cache-api.h
new file mode 100644 (file)
index 0000000..e43c7ca
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * netlink/cache-api.h         Caching API
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DUMMY_CACHE_API_H_
+#define NETLINK_DUMMY_CACHE_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#warning "You are including a deprecated header file, include <netlink/cache.h>."
+
+#endif
diff --git a/include/netlink/cache.h b/include/netlink/cache.h
new file mode 100644 (file)
index 0000000..415bb00
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * netlink/cache.h             Caching Module
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CACHE_H_
+#define NETLINK_CACHE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+       NL_ACT_UNSPEC,
+       NL_ACT_NEW,
+       NL_ACT_DEL,
+       NL_ACT_GET,
+       NL_ACT_SET,
+       NL_ACT_CHANGE,
+       __NL_ACT_MAX,
+};
+
+#define NL_ACT_MAX (__NL_ACT_MAX - 1)
+
+struct nl_cache;
+typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *);
+
+/**
+ * @ingroup cache
+ * Explicitely iterate over all address families when updating the cache
+ */
+#define NL_CACHE_AF_ITER       0x0001
+
+/* Access Functions */
+extern int                     nl_cache_nitems(struct nl_cache *);
+extern int                     nl_cache_nitems_filter(struct nl_cache *,
+                                                      struct nl_object *);
+extern struct nl_cache_ops *   nl_cache_get_ops(struct nl_cache *);
+extern struct nl_object *      nl_cache_get_first(struct nl_cache *);
+extern struct nl_object *      nl_cache_get_last(struct nl_cache *);
+extern struct nl_object *      nl_cache_get_next(struct nl_object *);
+extern struct nl_object *      nl_cache_get_prev(struct nl_object *);
+
+extern struct nl_cache *       nl_cache_alloc(struct nl_cache_ops *);
+extern int                     nl_cache_alloc_and_fill(struct nl_cache_ops *,
+                                                       struct nl_sock *,
+                                                       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 struct nl_cache *       nl_cache_clone(struct nl_cache *);
+extern void                    nl_cache_clear(struct nl_cache *);
+extern void                    nl_cache_get(struct nl_cache *);
+extern void                    nl_cache_free(struct nl_cache *);
+extern void                    nl_cache_put(struct nl_cache *cache);
+
+/* Cache modification */
+extern int                     nl_cache_add(struct nl_cache *,
+                                            struct nl_object *);
+extern int                     nl_cache_parse_and_add(struct nl_cache *,
+                                                      struct nl_msg *);
+extern void                    nl_cache_remove(struct nl_object *);
+extern int                     nl_cache_refill(struct nl_sock *,
+                                               struct nl_cache *);
+extern int                     nl_cache_pickup(struct nl_sock *,
+                                               struct nl_cache *);
+extern int                     nl_cache_resync(struct nl_sock *,
+                                               struct nl_cache *,
+                                               change_func_t,
+                                               void *);
+extern int                     nl_cache_include(struct nl_cache *,
+                                                struct nl_object *,
+                                                change_func_t,
+                                                void *);
+extern void                    nl_cache_set_arg1(struct nl_cache *, int);
+extern void                    nl_cache_set_arg2(struct nl_cache *, int);
+extern void                    nl_cache_set_flags(struct nl_cache *, unsigned int);
+
+/* General */
+extern int                     nl_cache_is_empty(struct nl_cache *);
+extern struct nl_object *      nl_cache_search(struct nl_cache *,
+                                               struct nl_object *);
+extern struct nl_object *      nl_cache_lookup(struct nl_cache *,
+                                               struct nl_object *);
+extern void                    nl_cache_mark_all(struct nl_cache *);
+
+/* Dumping */
+extern void                    nl_cache_dump(struct nl_cache *,
+                                             struct nl_dump_params *);
+extern void                    nl_cache_dump_filter(struct nl_cache *,
+                                                    struct nl_dump_params *,
+                                                    struct nl_object *);
+
+/* Iterators */
+extern void                    nl_cache_foreach(struct nl_cache *,
+                                                void (*cb)(struct nl_object *,
+                                                           void *),
+                                                void *arg);
+extern void                    nl_cache_foreach_filter(struct nl_cache *,
+                                                       struct nl_object *,
+                                                       void (*cb)(struct
+                                                                  nl_object *,
+                                                                  void *),
+                                                       void *arg);
+
+/* --- cache management --- */
+
+/* Cache type management */
+extern struct nl_cache_ops *   nl_cache_ops_lookup(const char *);
+extern struct nl_cache_ops *   nl_cache_ops_lookup_safe(const char *);
+extern struct nl_cache_ops *   nl_cache_ops_associate(int, int);
+extern struct nl_cache_ops *   nl_cache_ops_associate_safe(int, int);
+extern struct nl_msgtype *     nl_msgtype_lookup(struct nl_cache_ops *, int);
+extern void                    nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *);
+extern int                     nl_cache_mngt_register(struct nl_cache_ops *);
+extern int                     nl_cache_mngt_unregister(struct nl_cache_ops *);
+
+/* Global cache provisioning/requiring */
+extern void                    nl_cache_mngt_provide(struct nl_cache *);
+extern void                    nl_cache_mngt_unprovide(struct nl_cache *);
+extern struct nl_cache *       nl_cache_mngt_require(const char *);
+extern struct nl_cache *       nl_cache_mngt_require_safe(const char *);
+extern struct nl_cache *       __nl_cache_mngt_require(const char *);
+
+struct nl_cache_mngr;
+
+#define NL_AUTO_PROVIDE                1
+#define NL_ALLOCATED_SOCK      2  /* For internal use only, do not use */
+
+extern int                     nl_cache_mngr_alloc(struct nl_sock *,
+                                                   int, int,
+                                                   struct nl_cache_mngr **);
+extern int                     nl_cache_mngr_add(struct nl_cache_mngr *,
+                                                 const char *,
+                                                 change_func_t,
+                                                 void *,
+                                                 struct nl_cache **);
+extern int                     nl_cache_mngr_add_cache(struct nl_cache_mngr *mngr,
+                                                       struct nl_cache *cache,
+                                                       change_func_t cb, void *data);
+extern int                     nl_cache_mngr_get_fd(struct nl_cache_mngr *);
+extern int                     nl_cache_mngr_poll(struct nl_cache_mngr *,
+                                                  int);
+extern int                     nl_cache_mngr_data_ready(struct nl_cache_mngr *);
+extern void                    nl_cache_mngr_info(struct nl_cache_mngr *,
+                                                  struct nl_dump_params *);
+extern void                    nl_cache_mngr_free(struct nl_cache_mngr *);
+
+extern void                    nl_cache_ops_get(struct nl_cache_ops *);
+extern void                    nl_cache_ops_put(struct nl_cache_ops *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/cli/addr.h b/include/netlink/cli/addr.h
new file mode 100644 (file)
index 0000000..d0fd055
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * netlink/cli/addr.h    CLI Address Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_ADDR_H_
+#define __NETLINK_CLI_ADDR_H_
+
+#include <netlink/route/addr.h>
+
+#define nl_cli_addr_alloc_cache(sk) \
+               nl_cli_alloc_cache((sk), "address", rtnl_addr_alloc_cache)
+
+extern struct rtnl_addr *nl_cli_addr_alloc(void);
+
+extern void nl_cli_addr_parse_family(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_local(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_dev(struct rtnl_addr *, struct nl_cache *,char *);
+extern void nl_cli_addr_parse_label(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_peer(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_scope(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_broadcast(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_preferred(struct rtnl_addr *, char *);
+extern void nl_cli_addr_parse_valid(struct rtnl_addr *, char *);
+
+#endif
diff --git a/include/netlink/cli/class.h b/include/netlink/cli/class.h
new file mode 100644 (file)
index 0000000..5001e42
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * netlink/cli/class.h     CLI Class Helpers
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_CLASS_H_
+#define __NETLINK_CLI_CLASS_H_
+
+#include <netlink/route/class.h>
+#include <netlink/cli/tc.h>
+
+extern struct rtnl_class *nl_cli_class_alloc(void);
+extern struct nl_cache *nl_cli_class_alloc_cache(struct nl_sock *, int);
+
+#endif
diff --git a/include/netlink/cli/cls.h b/include/netlink/cli/cls.h
new file mode 100644 (file)
index 0000000..a2707b8
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * netlink/cli/cls.h           CLI Classifier Helpers
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_CLS_H_
+#define __NETLINK_CLI_CLS_H_
+
+#include <netlink/route/classifier.h>
+#include <netlink/cli/tc.h>
+
+extern struct rtnl_cls *       nl_cli_cls_alloc(void);
+extern struct nl_cache *       nl_cli_cls_alloc_cache(struct nl_sock *,
+                                                      int, uint32_t);
+extern void                    nl_cli_cls_parse_proto(struct rtnl_cls *, char *);
+extern struct rtnl_ematch_tree *nl_cli_cls_parse_ematch(struct rtnl_cls *, char *);
+
+#endif
diff --git a/include/netlink/cli/ct.h b/include/netlink/cli/ct.h
new file mode 100644 (file)
index 0000000..bed776b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * netlink/cli/ct.h    CLI Conntrack Helper
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_CT_H_
+#define __NETLINK_CLI_CT_H_
+
+#include <netlink/netfilter/ct.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+
+extern struct nfnl_ct *nl_cli_ct_alloc(void);
+extern struct nl_cache *nl_cli_ct_alloc_cache(struct nl_sock *);
+
+extern void nl_cli_ct_parse_family(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_protocol(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_mark(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_timeout(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_id(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_use(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_src(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_dst(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_src_port(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_dst_port(struct nfnl_ct *, int, char *);
+extern void nl_cli_ct_parse_tcp_state(struct nfnl_ct *, char *);
+extern void nl_cli_ct_parse_status(struct nfnl_ct *, char *);
+
+#endif
diff --git a/include/netlink/cli/exp.h b/include/netlink/cli/exp.h
new file mode 100644 (file)
index 0000000..b2418f8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * netlink/cli/exp.h   CLI Expectation Helper
+ *
+ *     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) 2012 Rich Fought <Rich.Fought@watchguard.com>
+ * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_EXP_H_
+#define __NETLINK_CLI_EXP_H_
+
+#include <netlink/netfilter/exp.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+
+extern struct nfnl_exp *nl_cli_exp_alloc(void);
+extern struct nl_cache *nl_cli_exp_alloc_cache(struct nl_sock *);
+
+extern void nl_cli_exp_parse_family(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_timeout(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_id(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_helper_name(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_zone(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_flags(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_class(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_nat_dir(struct nfnl_exp *, char *);
+extern void nl_cli_exp_parse_fn(struct nfnl_exp *, char *);
+
+extern void nl_cli_exp_parse_src(struct nfnl_exp *, int, char *);
+extern void nl_cli_exp_parse_dst(struct nfnl_exp *, int, char *);
+extern void nl_cli_exp_parse_l4protonum(struct nfnl_exp *, int, char *);
+extern void nl_cli_exp_parse_src_port(struct nfnl_exp *, int, char *);
+extern void nl_cli_exp_parse_dst_port(struct nfnl_exp *, int, char *);
+extern void nl_cli_exp_parse_icmp_id(struct nfnl_exp *, int, char *);
+extern void nl_cli_exp_parse_icmp_type(struct nfnl_exp *, int, char *);
+extern void nl_cli_exp_parse_icmp_code(struct nfnl_exp *, int, char *);
+
+
+#endif
diff --git a/include/netlink/cli/link.h b/include/netlink/cli/link.h
new file mode 100644 (file)
index 0000000..3f37948
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * netlink/cli/link.h     CLI Link Helpers
+ *
+ *     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-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_LINK_H_
+#define __NETLINK_CLI_LINK_H_
+
+#include <netlink/route/link.h>
+#include <netlink/cli/utils.h>
+
+extern struct rtnl_link *nl_cli_link_alloc(void);
+extern struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *, int);
+extern struct nl_cache *nl_cli_link_alloc_cache(struct nl_sock *);
+
+extern void nl_cli_link_parse_family(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_name(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_mtu(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_ifindex(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_txqlen(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_weight(struct rtnl_link *, char *);
+extern void nl_cli_link_parse_ifalias(struct rtnl_link *, char *);
+
+#endif
diff --git a/include/netlink/cli/neigh.h b/include/netlink/cli/neigh.h
new file mode 100644 (file)
index 0000000..5440012
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * netlink/cli/neighbour.h     CLI Neighbour Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_NEIGH_H_
+#define __NETLINK_CLI_NEIGH_H_
+
+#include <netlink/route/neighbour.h>
+
+#define nl_cli_neigh_alloc_cache(sk) \
+               nl_cli_alloc_cache((sk), "neighbour", rtnl_neigh_alloc_cache)
+
+extern struct rtnl_neigh *nl_cli_neigh_alloc(void);
+extern void nl_cli_neigh_parse_dst(struct rtnl_neigh *, char *);
+extern void nl_cli_neigh_parse_lladdr(struct rtnl_neigh *, char *);
+extern void nl_cli_neigh_parse_dev(struct rtnl_neigh *, struct nl_cache *, char *);
+extern void nl_cli_neigh_parse_family(struct rtnl_neigh *, char *);
+extern void nl_cli_neigh_parse_state(struct rtnl_neigh *, char *);
+
+#endif
diff --git a/include/netlink/cli/qdisc.h b/include/netlink/cli/qdisc.h
new file mode 100644 (file)
index 0000000..b102da4
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * netlink/cli/qdisc.h     CLI QDisc Helpers
+ *
+ *     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-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_QDISC_H_
+#define __NETLINK_CLI_QDISC_H_
+
+#include <netlink/route/qdisc.h>
+
+#define nl_cli_qdisc_alloc_cache(sk) \
+               nl_cli_alloc_cache((sk), "queueing disciplines", \
+                                  rtnl_qdisc_alloc_cache)
+
+extern struct rtnl_qdisc *nl_cli_qdisc_alloc(void);
+
+#endif
diff --git a/include/netlink/cli/route.h b/include/netlink/cli/route.h
new file mode 100644 (file)
index 0000000..089c658
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * netlink/cli//route.h     CLI Route Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_ROUTE_H_
+#define __NETLINK_CLI_ROUTE_H_
+
+#include <netlink/route/route.h>
+
+extern struct rtnl_route *nl_cli_route_alloc(void);
+
+extern struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *, int);
+
+extern void    nl_cli_route_parse_family(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_dst(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_src(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_pref_src(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_metric(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_nexthop(struct rtnl_route *, char *, struct nl_cache *);
+extern void    nl_cli_route_parse_table(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_prio(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_scope(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_protocol(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_type(struct rtnl_route *, char *);
+extern void    nl_cli_route_parse_iif(struct rtnl_route *, char *, struct nl_cache *);
+
+#endif
diff --git a/include/netlink/cli/rule.h b/include/netlink/cli/rule.h
new file mode 100644 (file)
index 0000000..61cd63e
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * netlink/cli/rule.h     CLI Routing Rule Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_RULE_H_
+#define __NETLINK_CLI_RULE_H_
+
+#include <netlink/route/rule.h>
+
+extern struct rtnl_rule *nl_cli_rule_alloc(void);
+extern struct nl_cache *nl_cli_rule_alloc_cache(struct nl_sock *);
+extern void nl_cli_rule_parse_family(struct rtnl_rule *, char *);
+
+#endif
diff --git a/include/netlink/cli/tc.h b/include/netlink/cli/tc.h
new file mode 100644 (file)
index 0000000..77042c7
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * netlink/cli/tc.h     CLI Traffic Control Helpers
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_TC_H_
+#define __NETLINK_CLI_TC_H_
+
+#include <netlink/route/tc.h>
+
+struct rtnl_tc_ops;
+
+extern void nl_cli_tc_parse_dev(struct rtnl_tc *, struct nl_cache *, char *);
+extern void nl_cli_tc_parse_parent(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_handle(struct rtnl_tc *, char *, int);
+extern void nl_cli_tc_parse_mtu(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_mpu(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_overhead(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_linktype(struct rtnl_tc *, char *);
+extern void nl_cli_tc_parse_kind(struct rtnl_tc *, char *);
+
+struct nl_cli_tc_module
+{
+       const char *            tm_name;
+       enum rtnl_tc_type       tm_type;
+       struct rtnl_tc_ops *    tm_ops;
+       void                  (*tm_parse_argv)(struct rtnl_tc *, int, char **);
+       struct nl_list_head     tm_list;
+};
+
+extern struct nl_cli_tc_module *nl_cli_tc_lookup(struct rtnl_tc_ops *);
+extern void nl_cli_tc_register(struct nl_cli_tc_module *);
+extern void nl_cli_tc_unregister(struct nl_cli_tc_module *);
+
+#endif
diff --git a/include/netlink/cli/utils.h b/include/netlink/cli/utils.h
new file mode 100644 (file)
index 0000000..da41c10
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * src/utils.h         Utilities
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_CLI_UTILS_H_
+#define __NETLINK_CLI_UTILS_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/addr.h>
+#include <netlink/list.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/neighbour.h>
+#include <netlink/route/neightbl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/rule.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/fib_lookup/lookup.h>
+#include <netlink/fib_lookup/request.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/netfilter/ct.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __init
+#define __init __attribute__((constructor))
+#endif
+
+#ifndef __exit
+#define __exit __attribute__((destructor))
+#endif
+
+extern uint32_t                nl_cli_parse_u32(const char *);
+extern void            nl_cli_print_version(void);
+extern void            nl_cli_fatal(int, const char *, ...);
+extern struct nl_addr *        nl_cli_addr_parse(const char *, int);
+extern int             nl_cli_connect(struct nl_sock *, int);
+extern struct nl_sock *        nl_cli_alloc_socket(void);
+extern int             nl_cli_parse_dumptype(const char *);
+extern int             nl_cli_confirm(struct nl_object *,
+                                      struct nl_dump_params *, int);
+
+extern struct nl_cache *nl_cli_alloc_cache(struct nl_sock *, const char *,
+                            int (*ac)(struct nl_sock *, struct nl_cache **));
+
+extern void            nl_cli_load_module(const char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/data.h b/include/netlink/data.h
new file mode 100644 (file)
index 0000000..071159e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * netlink/data.h      Abstract Data
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DATA_H_
+#define NETLINK_DATA_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_data;
+
+/* General */
+extern struct nl_data *        nl_data_alloc(void *, size_t);
+extern struct nl_data * nl_data_alloc_attr(struct nlattr *);
+extern struct nl_data *        nl_data_clone(struct nl_data *);
+extern int             nl_data_append(struct nl_data *, void *, size_t);
+extern void            nl_data_free(struct nl_data *);
+
+/* Access Functions */
+extern void *          nl_data_get(struct nl_data *);
+extern size_t          nl_data_get_size(struct nl_data *);
+
+/* Misc */
+extern int             nl_data_cmp(struct nl_data *, struct nl_data *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/errno.h b/include/netlink/errno.h
new file mode 100644 (file)
index 0000000..f8b5130
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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_PKTLOC_FILE                29
+#define NLE_PARSE_ERR          30
+#define NLE_NODEV              31
+#define NLE_IMMUTABLE          32
+#define NLE_DUMP_INTR          33
+
+#define NLE_MAX                        NLE_DUMP_INTR
+
+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
new file mode 100644 (file)
index 0000000..8bf27b8
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * netlink/fib_lookup/fib_lookup.h     FIB Lookup
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_FIB_LOOKUP_H_
+#define NETLINK_FIB_LOOKUP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/fib_lookup/request.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct flnl_result;
+
+extern struct flnl_result *    flnl_result_alloc(void);
+extern void                    flnl_result_put(struct flnl_result *);
+
+extern struct nl_cache *       flnl_result_alloc_cache(void);
+
+extern int                     flnl_lookup_build_request(struct flnl_request *,
+                                                         int,
+                                                         struct nl_msg **);
+extern int                     flnl_lookup(struct nl_sock *,
+                                           struct flnl_request *,
+                                           struct nl_cache *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/fib_lookup/request.h b/include/netlink/fib_lookup/request.h
new file mode 100644 (file)
index 0000000..60e8820
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * netlink/fib_lookup/request.h                FIB Lookup Request      
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_FIB_LOOKUP_REQUEST_H_
+#define NETLINK_FIB_LOOKUP_REQUEST_H_
+
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct flnl_request;
+
+#define REQUEST_CAST(ptr)      ((struct flnl_request *) (ptr))
+
+extern struct flnl_request *   flnl_request_alloc(void);
+
+extern void                    flnl_request_set_fwmark(struct flnl_request *,
+                                                       uint64_t);
+extern uint64_t                        flnl_request_get_fwmark(struct flnl_request *);
+extern void                    flnl_request_set_tos(struct flnl_request *,
+                                                    int);
+extern int                     flnl_request_get_tos(struct flnl_request *);
+extern void                    flnl_request_set_scope(struct flnl_request *,
+                                                      int);
+extern int                     flnl_request_get_scope(struct flnl_request *);
+extern void                    flnl_request_set_table(struct flnl_request *,
+                                                      int);
+extern int                     flnl_request_get_table(struct flnl_request *);
+extern int                     flnl_request_set_addr(struct flnl_request *,
+                                                     struct nl_addr *);
+extern struct nl_addr *                flnl_request_get_addr(struct flnl_request *);
+
+extern int                     flnl_request_cmp(struct flnl_request *,
+                                                struct flnl_request *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/genl/ctrl.h b/include/netlink/genl/ctrl.h
new file mode 100644 (file)
index 0000000..017b8fd
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * netlink/genl/ctrl.h         Generic Netlink Controller
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_CTRL_H_
+#define NETLINK_GENL_CTRL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct genl_family;
+
+extern int                     genl_ctrl_alloc_cache(struct nl_sock *,
+                                                     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 *);
+extern int                     genl_ctrl_resolve(struct nl_sock *,
+                                                 const char *);
+extern int                     genl_ctrl_resolve_grp(struct nl_sock *sk,
+                                                     const char *family,
+                                                     const char *grp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/genl/family.h b/include/netlink/genl/family.h
new file mode 100644 (file)
index 0000000..5432b59
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * netlink/genl/family.h       Generic Netlink Family
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_FAMILY_H_
+#define NETLINK_GENL_FAMILY_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct genl_family;
+
+extern struct genl_family *    genl_family_alloc(void);
+extern void                    genl_family_put(struct genl_family *);
+
+extern unsigned int            genl_family_get_id(struct genl_family *);
+extern void                    genl_family_set_id(struct genl_family *, unsigned int);
+extern char *                  genl_family_get_name(struct genl_family *);
+extern void                    genl_family_set_name(struct genl_family *, const char *);
+extern uint8_t                 genl_family_get_version(struct genl_family *);
+extern void                    genl_family_set_version(struct genl_family *, uint8_t);
+extern uint32_t                        genl_family_get_hdrsize(struct genl_family *);
+extern void                    genl_family_set_hdrsize(struct genl_family *, uint32_t);
+extern uint32_t                        genl_family_get_maxattr(struct genl_family *);
+extern void                    genl_family_set_maxattr(struct genl_family *, uint32_t);
+
+extern int                     genl_family_add_op(struct genl_family *, int, int);
+extern int                     genl_family_add_grp(struct genl_family *, uint32_t ,
+                                                   const char *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/genl/genl.h b/include/netlink/genl/genl.h
new file mode 100644 (file)
index 0000000..e455581
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * netlink/genl/genl.h         Generic Netlink
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_H_
+#define NETLINK_GENL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int             genl_connect(struct nl_sock *);
+extern int             genl_send_simple(struct nl_sock *, int, int,
+                                        int, int);
+
+extern void *          genlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+                                   int, int, int, uint8_t, uint8_t);
+
+extern int             genlmsg_valid_hdr(struct nlmsghdr *, int);
+extern int             genlmsg_validate(struct nlmsghdr *, int, int,
+                                        struct nla_policy *);
+extern int             genlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
+                                     int, struct nla_policy *);
+extern struct genlmsghdr *
+                       genlmsg_hdr(struct nlmsghdr *);
+extern void *          genlmsg_data(const struct genlmsghdr *);
+extern void *          genlmsg_user_hdr(const struct genlmsghdr *);
+extern void *          genlmsg_user_data(const struct genlmsghdr *, const int);
+extern int             genlmsg_user_datalen(const struct genlmsghdr *,
+                                            const int);
+extern int             genlmsg_len(const struct genlmsghdr *);
+extern struct nlattr * genlmsg_attrdata(const struct genlmsghdr *, int);
+extern int             genlmsg_attrlen(const struct genlmsghdr *, int);
+
+extern char *          genl_op2name(int, int, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/genl/mngt.h b/include/netlink/genl/mngt.h
new file mode 100644 (file)
index 0000000..8a51ccd
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * netlink/genl/mngt.h         Generic Netlink Management
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_GENL_MNGT_H_
+#define NETLINK_GENL_MNGT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cache_ops;
+
+/**
+ * @ingroup genl_mngt
+ * @struct genl_info netlink/genl/mngt.h
+ *
+ * Informative structure passed on to message parser callbacks
+ *
+ * This structure is passed on to all message parser callbacks and contains
+ * information about the sender of the message as well as pointers to all
+ * relevant sections of the parsed message.
+ *
+ * @see genl_cmd::c_msg_parser
+ */
+struct genl_info
+{
+       /** Socket address of sender */
+       struct sockaddr_nl *    who;
+
+       /** Pointer to Netlink message header */
+       struct nlmsghdr *       nlh;
+
+       /** Pointer to Generic Netlink message header */
+       struct genlmsghdr *     genlhdr;
+
+       /** Pointer to user header */
+       void *                  userhdr;
+
+       /** Pointer to array of parsed attributes */
+       struct nlattr **        attrs;
+};
+
+/**
+ * @ingroup genl_mngt
+ * @struct genl_cmd netlink/genl/mngt.h
+ *
+ * Definition of a Generic Netlink command.
+ *
+ * This structure is used to define the list of available commands on the
+ * receiving side.
+ *
+ * @par Example:
+ * @code
+ * static struct genl_cmd foo_cmds[] = {
+ *     {
+ *             .c_id           = FOO_CMD_NEW,
+ *             .c_name         = "NEWFOO" ,
+ *             .c_maxattr      = FOO_ATTR_MAX,
+ *             .c_attr_policy  = foo_policy,
+ *             .c_msg_parser   = foo_msg_parser,
+ *     },
+ *     {
+ *             .c_id           = FOO_CMD_DEL,
+ *             .c_name         = "DELFOO" ,
+ *     },
+ * };
+ *
+ * static struct genl_ops my_genl_ops = {
+ *     [...]
+ *     .o_cmds                 = foo_cmds,
+ *     .o_ncmds                = ARRAY_SIZE(foo_cmds),
+ * };
+ * @endcode
+ */
+struct genl_cmd
+{
+       /** Numeric command identifier (required) */
+       int                     c_id;
+
+       /** Human readable name  (required) */
+       char *                  c_name;
+
+       /** Maximum attribute identifier that the command is prepared to handle. */
+       int                     c_maxattr;
+
+       /** Called whenever a message for this command is received */
+       int                   (*c_msg_parser)(struct nl_cache_ops *,
+                                             struct genl_cmd *,
+                                             struct genl_info *, void *);
+
+       /** Attribute validation policy, enforced before the callback is called */
+       struct nla_policy *     c_attr_policy;
+};
+
+/**
+ * @ingroup genl_mngt
+ * @struct genl_ops netlink/genl/mngt.h
+ *
+ * Definition of a Generic Netlink family
+ *
+ * @par Example:
+ * @code
+ * static struct genl_cmd foo_cmds[] = {
+ *     [...]
+ * };
+ *
+ * static struct genl_ops my_genl_ops = {
+ *     .o_name                 = "foo",
+ *     .o_hdrsize              = sizeof(struct my_hdr),
+ *     .o_cmds                 = foo_cmds,
+ *     .o_ncmds                = ARRAY_SIZE(foo_cmds),
+ * };
+ *
+ * if ((err = genl_register_family(&my_genl_ops)) < 0)
+ *     // ERROR
+ * @endcode
+ *
+ * @see genl_cmd
+ */
+struct genl_ops
+{
+       /** Length of user header */
+       unsigned int            o_hdrsize;
+
+       /** Numeric identifier, automatically filled in by genl_ops_resolve() */
+       int                     o_id;
+
+       /** Human readable name, used by genl_ops_resolve() to resolve numeric id */
+       char *                  o_name;
+
+       /**
+        * If registered via genl_register(), will point to the related
+        * cache operations.
+        */
+       struct nl_cache_ops *   o_cache_ops;
+
+       /** Optional array defining the available Generic Netlink commands */
+       struct genl_cmd *       o_cmds;
+
+       /** Number of elements in \c o_cmds array */
+       int                     o_ncmds;
+
+       /**
+        * @private
+        * Used internally to link together all registered operations.
+        */
+       struct nl_list_head     o_list;
+};
+
+extern int             genl_register_family(struct genl_ops *);
+extern int             genl_unregister_family(struct genl_ops *);
+extern int             genl_handle_msg(struct nl_msg *, void *);
+
+extern int             genl_register(struct nl_cache_ops *);
+extern void            genl_unregister(struct nl_cache_ops *);
+
+extern int             genl_ops_resolve(struct nl_sock *, struct genl_ops *);
+extern int             genl_mngt_resolve(struct nl_sock *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/handlers.h b/include/netlink/handlers.h
new file mode 100644 (file)
index 0000000..dfa2809
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * netlink/handlers.c  default netlink message handlers
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_HANDLERS_H_
+#define NETLINK_HANDLERS_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <netlink/netlink-compat.h>
+#include <netlink/netlink-kernel.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cb;
+struct nl_sock;
+struct nl_msg;
+struct ucred;
+
+/**
+ * @name Callback Typedefs
+ * @{
+ */
+
+/**
+ * nl_recvmsgs() callback for message processing customization
+ * @ingroup cb
+ * @arg msg            netlink message being processed
+ * @arg arg            argument passwd on through caller
+ */
+typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
+
+/**
+ * nl_recvmsgs() callback for error message processing customization
+ * @ingroup cb
+ * @arg nla            netlink address of the peer
+ * @arg nlerr          netlink error message being processed
+ * @arg arg            argument passed on through caller
+ */
+typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla,
+                                  struct nlmsgerr *nlerr, void *arg);
+
+/** @} */
+
+/**
+ * Callback actions
+ * @ingroup cb
+ */
+enum nl_cb_action {
+       /** Proceed with wathever would come next */
+       NL_OK,
+       /** Skip this message */
+       NL_SKIP,
+       /** Stop parsing altogether and discard remaining messages */
+       NL_STOP,
+};
+
+/**
+ * Callback kinds
+ * @ingroup cb
+ */
+enum nl_cb_kind {
+       /** Default handlers (quiet) */
+       NL_CB_DEFAULT,
+       /** Verbose default handlers (error messages printed) */
+       NL_CB_VERBOSE,
+       /** Debug handlers for debugging */
+       NL_CB_DEBUG,
+       /** Customized handler specified by the user */
+       NL_CB_CUSTOM,
+       __NL_CB_KIND_MAX,
+};
+
+#define NL_CB_KIND_MAX (__NL_CB_KIND_MAX - 1)
+
+/**
+ * Callback types
+ * @ingroup cb
+ */
+enum nl_cb_type {
+       /** Message is valid */
+       NL_CB_VALID,
+       /** Last message in a series of multi part messages received */
+       NL_CB_FINISH,
+       /** Report received that data was lost */
+       NL_CB_OVERRUN,
+       /** Message wants to be skipped */
+       NL_CB_SKIPPED,
+       /** Message is an acknowledge */
+       NL_CB_ACK,
+       /** Called for every message received */
+       NL_CB_MSG_IN,
+       /** Called for every message sent out except for nl_sendto() */
+       NL_CB_MSG_OUT,
+       /** Message is malformed and invalid */
+       NL_CB_INVALID,
+       /** Called instead of internal sequence number checking */
+       NL_CB_SEQ_CHECK,
+       /** Sending of an acknowledge message has been requested */
+       NL_CB_SEND_ACK,
+       /** Flag NLM_F_DUMP_INTR is set in message */
+       NL_CB_DUMP_INTR,
+       __NL_CB_TYPE_MAX,
+};
+
+#define NL_CB_TYPE_MAX (__NL_CB_TYPE_MAX - 1)
+
+extern struct nl_cb *  nl_cb_alloc(enum nl_cb_kind);
+extern struct nl_cb *  nl_cb_clone(struct nl_cb *);
+extern struct nl_cb *  nl_cb_get(struct nl_cb *);
+extern void            nl_cb_put(struct nl_cb *);
+
+extern int  nl_cb_set(struct nl_cb *, enum nl_cb_type, enum nl_cb_kind,
+                     nl_recvmsg_msg_cb_t, void *);
+extern int  nl_cb_set_all(struct nl_cb *, enum nl_cb_kind,
+                         nl_recvmsg_msg_cb_t, void *);
+extern int  nl_cb_err(struct nl_cb *, enum nl_cb_kind, nl_recvmsg_err_cb_t,
+                     void *);
+
+extern void nl_cb_overwrite_recvmsgs(struct nl_cb *,
+                                    int (*func)(struct nl_sock *,
+                                                struct nl_cb *));
+extern void nl_cb_overwrite_recv(struct nl_cb *,
+                                int (*func)(struct nl_sock *,
+                                            struct sockaddr_nl *,
+                                            unsigned char **,
+                                            struct ucred **));
+extern void nl_cb_overwrite_send(struct nl_cb *,
+                                int (*func)(struct nl_sock *,
+                                            struct nl_msg *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/hash.h b/include/netlink/hash.h
new file mode 100644 (file)
index 0000000..0bda74e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * This file was taken from http://ccodearchive.net/info/hash.html
+ * Changes to the original file include cleanups and removal of unwanted code
+ * and also code that depended on build_asert
+ */
+#ifndef CCAN_HASH_H
+#define CCAN_HASH_H
+#include <stdint.h>
+#include <stdlib.h>
+#include <endian.h>
+
+/* Stolen mostly from: lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+ *
+ * http://burtleburtle.net/bob/c/lookup3.c
+ */
+
+#ifdef __LITTLE_ENDIAN
+#   define HAVE_LITTLE_ENDIAN 1
+#elif __BIG_ENDIAN
+#   define HAVE_BIG_ENDIAN 1
+#else
+#error Unknown endianness.  Failure in endian.h
+#endif
+
+/**
+ * hash - fast hash of an array for internal use
+ * @p: the array or pointer to first element
+ * @num: the number of elements to hash
+ * @base: the base number to roll into the hash (usually 0)
+ *
+ * The memory region pointed to by p is combined with the base to form
+ * a 32-bit hash.
+ *
+ * This hash will have different results on different machines, so is
+ * only useful for internal hashes (ie. not hashes sent across the
+ * network or saved to disk).
+ *
+ * It may also change with future versions: it could even detect at runtime
+ * what the fastest hash to use is.
+ *
+ * See also: hash64, hash_stable.
+ *
+ * Example:
+ *     #include <ccan/hash/hash.h>
+ *     #include <err.h>
+ *     #include <stdio.h>
+ *     #include <string.h>
+ *
+ *     // Simple demonstration: idential strings will have the same hash, but
+ *     // two different strings will probably not.
+ *     int main(int argc, char *argv[])
+ *     {
+ *             uint32_t hash1, hash2;
+ *
+ *             if (argc != 3)
+ *                     err(1, "Usage: %s <string1> <string2>", argv[0]);
+ *
+ *             hash1 = __nl_hash(argv[1], strlen(argv[1]), 0);
+ *             hash2 = __nl_hash(argv[2], strlen(argv[2]), 0);
+ *             printf("Hash is %s\n", hash1 == hash2 ? "same" : "different");
+ *             return 0;
+ *     }
+ */
+#define __nl_hash(p, num, base) nl_hash_any((p), (num)*sizeof(*(p)), (base))
+
+/* Our underlying operations. */
+uint32_t nl_hash_any(const void *key, size_t length, uint32_t base);
+
+#endif /* HASH_H */
diff --git a/include/netlink/hashtable.h b/include/netlink/hashtable.h
new file mode 100644 (file)
index 0000000..d9e6ee4
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * netlink/hashtable.h       Netlink hashtable Utilities
+ *
+ *      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) 2012 Cumulus Networks, Inc
+ */
+
+#ifndef NETLINK_HASHTABLE_H_
+#define NETLINK_HASHTABLE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct nl_hash_node {
+    uint32_t                   key;
+    uint32_t                   key_size;
+    struct nl_object *         obj;
+    struct nl_hash_node *      next;
+} nl_hash_node_t;
+
+typedef struct nl_hash_table {
+    int                        size;
+    nl_hash_node_t **          nodes;
+} nl_hash_table_t;
+
+/* Default hash table size */
+#define NL_MAX_HASH_ENTRIES 1024
+
+/* Access Functions */
+extern nl_hash_table_t *       nl_hash_table_alloc(int size);
+extern void                    nl_hash_table_free(nl_hash_table_t *ht);
+
+extern int                     nl_hash_table_add(nl_hash_table_t *ht,
+                                                 struct nl_object *obj);
+extern int                     nl_hash_table_del(nl_hash_table_t *ht,
+                                                 struct nl_object *obj);
+
+extern struct nl_object *      nl_hash_table_lookup(nl_hash_table_t *ht,
+                                                    struct nl_object *obj);
+extern uint32_t                nl_hash(void *k, size_t length,
+                                       uint32_t initval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETLINK_HASHTABLE_H_ */
diff --git a/include/netlink/list.h b/include/netlink/list.h
new file mode 100644 (file)
index 0000000..28712ed
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * netlink/list.h      Netlink List Utilities
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LIST_H_
+#define NETLINK_LIST_H_
+
+struct nl_list_head
+{
+       struct nl_list_head *   next;
+       struct nl_list_head *   prev;
+};
+
+static inline void NL_INIT_LIST_HEAD(struct nl_list_head *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+static inline void __nl_list_add(struct nl_list_head *obj,
+                                struct nl_list_head *prev,
+                                struct nl_list_head *next)
+{
+       prev->next = obj;
+       obj->prev = prev;
+       next->prev = obj;
+       obj->next = next;
+}
+
+static inline void nl_list_add_tail(struct nl_list_head *obj,
+                                   struct nl_list_head *head)
+{
+       __nl_list_add(obj, head->prev, head);
+}
+
+static inline void nl_list_add_head(struct nl_list_head *obj,
+                                   struct nl_list_head *head)
+{
+       __nl_list_add(obj, head, head->next);
+}
+
+static inline void nl_list_del(struct nl_list_head *obj)
+{
+       obj->next->prev = obj->prev;
+       obj->prev->next = obj->next;
+}
+
+static inline int nl_list_empty(struct nl_list_head *head)
+{
+       return head->next == head;
+}
+
+#define nl_container_of(ptr, type, member) ({                  \
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
+        (type *)( (char *)__mptr - ((size_t) &((type *)0)->member));})
+
+#define nl_list_entry(ptr, type, member) \
+       nl_container_of(ptr, type, member)
+
+#define nl_list_at_tail(pos, head, member) \
+       ((pos)->member.next == (head))
+
+#define nl_list_at_head(pos, head, member) \
+       ((pos)->member.prev == (head))
+
+#define NL_LIST_HEAD(name) \
+       struct nl_list_head name = { &(name), &(name) }
+
+#define nl_list_first_entry(head, type, member)                        \
+       nl_list_entry((head)->next, type, member)
+
+#define nl_list_for_each_entry(pos, head, member)                              \
+       for (pos = nl_list_entry((head)->next, typeof(*pos), member);   \
+            &(pos)->member != (head);  \
+            (pos) = nl_list_entry((pos)->member.next, typeof(*(pos)), member))
+
+#define nl_list_for_each_entry_safe(pos, n, head, member)                      \
+       for (pos = nl_list_entry((head)->next, typeof(*pos), member),   \
+               n = nl_list_entry(pos->member.next, typeof(*pos), member);      \
+            &(pos)->member != (head);                                  \
+            pos = n, n = nl_list_entry(n->member.next, typeof(*n), member))
+
+#define nl_init_list_head(head) \
+       do { (head)->next = (head); (head)->prev = (head); } while (0)
+
+#endif
diff --git a/include/netlink/msg.h b/include/netlink/msg.h
new file mode 100644 (file)
index 0000000..f3d50ae
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * netlink/msg.c               Netlink Messages Interface
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_MSG_H_
+#define NETLINK_MSG_H_
+
+#include <netlink/netlink.h>
+#include <netlink/object.h>
+#include <netlink/attr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NL_DONTPAD     0
+
+/**
+ * @ingroup msg
+ * @brief
+ * Will cause the netlink port to be set to the port assigned to
+ * the netlink icoket ust before sending the message off.
+ *
+ * @note Requires the use of nl_send_auto()!
+ */
+#define NL_AUTO_PORT   0
+#define NL_AUTO_PID    NL_AUTO_PORT
+
+/**
+ * @ingroup msg
+ * @brief
+ * May be used to refer to a sequence number which should be
+ * automatically set just before sending the message off.
+ *
+ * @note Requires the use of nl_send_auto()!
+ */
+#define NL_AUTO_SEQ    0
+
+struct nl_msg;
+struct nl_tree;
+struct ucred;
+
+extern int                     nlmsg_size(int);
+extern int                     nlmsg_total_size(int);
+extern int                     nlmsg_padlen(int);
+
+extern void *                  nlmsg_data(const struct nlmsghdr *);
+extern int                     nlmsg_datalen(const struct nlmsghdr *);
+extern void *                  nlmsg_tail(const struct nlmsghdr *);
+
+/* attribute access */
+extern struct nlattr *   nlmsg_attrdata(const struct nlmsghdr *, int);
+extern int               nlmsg_attrlen(const struct nlmsghdr *, int);
+
+/* message parsing */
+extern int               nlmsg_valid_hdr(const struct nlmsghdr *, int);
+extern int               nlmsg_ok(const struct nlmsghdr *, int);
+extern struct nlmsghdr *  nlmsg_next(struct nlmsghdr *, int *);
+extern int               nlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
+                                     int, struct nla_policy *);
+extern struct nlattr *   nlmsg_find_attr(struct nlmsghdr *, int, int);
+extern int               nlmsg_validate(struct nlmsghdr *, int, int,
+                                        struct nla_policy *);
+
+extern struct nl_msg *   nlmsg_alloc(void);
+extern struct nl_msg *   nlmsg_alloc_size(size_t);
+extern struct nl_msg *   nlmsg_alloc_simple(int, int);
+extern void              nlmsg_set_default_size(size_t);
+extern struct nl_msg *   nlmsg_inherit(struct nlmsghdr *);
+extern struct nl_msg *   nlmsg_convert(struct nlmsghdr *);
+extern void *            nlmsg_reserve(struct nl_msg *, size_t, int);
+extern int               nlmsg_append(struct nl_msg *, void *, size_t, int);
+extern int               nlmsg_expand(struct nl_msg *, size_t);
+
+extern struct nlmsghdr *  nlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+                                   int, int, int);
+extern struct nlmsghdr *  nlmsg_hdr(struct nl_msg *);
+extern void              nlmsg_get(struct nl_msg *);
+extern void              nlmsg_free(struct nl_msg *);
+
+/* attribute modification */
+extern void              nlmsg_set_proto(struct nl_msg *, int);
+extern int               nlmsg_get_proto(struct nl_msg *);
+extern size_t            nlmsg_get_max_size(struct nl_msg *);
+extern void              nlmsg_set_src(struct nl_msg *, struct sockaddr_nl *);
+extern struct sockaddr_nl *nlmsg_get_src(struct nl_msg *);
+extern void              nlmsg_set_dst(struct nl_msg *, struct sockaddr_nl *);
+extern struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *);
+extern void              nlmsg_set_creds(struct nl_msg *, struct ucred *);
+extern struct ucred *    nlmsg_get_creds(struct nl_msg *);
+
+extern char *            nl_nlmsgtype2str(int, char *, size_t);
+extern int               nl_str2nlmsgtype(const char *);
+
+extern char *            nl_nlmsg_flags2str(int, char *, size_t);
+
+extern int               nl_msg_parse(struct nl_msg *,
+                                      void (*cb)(struct nl_object *, void *),
+                                      void *);
+
+extern void            nl_msg_dump(struct nl_msg *, FILE *);
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * @ingroup msg
+ * Iterate over a stream of attributes in a message
+ * @arg pos    loop counter, set to current attribute
+ * @arg nlh    netlink message header
+ * @arg hdrlen length of family header
+ * @arg rem    initialized to len, holds bytes currently remaining in stream
+ */
+#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \
+       nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \
+                         nlmsg_attrlen(nlh, hdrlen), rem)
+
+/**
+ * Iterate over a stream of messages
+ * @arg pos    loop counter, set to current message
+ * @arg head   head of message stream
+ * @arg len    length of message stream
+ */
+#define nlmsg_for_each(pos, head, len) \
+       for (int rem = len, pos = head; \
+               nlmsg_ok(pos, rem); \
+               pos = nlmsg_next(pos, &rem))
+
+#define nlmsg_for_each_msg(pos, head, len, rem) \
+               nlmsg_for_each(pos, head, len)
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/netfilter/ct.h b/include/netlink/netfilter/ct.h
new file mode 100644 (file)
index 0000000..57fbe53
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * netlink/netfilter/ct.h      Conntrack
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#ifndef NETLINK_CT_H_
+#define NETLINK_CT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+#include <netlink/cache.h>
+#include <netlink/msg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nfnl_ct;
+
+extern struct nl_object_ops ct_obj_ops;
+
+extern struct nfnl_ct *        nfnl_ct_alloc(void);
+extern int     nfnl_ct_alloc_cache(struct nl_sock *, struct nl_cache **);
+
+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 int     nfnl_ct_dump_request(struct nl_sock *);
+
+extern int     nfnl_ct_build_add_request(const struct nfnl_ct *, int,
+                                         struct nl_msg **);
+extern int     nfnl_ct_add(struct nl_sock *, const struct nfnl_ct *, int);
+
+extern int     nfnl_ct_build_delete_request(const struct nfnl_ct *, int,
+                                            struct nl_msg **);
+extern int     nfnl_ct_del(struct nl_sock *, 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_sock *, 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_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_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 char *  nfnl_ct_status2str(int, char *, size_t);
+extern int     nfnl_ct_str2status(const char *);
+
+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_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 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 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_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_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_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/netfilter/exp.h b/include/netlink/netfilter/exp.h
new file mode 100644 (file)
index 0000000..4e95014
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * netlink/netfilter/exp.h   Conntrack Expectation
+ *
+ *  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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
+ */
+
+#ifndef NETLINK_EXP_H_
+#define NETLINK_EXP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+#include <netlink/cache.h>
+#include <netlink/msg.h>
+
+#include <linux/version.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nfnl_exp;
+
+enum nfnl_exp_tuples {
+       NFNL_EXP_TUPLE_EXPECT,
+       NFNL_EXP_TUPLE_MASTER,
+       NFNL_EXP_TUPLE_MASK,
+       NFNL_EXP_TUPLE_NAT,
+       NFNL_EXP_TUPLE_MAX
+};
+
+extern struct nl_object_ops exp_obj_ops;
+
+extern struct nfnl_exp * nfnl_exp_alloc(void);
+extern int  nfnl_exp_alloc_cache(struct nl_sock *, struct nl_cache **);
+
+extern int  nfnlmsg_exp_group(struct nlmsghdr *);
+extern int  nfnlmsg_exp_parse(struct nlmsghdr *, struct nfnl_exp **);
+
+extern void nfnl_exp_get(struct nfnl_exp *);
+extern void nfnl_exp_put(struct nfnl_exp *);
+
+extern int  nfnl_exp_dump_request(struct nl_sock *);
+
+extern int  nfnl_exp_build_add_request(const struct nfnl_exp *, int,
+                                               struct nl_msg **);
+extern int  nfnl_exp_add(struct nl_sock *, const struct nfnl_exp *, int);
+
+extern int  nfnl_exp_build_delete_request(const struct nfnl_exp *, int,
+                                               struct nl_msg **);
+extern int  nfnl_exp_del(struct nl_sock *, const struct nfnl_exp *, int);
+
+extern int  nfnl_exp_build_query_request(const struct nfnl_exp *, int,
+                                               struct nl_msg **);
+extern int  nfnl_exp_query(struct nl_sock *, const struct nfnl_exp *, int);
+
+extern void nfnl_exp_set_family(struct nfnl_exp *, uint8_t);
+extern uint8_t  nfnl_exp_get_family(const struct nfnl_exp *);
+
+extern void nfnl_exp_set_timeout(struct nfnl_exp *, uint32_t);
+extern int  nfnl_exp_test_timeout(const struct nfnl_exp *);
+extern uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *);
+
+extern void nfnl_exp_set_id(struct nfnl_exp *, uint32_t);
+extern int  nfnl_exp_test_id(const struct nfnl_exp *);
+extern uint32_t nfnl_exp_get_id(const struct nfnl_exp *);
+
+extern int  nfnl_exp_set_helper_name(struct nfnl_exp *, void *);
+extern int  nfnl_exp_test_helper_name(const struct nfnl_exp *);
+extern const char * nfnl_exp_get_helper_name(const struct nfnl_exp *);
+
+extern void nfnl_exp_set_zone(struct nfnl_exp *, uint16_t);
+extern int  nfnl_exp_test_zone(const struct nfnl_exp *);
+extern uint16_t nfnl_exp_get_zone(const struct nfnl_exp *);
+
+extern void nfnl_exp_set_flags(struct nfnl_exp *, uint32_t);
+extern int  nfnl_exp_test_flags(const struct nfnl_exp *);
+extern uint32_t nfnl_exp_get_flags(const struct nfnl_exp *);
+
+extern void nfnl_exp_set_class(struct nfnl_exp *, uint32_t);
+extern int  nfnl_exp_test_class(const struct nfnl_exp *);
+extern uint32_t nfnl_exp_get_class(const struct nfnl_exp *);
+
+extern int  nfnl_exp_set_fn(struct nfnl_exp *, void *);
+extern int  nfnl_exp_test_fn(const struct nfnl_exp *);
+extern const char * nfnl_exp_get_fn(const struct nfnl_exp *);
+
+extern void nfnl_exp_set_nat_dir(struct nfnl_exp *, uint8_t);
+extern int  nfnl_exp_test_nat_dir(const struct nfnl_exp *);
+extern uint8_t nfnl_exp_get_nat_dir(const struct nfnl_exp *);
+
+// The int argument specifies which nfnl_exp_dir (expect, master, mask or nat)
+// Expectation objects only use orig, not reply
+
+extern int  nfnl_exp_set_src(struct nfnl_exp *, int, struct nl_addr *);
+extern int  nfnl_exp_test_src(const struct nfnl_exp *, int);
+extern struct nl_addr * nfnl_exp_get_src(const struct nfnl_exp *, int);
+
+extern int  nfnl_exp_set_dst(struct nfnl_exp *, int, struct nl_addr *);
+extern int  nfnl_exp_test_dst(const struct nfnl_exp *, int);
+extern struct nl_addr * nfnl_exp_get_dst(const struct nfnl_exp *, int);
+
+extern void  nfnl_exp_set_l4protonum(struct nfnl_exp *, int, uint8_t);
+extern int  nfnl_exp_test_l4protonum(const struct nfnl_exp *, int);
+extern uint8_t nfnl_exp_get_l4protonum(const struct nfnl_exp *, int);
+
+extern void nfnl_exp_set_ports(struct nfnl_exp *, int, uint16_t, uint16_t);
+extern int nfnl_exp_test_ports(const struct nfnl_exp *, int);
+extern uint16_t nfnl_exp_get_src_port(const struct nfnl_exp *, int);
+extern uint16_t nfnl_exp_get_dst_port(const struct nfnl_exp *, int);
+
+extern void nfnl_exp_set_icmp(struct nfnl_exp *, int, uint16_t, uint8_t, uint8_t);
+extern int nfnl_exp_test_icmp(const struct nfnl_exp *, int);
+extern uint16_t nfnl_exp_get_icmp_id(const struct nfnl_exp *, int);
+extern uint8_t  nfnl_exp_get_icmp_type(const struct nfnl_exp *, int);
+extern uint8_t  nfnl_exp_get_icmp_code(const struct nfnl_exp *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/netfilter/log.h b/include/netlink/netfilter/log.h
new file mode 100644 (file)
index 0000000..2002fa8
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * netlink/netfilter/log.h     Netfilter Log
+ *
+ *     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) 2003-2006 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>
+ */
+
+#ifndef NETLINK_LOG_H_
+#define NETLINK_LOG_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_sock;
+struct nlmsghdr;
+struct nfnl_log;
+
+extern struct nl_object_ops log_obj_ops;
+
+enum nfnl_log_copy_mode {
+       NFNL_LOG_COPY_NONE,
+       NFNL_LOG_COPY_META,
+       NFNL_LOG_COPY_PACKET,
+};
+
+enum nfnl_log_flags {
+       NFNL_LOG_FLAG_SEQ               = 0x1,
+       NFNL_LOG_FLAG_SEQ_GLOBAL        = 0x2,
+};
+
+/* General */
+extern struct nfnl_log *       nfnl_log_alloc(void);
+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 *);
+
+/* Attributes */
+extern void                    nfnl_log_set_group(struct nfnl_log *, uint16_t);
+extern int                     nfnl_log_test_group(const struct nfnl_log *);
+extern uint16_t                        nfnl_log_get_group(const struct nfnl_log *);
+
+extern void                    nfnl_log_set_copy_mode(struct nfnl_log *,
+                                                      enum nfnl_log_copy_mode);
+extern int                     nfnl_log_test_copy_mode(const struct nfnl_log *);
+extern enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *);
+
+extern char *                  nfnl_log_copy_mode2str(enum nfnl_log_copy_mode,
+                                                      char *, size_t);
+extern enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *);
+
+extern void                    nfnl_log_set_copy_range(struct nfnl_log *, uint32_t);
+extern int                     nfnl_log_test_copy_range(const struct nfnl_log *);
+extern uint32_t                        nfnl_log_get_copy_range(const struct nfnl_log *);
+
+extern void                    nfnl_log_set_flush_timeout(struct nfnl_log *, uint32_t);
+extern int                     nfnl_log_test_flush_timeout(const struct nfnl_log *);
+extern uint32_t                        nfnl_log_get_flush_timeout(const struct nfnl_log *);
+
+extern void                    nfnl_log_set_alloc_size(struct nfnl_log *, uint32_t);
+extern int                     nfnl_log_test_alloc_size(const struct nfnl_log *);
+extern uint32_t                        nfnl_log_get_alloc_size(const struct nfnl_log *);
+
+extern void                    nfnl_log_set_queue_threshold(struct nfnl_log *, uint32_t);
+extern int                     nfnl_log_test_queue_threshold(const struct nfnl_log *);
+extern uint32_t                        nfnl_log_get_queue_threshold(const struct nfnl_log *);
+
+extern void                    nfnl_log_set_flags(struct nfnl_log *, unsigned int);
+extern void                    nfnl_log_unset_flags(struct nfnl_log *, unsigned int);
+extern unsigned int            nfnl_log_get_flags(const struct nfnl_log *);
+
+extern char *                  nfnl_log_flags2str(unsigned int, char *, size_t);
+extern unsigned int            nfnl_log_str2flags(const char *);
+
+extern int     nfnl_log_build_pf_bind(uint8_t, struct nl_msg **);
+extern int     nfnl_log_pf_bind(struct nl_sock *, uint8_t);
+
+extern int     nfnl_log_build_pf_unbind(uint8_t, struct nl_msg **);
+extern int     nfnl_log_pf_unbind(struct nl_sock *, uint8_t);
+
+extern int     nfnl_log_build_create_request(const struct nfnl_log *,
+                                             struct nl_msg **);
+extern int     nfnl_log_create(struct nl_sock *, 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_sock *, 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_sock *, const struct nfnl_log *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/netlink/netfilter/log_msg.h b/include/netlink/netfilter/log_msg.h
new file mode 100644 (file)
index 0000000..63b0f64
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * netlink/netfilter/log_msg.h Netfilter Log Message
+ *
+ *     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) 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>
+ */
+
+#ifndef NETLINK_LOG_MSG_H_
+#define NETLINK_LOG_MSG_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nlmsghdr;
+struct nfnl_log_msg;
+
+extern struct nl_object_ops log_msg_obj_ops;
+
+/* General */
+extern struct nfnl_log_msg *nfnl_log_msg_alloc(void);
+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 *);
+
+extern void            nfnl_log_msg_set_family(struct nfnl_log_msg *, uint8_t);
+extern uint8_t         nfnl_log_msg_get_family(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_hwproto(struct nfnl_log_msg *, uint16_t);
+extern int             nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *);
+extern uint16_t                nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_hook(struct nfnl_log_msg *, uint8_t);
+extern int             nfnl_log_msg_test_hook(const struct nfnl_log_msg *);
+extern uint8_t         nfnl_log_msg_get_hook(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_mark(struct nfnl_log_msg *, uint32_t);
+extern int             nfnl_log_msg_test_mark(const struct nfnl_log_msg *);
+extern uint32_t                nfnl_log_msg_get_mark(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_timestamp(struct nfnl_log_msg *,
+                                              struct timeval *);
+extern const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_indev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t                nfnl_log_msg_get_indev(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_outdev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t                nfnl_log_msg_get_outdev(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_physindev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t                nfnl_log_msg_get_physindev(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *, uint32_t);
+extern uint32_t                nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *, uint8_t *, int);
+extern const uint8_t * nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *, int *);
+
+extern int             nfnl_log_msg_set_payload(struct nfnl_log_msg *, uint8_t *, int);
+extern const void *    nfnl_log_msg_get_payload(const struct nfnl_log_msg *, int *);
+
+extern int             nfnl_log_msg_set_prefix(struct nfnl_log_msg *, void *);
+extern const char *    nfnl_log_msg_get_prefix(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_uid(struct nfnl_log_msg *, uint32_t);
+extern int             nfnl_log_msg_test_uid(const struct nfnl_log_msg *);
+extern uint32_t                nfnl_log_msg_get_uid(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_gid(struct nfnl_log_msg *, uint32_t);
+extern int             nfnl_log_msg_test_gid(const struct nfnl_log_msg *);
+extern uint32_t                nfnl_log_msg_get_gid(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_seq(struct nfnl_log_msg *, uint32_t);
+extern int             nfnl_log_msg_test_seq(const struct nfnl_log_msg *);
+extern uint32_t                nfnl_log_msg_get_seq(const struct nfnl_log_msg *);
+
+extern void            nfnl_log_msg_set_seq_global(struct nfnl_log_msg *, uint32_t);
+extern int             nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *);
+extern uint32_t                nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/netlink/netfilter/netfilter.h b/include/netlink/netfilter/netfilter.h
new file mode 100644 (file)
index 0000000..dd3589c
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * netlink/netfilter/netfilter.h       Netfilter generic functions
+ *
+ *     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 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef NETLINK_NETFILTER_H_
+#define NETLINK_NETFILTER_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *                  nfnl_verdict2str(unsigned int, char *, size_t);
+extern unsigned int            nfnl_str2verdict(const char *);
+
+extern char *                  nfnl_inet_hook2str(unsigned int, char *, size_t);
+extern unsigned int            nfnl_str2inet_hook(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/netfilter/nfnl.h b/include/netlink/netfilter/nfnl.h
new file mode 100644 (file)
index 0000000..8da4ba1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * netlink/nfnl/nfnl.h         Netfilter Netlink
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#ifndef NETLINK_NFNL_H_
+#define NETLINK_NFNL_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NFNL_HDRLEN NLMSG_ALIGN(sizeof(struct nfgenmsg))
+#define NFNLMSG_TYPE(subsys, subtype) (((subsys) << 8) | (subtype))
+
+extern int             nfnl_connect(struct nl_sock *);
+
+extern uint8_t         nfnlmsg_subsys(struct nlmsghdr *);
+extern uint8_t         nfnlmsg_subtype(struct nlmsghdr *);
+extern uint8_t         nfnlmsg_family(struct nlmsghdr *);
+extern uint16_t                nfnlmsg_res_id(struct nlmsghdr *);
+
+extern int             nfnl_send_simple(struct nl_sock *, uint8_t, uint8_t,
+                                        int, uint8_t, uint16_t);
+extern struct nl_msg * nfnlmsg_alloc_simple(uint8_t, uint8_t, int,
+                                            uint8_t, uint16_t);
+extern int             nfnlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+                                   uint8_t, uint8_t, int, uint8_t, uint16_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/netfilter/queue.h b/include/netlink/netfilter/queue.h
new file mode 100644 (file)
index 0000000..664610d
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * netlink/netfilter/queue.h   Netfilter Queue
+ *
+ *     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) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef NETLINK_QUEUE_H_
+#define NETLINK_QUEUE_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_sock;
+struct nlmsghdr;
+struct nfnl_queue;
+
+extern struct nl_object_ops queue_obj_ops;
+
+enum nfnl_queue_copy_mode {
+       NFNL_QUEUE_COPY_NONE,
+       NFNL_QUEUE_COPY_META,
+       NFNL_QUEUE_COPY_PACKET,
+};
+
+/* General */
+extern struct nl_sock *                nfnl_queue_socket_alloc(void);
+
+extern struct nfnl_queue *     nfnl_queue_alloc(void);
+
+extern void                    nfnl_queue_get(struct nfnl_queue *);
+extern void                    nfnl_queue_put(struct nfnl_queue *);
+
+/* Attributes */
+extern void                    nfnl_queue_set_group(struct nfnl_queue *, uint16_t);
+extern int                     nfnl_queue_test_group(const struct nfnl_queue *);
+extern uint16_t                        nfnl_queue_get_group(const struct nfnl_queue *);
+
+extern void                    nfnl_queue_set_maxlen(struct nfnl_queue *, uint32_t);
+extern int                     nfnl_queue_test_maxlen(const struct nfnl_queue *);
+extern uint32_t                        nfnl_queue_get_maxlen(const struct nfnl_queue *);
+
+extern void                    nfnl_queue_set_copy_mode(struct nfnl_queue *,
+                                                        enum nfnl_queue_copy_mode);
+extern int                     nfnl_queue_test_copy_mode(const struct nfnl_queue *);
+extern enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *);
+
+extern char *                  nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode,
+                                                        char *, size_t);
+extern enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *);
+
+extern void                    nfnl_queue_set_copy_range(struct nfnl_queue *,
+                                                         uint32_t);
+extern int                     nfnl_queue_test_copy_range(const struct nfnl_queue *);
+extern uint32_t                        nfnl_queue_get_copy_range(const struct nfnl_queue *);
+
+extern int     nfnl_queue_build_pf_bind(uint8_t, struct nl_msg **);
+extern int     nfnl_queue_pf_bind(struct nl_sock *, uint8_t);
+
+extern int     nfnl_queue_build_pf_unbind(uint8_t, struct nl_msg **);
+extern int     nfnl_queue_pf_unbind(struct nl_sock *, uint8_t);
+
+extern int     nfnl_queue_build_create_request(const struct nfnl_queue *,
+                                               struct nl_msg **);
+extern int     nfnl_queue_create(struct nl_sock *,
+                                 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_sock *,
+                                 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_sock *,
+                                 const struct nfnl_queue *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/netlink/netfilter/queue_msg.h b/include/netlink/netfilter/queue_msg.h
new file mode 100644 (file)
index 0000000..24ed081
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * netlink/netfilter/queue_msg.h       Netfilter Queue Messages
+ *
+ *     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) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef NETLINK_QUEUE_MSG_H_
+#define NETLINK_QUEUE_MSG_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_sock;
+struct nlmsghdr;
+struct nfnl_queue_msg;
+
+extern struct nl_object_ops queue_msg_obj_ops;
+
+/* General */
+extern struct nfnl_queue_msg * nfnl_queue_msg_alloc(void);
+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 *);
+
+extern void                    nfnl_queue_msg_set_group(struct nfnl_queue_msg *, uint16_t);
+extern int                     nfnl_queue_msg_test_group(const struct nfnl_queue_msg *);
+extern uint16_t                        nfnl_queue_msg_get_group(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_family(struct nfnl_queue_msg *, uint8_t);
+extern int                     nfnl_queue_msg_test_family(const struct nfnl_queue_msg *);
+extern uint8_t                 nfnl_queue_msg_get_family(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *, uint32_t);
+extern int                     nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *);
+extern uint32_t                        nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *, uint16_t);
+extern int                     nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *);
+extern uint16_t                        nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_hook(struct nfnl_queue_msg *, uint8_t);
+extern int                     nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *);
+extern uint8_t                 nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_mark(struct nfnl_queue_msg *, uint32_t);
+extern int                     nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *);
+extern uint32_t                        nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *,
+                                                             struct timeval *);
+extern int                     nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *);
+extern const struct timeval *  nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_indev(struct nfnl_queue_msg *, uint32_t);
+extern int                     nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *);
+extern uint32_t                        nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *, uint32_t);
+extern int                     nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *);
+extern uint32_t                        nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *, uint32_t);
+extern int                     nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *);
+extern uint32_t                        nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *, uint32_t);
+extern int                     nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *);
+extern uint32_t                        nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *);
+
+extern void                    nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *, uint8_t *, int);
+extern int                     nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *);
+extern const uint8_t *         nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *, int *);
+
+extern int                     nfnl_queue_msg_set_payload(struct nfnl_queue_msg *, uint8_t *, int);
+extern int                     nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *);
+extern const void *            nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *, int *);
+
+extern void                    nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *,
+                                                          unsigned int);
+extern int                     nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *);
+extern unsigned int            nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *);
+
+extern struct nl_msg *         nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *);
+extern int                     nfnl_queue_msg_send_verdict(struct nl_sock *,
+                                                           const struct nfnl_queue_msg *);
+extern int                     nfnl_queue_msg_send_verdict_payload(struct nl_sock *,
+                                               const struct nfnl_queue_msg *,
+                                               const void *, unsigned );
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/netlink/netlink-compat.h b/include/netlink/netlink-compat.h
new file mode 100644 (file)
index 0000000..17ec9fc
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * netlink/netlink-compat.h    Netlink Compatability
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_COMPAT_H_
+#define NETLINK_COMPAT_H_
+
+#if !defined _LINUX_SOCKET_H && !defined _BITS_SOCKADDR_H
+typedef unsigned short  sa_family_t;
+#endif
+
+#ifndef IFNAMSIZ 
+/** Maximum length of a interface name */
+#define IFNAMSIZ 16
+#endif
+
+/* patch 2.4.x if_arp */
+#ifndef ARPHRD_INFINIBAND
+#define ARPHRD_INFINIBAND 32
+#endif
+
+/* patch 2.4.x eth header file */
+#ifndef ETH_P_MPLS_UC
+#define ETH_P_MPLS_UC  0x8847 
+#endif
+
+#ifndef ETH_P_MPLS_MC
+#define ETH_P_MPLS_MC   0x8848
+#endif
+
+#ifndef  ETH_P_EDP2
+#define ETH_P_EDP2      0x88A2
+#endif
+
+#ifndef ETH_P_HDLC
+#define ETH_P_HDLC      0x0019 
+#endif
+
+#ifndef AF_LLC
+#define AF_LLC         26
+#endif
+
+#endif
diff --git a/include/netlink/netlink-kernel.h b/include/netlink/netlink-kernel.h
new file mode 100644 (file)
index 0000000..f09051d
--- /dev/null
@@ -0,0 +1,293 @@
+#ifndef __NETLINK_KERNEL_H_
+#define __NETLINK_KERNEL_H_
+
+#if 0
+
+/*
+ * FIXME: Goal is to preseve the documentation but make it simple
+ * to keep linux/netlink.h in sync. Maybe use named documentation
+ * sections.
+ */
+
+/**
+ * Netlink socket address
+ * @ingroup nl
+ */
+struct sockaddr_nl
+{
+       /** socket family (AF_NETLINK) */
+       sa_family_t     nl_family;
+
+       /** Padding (unused) */
+       unsigned short  nl_pad;
+
+       /** Unique process ID  */
+       uint32_t        nl_pid;
+
+       /** Multicast group subscriptions */
+       uint32_t        nl_groups;
+};
+
+/**
+ * @addtogroup msg
+ * @{
+ */
+
+
+/**
+ * Netlink message header
+ */
+struct nlmsghdr
+{
+       /** Length of message including header and padding. */
+       uint32_t        nlmsg_len;
+
+       /** Message type (content type) */
+       uint16_t        nlmsg_type;
+
+       /** Message flags */
+       uint16_t        nlmsg_flags;
+
+       /** Sequence number of message \see core_sk_seq_num. */
+       uint32_t        nlmsg_seq;
+
+       /** Netlink port */
+       uint32_t        nlmsg_pid;
+};
+
+/**
+ * @name Standard message flags
+ * @{
+ */
+
+/**
+ * Must be set on all request messages (typically from user space to
+ * kernel space).
+ */
+#define NLM_F_REQUEST          1
+
+/**
+ * Indicates the message is part of a multipart message terminated
+ * by NLMSG_DONE.
+ */
+#define NLM_F_MULTI            2
+
+/**
+ * Request for an acknowledgment on success.
+ */
+#define NLM_F_ACK              4
+
+/**
+ * Echo this request
+ */
+#define NLM_F_ECHO             8
+
+/** @} */
+
+/**
+ * @name Additional message flags for GET requests
+ * @{
+ */
+
+/**
+ * Return the complete table instead of a single entry.
+ */
+#define NLM_F_ROOT     0x100
+
+/**
+ * Return all entries matching criteria passed in message content.
+ */
+#define NLM_F_MATCH    0x200
+
+/**
+ * Return an atomic snapshot of the table being referenced. This
+ * may require special privileges because it has the potential to
+ * interrupt service in the FE for a longer time.
+ */
+#define NLM_F_ATOMIC   0x400
+
+/**
+ * Dump all entries
+ */
+#define NLM_F_DUMP     (NLM_F_ROOT|NLM_F_MATCH)
+
+/** @} */
+
+/**
+ * @name Additional messsage flags for NEW requests
+ * @{
+ */
+
+/**
+ * Replace existing matching config object with this request.
+ */
+#define NLM_F_REPLACE  0x100
+
+/**
+ * Don't replace the config object if it already exists.
+ */
+#define NLM_F_EXCL     0x200
+
+/**
+ * Create config object if it doesn't already exist.
+ */
+#define NLM_F_CREATE   0x400
+
+/**
+ * Add to the end of the object list.
+ */
+#define NLM_F_APPEND   0x800
+
+/** @} */
+
+/**
+ * @name Standard Message types
+ * @{
+ */
+
+/**
+ * No operation, message must be ignored
+ */
+#define NLMSG_NOOP             0x1
+
+/**
+ * The message signals an error and the payload contains a nlmsgerr
+ * structure. This can be looked at as a NACK and typically it is
+ * from FEC to CPC.
+ */
+#define NLMSG_ERROR            0x2
+
+/**
+ * Message terminates a multipart message.
+ */
+#define NLMSG_DONE             0x3
+
+/**
+ * The message signals that data got lost
+ */
+#define NLMSG_OVERRUN          0x4
+
+/**
+ * Lower limit of reserved message types
+ */
+#define NLMSG_MIN_TYPE         0x10
+
+/** @} */
+
+/**
+ * Netlink error message header
+ */
+struct nlmsgerr
+{
+       /** Error code (errno number) */
+       int             error;
+
+       /** Original netlink message causing the error */
+       struct nlmsghdr msg;
+};
+
+struct nl_pktinfo
+{
+       __u32   group;
+};
+
+/**
+ * Netlink alignment constant, all boundries within messages must be align to this.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLMSG_ALIGNTO  4
+
+/**
+ * Returns \p len properly aligned to NLMSG_ALIGNTO.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+
+/**
+ * Length of a netlink message header including padding.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLMSG_HDRLEN    ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+
+/** @} */
+
+/**
+ * @addtogroup attr
+ * @{
+ */
+
+/*
+ */
+
+/**
+ * Netlink attribute structure
+ *
+ * @code
+ *  <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * |        Header       | Pad |     Payload       | Pad |
+ * |   (struct nlattr)   | ing |                   | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ *  <-------------- nlattr->nla_len -------------->
+ * @endcode
+ */
+struct nlattr {
+       /**
+        * Attribute length in bytes including header
+        */
+       __u16           nla_len;
+
+       /**
+        * Netlink attribute type
+        */
+       __u16           nla_type;
+};
+
+/**
+ * @name Attribute Type Flags
+ *
+ * @code
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ * @endcode
+ *
+ * @note The N and O flag are mutually exclusive.
+ *
+ * @{
+ */
+
+/*
+ */
+#define NLA_F_NESTED           (1 << 15)
+#define NLA_F_NET_BYTEORDER    (1 << 14)
+#define NLA_TYPE_MASK          ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+/** @} */
+
+#define NLA_ALIGNTO            4
+
+/**
+ * Returns \p len properly aligned to NLA_ALIGNTO.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLA_ALIGN(len)         (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+
+/**
+ * Length of a netlink attribute header including padding.
+ *
+ * See \ref core_msg_fmt_align for more information on message alignment.
+ */
+#define NLA_HDRLEN             ((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+/** @} */
+
+#endif
+#endif /* __LINUX_NETLINK_H */
diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h
new file mode 100644 (file)
index 0000000..1d74ba1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * netlink/netlink.h           Netlink Interface
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_NETLINK_H_
+#define NETLINK_NETLINK_H_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <netlink/netlink-compat.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#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>
+#include <netlink/object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ucred;
+struct nl_cache_ops;
+struct nl_parser_param;
+struct nl_object;
+struct nl_sock;
+
+extern int nl_debug;
+extern struct nl_dump_params nl_debug_dp;
+
+/* Connection Management */
+extern int                     nl_connect(struct nl_sock *, int);
+extern void                    nl_close(struct nl_sock *);
+
+/* Send */
+extern int                     nl_sendto(struct nl_sock *, void *, size_t);
+extern int                     nl_sendmsg(struct nl_sock *, struct nl_msg *,
+                                          struct msghdr *);
+extern int                     nl_send(struct nl_sock *, struct nl_msg *);
+extern int                     nl_send_iovec(struct nl_sock *, struct nl_msg *,
+                                             struct iovec *, unsigned);
+extern void                    nl_complete_msg(struct nl_sock *,
+                                               struct nl_msg *);
+extern void                    nl_auto_complete(struct nl_sock *,
+                                                struct nl_msg *);
+extern int                     nl_send_auto(struct nl_sock *, struct nl_msg *);
+extern int                     nl_send_auto_complete(struct nl_sock *,
+                                                     struct nl_msg *);
+extern int                     nl_send_sync(struct nl_sock *, struct nl_msg *);
+extern int                     nl_send_simple(struct nl_sock *, int, int,
+                                              void *, size_t);
+
+/* Receive */
+extern int                     nl_recv(struct nl_sock *,
+                                       struct sockaddr_nl *, unsigned char **,
+                                       struct ucred **);
+
+extern int                     nl_recvmsgs(struct nl_sock *, struct nl_cb *);
+extern int                     nl_recvmsgs_report(struct nl_sock *, struct nl_cb *);
+
+extern int                     nl_recvmsgs_default(struct nl_sock *);
+
+extern int                     nl_wait_for_ack(struct nl_sock *);
+
+extern int                     nl_pickup(struct nl_sock *,
+                                         int (*parser)(struct nl_cache_ops *,
+                                               struct sockaddr_nl *,
+                                               struct nlmsghdr *,
+                                               struct nl_parser_param *),
+                                         struct nl_object **);
+/* Netlink Family Translations */
+extern char *                  nl_nlfamily2str(int, char *, size_t);
+extern int                     nl_str2nlfamily(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/object-api.h b/include/netlink/object-api.h
new file mode 100644 (file)
index 0000000..75f29cb
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * netlink/object-api.h                Object API
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DUMMY_OBJECT_API_H_
+#define NETLINK_DUMMY_OBJECT_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+
+#endif
diff --git a/include/netlink/object.h b/include/netlink/object.h
new file mode 100644 (file)
index 0000000..a95feda
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * netlink/object.c    Generic Cacheable Object
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_OBJECT_H_
+#define NETLINK_OBJECT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nl_cache;
+struct nl_object;
+struct nl_object_ops;
+
+#define OBJ_CAST(ptr)          ((struct nl_object *) (ptr))
+
+/* General */
+extern struct nl_object *      nl_object_alloc(struct nl_object_ops *);
+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 int                     nl_object_update(struct nl_object *dst,
+                                                struct nl_object *src);
+extern void                    nl_object_get(struct nl_object *);
+extern void                    nl_object_put(struct nl_object *);
+extern int                     nl_object_shared(struct nl_object *);
+extern void                    nl_object_dump(struct nl_object *,
+                                              struct nl_dump_params *);
+extern void                    nl_object_dump_buf(struct nl_object *, char *, size_t);
+extern int                     nl_object_identical(struct nl_object *,
+                                                   struct nl_object *);
+extern uint32_t                        nl_object_diff(struct nl_object *,
+                                              struct nl_object *);
+extern int                     nl_object_match_filter(struct nl_object *,
+                                                      struct nl_object *);
+extern char *                  nl_object_attrs2str(struct nl_object *,
+                                                   uint32_t attrs, char *buf,
+                                                   size_t);
+extern char *                  nl_object_attr_list(struct nl_object *,
+                                                   char *, size_t);
+extern void                    nl_object_keygen(struct nl_object *,
+                                                uint32_t *, uint32_t);
+
+/* Marks */
+extern void                    nl_object_mark(struct nl_object *);
+extern void                    nl_object_unmark(struct nl_object *);
+extern int                     nl_object_is_marked(struct nl_object *);
+
+/* Access Functions */
+extern int                     nl_object_get_refcnt(struct nl_object *);
+extern struct nl_cache *       nl_object_get_cache(struct nl_object *);
+extern const char *            nl_object_get_type(const struct nl_object *);
+extern int                     nl_object_get_msgtype(const struct nl_object *);
+struct nl_object_ops *         nl_object_get_ops(const struct nl_object *);
+uint32_t                       nl_object_get_id_attrs(struct nl_object *obj);
+
+
+static inline void *           nl_object_priv(struct nl_object *obj)
+{
+       return obj;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/addr.h b/include/netlink/route/addr.h
new file mode 100644 (file)
index 0000000..56c12e7
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * netlink/route/addr.c                rtnetlink addr layer
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
+ *                         Mediatrix Telecom, inc. <ericb@mediatrix.com>
+ */
+
+#ifndef NETADDR_ADDR_H_
+#define NETADDR_ADDR_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_addr;
+
+/* General */
+extern struct rtnl_addr *rtnl_addr_alloc(void);
+extern void    rtnl_addr_put(struct rtnl_addr *);
+
+extern int     rtnl_addr_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern struct rtnl_addr *
+               rtnl_addr_get(struct nl_cache *, int, struct nl_addr *);
+
+extern int     rtnl_addr_build_add_request(struct rtnl_addr *, int,
+                                           struct nl_msg **);
+extern int     rtnl_addr_add(struct nl_sock *, 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_sock *,
+                                struct rtnl_addr *, int);
+
+extern char *  rtnl_addr_flags2str(int, char *, size_t);
+extern int     rtnl_addr_str2flags(const char *);
+
+extern int     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_link(struct rtnl_addr *, struct rtnl_link *);
+extern struct rtnl_link *
+               rtnl_addr_get_link(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_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 int     rtnl_addr_set_local(struct rtnl_addr *,
+                                           struct nl_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_broadcast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_broadcast(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_anycast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *);
+
+extern uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *);
+extern void    rtnl_addr_set_valid_lifetime(struct rtnl_addr *, uint32_t);
+extern uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *);
+extern void    rtnl_addr_set_preferred_lifetime(struct rtnl_addr *, uint32_t);
+extern uint32_t rtnl_addr_get_create_time(struct rtnl_addr *);
+extern uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/class.h b/include/netlink/route/class.h
new file mode 100644 (file)
index 0000000..e73b60a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * netlink/route/class.h       Traffic Classes
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLASS_H_
+#define NETLINK_CLASS_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_class;
+
+extern struct rtnl_class *
+                       rtnl_class_alloc(void);
+extern void            rtnl_class_put(struct rtnl_class *);
+
+extern int             rtnl_class_alloc_cache(struct nl_sock *, int,
+                                              struct nl_cache **);
+extern struct rtnl_class *
+                       rtnl_class_get(struct nl_cache *, int, uint32_t);
+
+extern struct rtnl_qdisc *
+                       rtnl_class_leaf_qdisc(struct rtnl_class *,
+                                                     struct nl_cache *);
+
+extern int             rtnl_class_build_add_request(struct rtnl_class *, int,
+                                                    struct nl_msg **);
+extern int             rtnl_class_add(struct nl_sock *, struct rtnl_class *,
+                                      int);
+
+extern int             rtnl_class_build_delete_request(struct rtnl_class *,
+                                                       struct nl_msg **);
+extern int             rtnl_class_delete(struct nl_sock *,
+                                         struct rtnl_class *);
+
+/* deprecated functions */
+extern void            rtnl_class_foreach_child(struct rtnl_class *,
+                                                struct nl_cache *,
+                                                void (*cb)(struct nl_object *,
+                                                           void *),
+                                                void *)
+                                                __attribute__((deprecated));
+extern void            rtnl_class_foreach_cls(struct rtnl_class *,
+                                              struct nl_cache *,
+                                              void (*cb)(struct nl_object *,
+                                                         void *),
+                                              void *)
+                                              __attribute__((deprecated));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/classifier.h b/include/netlink/route/classifier.h
new file mode 100644 (file)
index 0000000..647bf1e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * netlink/route/classifier.h       Classifiers
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLASSIFIER_H_
+#define NETLINK_CLASSIFIER_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+#include <netlink/utils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_cls *rtnl_cls_alloc(void);
+extern void            rtnl_cls_put(struct rtnl_cls *);
+
+extern int             rtnl_cls_alloc_cache(struct nl_sock *, int, uint32_t,
+                                            struct nl_cache **);
+
+extern int             rtnl_cls_build_add_request(struct rtnl_cls *, int,
+                                                  struct nl_msg **);
+extern int             rtnl_cls_add(struct nl_sock *, 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_sock *, struct rtnl_cls *,
+                                       int);
+
+extern void            rtnl_cls_set_prio(struct rtnl_cls *, uint16_t);
+extern uint16_t                rtnl_cls_get_prio(struct rtnl_cls *);
+
+extern void            rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t);
+extern uint16_t                rtnl_cls_get_protocol(struct rtnl_cls *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/basic.h b/include/netlink/route/cls/basic.h
new file mode 100644 (file)
index 0000000..603fa88
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * netlink/route/cls/basic.h   Basic Classifier
+ *
+ *     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-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_BASIC_H_
+#define NETLINK_BASIC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/ematch.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void                    rtnl_basic_set_target(struct rtnl_cls *, uint32_t);
+extern uint32_t                        rtnl_basic_get_target(struct rtnl_cls *);
+extern void                    rtnl_basic_set_ematch(struct rtnl_cls *,
+                                                     struct rtnl_ematch_tree *);
+extern struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/cgroup.h b/include/netlink/route/cls/cgroup.h
new file mode 100644 (file)
index 0000000..9cd4845
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * netlink/route/cls/cgroup.h  Control Groups Classifier
+ *
+ *     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) 2009-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_CGROUP_H_
+#define NETLINK_CLS_CGROUP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/ematch.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void                    rtnl_cgroup_set_ematch(struct rtnl_cls *,
+                                               struct rtnl_ematch_tree *);
+struct rtnl_ematch_tree *      rtnl_cgroup_get_ematch(struct rtnl_cls *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/ematch.h b/include/netlink/route/cls/ematch.h
new file mode 100644 (file)
index 0000000..13f9c32
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * netlink/route/cls/ematch.h          Extended Matches
+ *
+ *     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-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_H_
+#define NETLINK_CLS_EMATCH_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/route/classifier.h>
+#include <linux/pkt_cls.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* FIXME: Should be moved to the kernel header at some point */
+#define RTNL_EMATCH_PROGID     2
+
+struct rtnl_ematch;
+struct rtnl_ematch_tree;
+
+/**
+ * Extended Match Operations
+ */
+struct rtnl_ematch_ops
+{
+       int                     eo_kind;
+       const char *            eo_name;
+       size_t                  eo_minlen;
+       size_t                  eo_datalen;
+
+       int                   (*eo_parse)(struct rtnl_ematch *, void *, size_t);
+       void                  (*eo_dump)(struct rtnl_ematch *,
+                                        struct nl_dump_params *);
+       int                   (*eo_fill)(struct rtnl_ematch *, struct nl_msg *);
+       void                  (*eo_free)(struct rtnl_ematch *);
+       struct nl_list_head     eo_list;
+};
+
+extern int                     rtnl_ematch_register(struct rtnl_ematch_ops *);
+extern struct rtnl_ematch_ops *        rtnl_ematch_lookup_ops(int);
+extern struct rtnl_ematch_ops *        rtnl_ematch_lookup_ops_by_name(const char *);
+
+extern struct rtnl_ematch *    rtnl_ematch_alloc(void);
+extern int                     rtnl_ematch_add_child(struct rtnl_ematch *,
+                                                     struct rtnl_ematch *);
+extern void                    rtnl_ematch_unlink(struct rtnl_ematch *);
+extern void                    rtnl_ematch_free(struct rtnl_ematch *);
+
+extern void *                  rtnl_ematch_data(struct rtnl_ematch *);
+extern void                    rtnl_ematch_set_flags(struct rtnl_ematch *,
+                                                     uint16_t);
+extern void                    rtnl_ematch_unset_flags(struct rtnl_ematch *,
+                                                       uint16_t);
+extern uint16_t                        rtnl_ematch_get_flags(struct rtnl_ematch *);
+extern int                     rtnl_ematch_set_ops(struct rtnl_ematch *,
+                                                   struct rtnl_ematch_ops *);
+extern int                     rtnl_ematch_set_kind(struct rtnl_ematch *,
+                                                    uint16_t);
+extern int                     rtnl_ematch_set_name(struct rtnl_ematch *,
+                                                    const char *);
+
+extern struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t);
+extern void                    rtnl_ematch_tree_free(struct rtnl_ematch_tree *);
+extern void                    rtnl_ematch_tree_add(struct rtnl_ematch_tree *,
+                                                    struct rtnl_ematch *);
+
+extern int                     rtnl_ematch_parse_attr(struct nlattr *,
+                                                      struct rtnl_ematch_tree **);
+extern int                     rtnl_ematch_fill_attr(struct nl_msg *, int,
+                                                     struct rtnl_ematch_tree *);
+extern void                    rtnl_ematch_tree_dump(struct rtnl_ematch_tree *,
+                                                     struct nl_dump_params *);
+
+
+extern int                     rtnl_ematch_parse_expr(const char *, char **,
+                                                      struct rtnl_ematch_tree **);
+
+extern char *                  rtnl_ematch_offset2txt(uint8_t, uint16_t,
+                                                      char *, size_t);
+extern char *                  rtnl_ematch_opnd2txt(uint8_t, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/ematch/cmp.h b/include/netlink/route/cls/ematch/cmp.h
new file mode 100644 (file)
index 0000000..308113e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * netlink/route/cls/ematch/cmp.h      Simple Comparison
+ *
+ *     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-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_CMP_H_
+#define NETLINK_CLS_EMATCH_CMP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void    rtnl_ematch_cmp_set(struct rtnl_ematch *,
+                                   struct tcf_em_cmp *);
+extern struct tcf_em_cmp *
+               rtnl_ematch_cmp_get(struct rtnl_ematch *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/ematch/meta.h b/include/netlink/route/cls/ematch/meta.h
new file mode 100644 (file)
index 0000000..2fe5899
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * netlink/route/cls/ematch/meta.h     Metadata Match
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_META_H_
+#define NETLINK_CLS_EMATCH_META_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_meta.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_meta_value;
+
+extern struct rtnl_meta_value *        rtnl_meta_value_alloc_int(uint64_t);
+extern struct rtnl_meta_value *        rtnl_meta_value_alloc_var(void *, size_t);
+extern struct rtnl_meta_value *        rtnl_meta_value_alloc_id(uint8_t, uint16_t,
+                                                         uint8_t, uint64_t);
+extern void    rtnl_meta_value_put(struct rtnl_meta_value *);
+
+extern void    rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *,
+                                           struct rtnl_meta_value *);
+void           rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *,
+                                           struct rtnl_meta_value *);
+extern void    rtnl_ematch_meta_set_operand(struct rtnl_ematch *, uint8_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/ematch/nbyte.h b/include/netlink/route/cls/ematch/nbyte.h
new file mode 100644 (file)
index 0000000..014c719
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * netlink/route/cls/ematch/nbyte.h    N-Byte Comparison
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_NBYTE_H_
+#define NETLINK_CLS_EMATCH_NBYTE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_nbyte.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void            rtnl_ematch_nbyte_set_offset(struct rtnl_ematch *,
+                                                    uint8_t, uint16_t);
+extern uint16_t                rtnl_ematch_nbyte_get_offset(struct rtnl_ematch *);
+extern uint8_t         rtnl_ematch_nbyte_get_layer(struct rtnl_ematch *);
+extern void            rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch *,
+                                                     uint8_t *, size_t);
+extern uint8_t *       rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch *);
+extern size_t          rtnl_ematch_nbyte_get_len(struct rtnl_ematch *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/ematch/text.h b/include/netlink/route/cls/ematch/text.h
new file mode 100644 (file)
index 0000000..e599abf
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * netlink/route/cls/ematch/text.h     Text Search
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_EMATCH_TEXT_H_
+#define NETLINK_CLS_EMATCH_TEXT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_text.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void    rtnl_ematch_text_set_from(struct rtnl_ematch *,
+                                         uint8_t, uint16_t);
+extern uint16_t        rtnl_ematch_text_get_from_offset(struct rtnl_ematch *);
+extern uint8_t rtnl_ematch_text_get_from_layer(struct rtnl_ematch *);
+extern void    rtnl_ematch_text_set_to(struct rtnl_ematch *,
+                                       uint8_t, uint16_t);
+extern uint16_t        rtnl_ematch_text_get_to_offset(struct rtnl_ematch *);
+extern uint8_t rtnl_ematch_text_get_to_layer(struct rtnl_ematch *);
+extern void    rtnl_ematch_text_set_pattern(struct rtnl_ematch *,
+                                            char *, size_t);
+extern char *  rtnl_ematch_text_get_pattern(struct rtnl_ematch *);
+extern size_t  rtnl_ematch_text_get_len(struct rtnl_ematch *);
+extern void    rtnl_ematch_text_set_algo(struct rtnl_ematch *, const char *);
+extern char *  rtnl_ematch_text_get_algo(struct rtnl_ematch *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/fw.h b/include/netlink/route/cls/fw.h
new file mode 100644 (file)
index 0000000..2e1bade
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * netlink/route/cls/fw.h      fw classifier
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
+ * Copyright (c) 2006 Siemens AG Oesterreich
+ */
+
+#ifndef NETLINK_FW_H_
+#define NETLINK_FW_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/classifier.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int     rtnl_fw_set_classid(struct rtnl_cls *, uint32_t);
+extern int     rtnl_fw_set_mask(struct rtnl_cls *, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/police.h b/include/netlink/route/cls/police.h
new file mode 100644 (file)
index 0000000..cd1efb0
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * netlink/route/cls/police.h  Policer
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CLS_POLICE_H_
+#define NETLINK_CLS_POLICE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *  nl_police2str(int, char *, size_t);
+extern int     nl_str2police(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/u32.h b/include/netlink/route/cls/u32.h
new file mode 100644 (file)
index 0000000..59bed33
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * netlink/route/cls/u32.h     u32 classifier
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_U32_H_
+#define NETLINK_U32_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/classifier.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void    rtnl_u32_set_handle(struct rtnl_cls *, int, int, int);
+extern int     rtnl_u32_set_classid(struct rtnl_cls *, uint32_t);
+extern int     rtnl_u32_set_divisor(struct rtnl_cls *, uint32_t);
+extern int     rtnl_u32_set_link(struct rtnl_cls *, uint32_t);
+extern int     rtnl_u32_set_hashtable(struct rtnl_cls *, uint32_t);
+extern int     rtnl_u32_set_hashmask(struct rtnl_cls *, uint32_t, uint32_t);
+extern int     rtnl_u32_set_cls_terminal(struct rtnl_cls *);
+
+extern int     rtnl_u32_set_flags(struct rtnl_cls *, int);
+extern int     rtnl_u32_add_key(struct rtnl_cls *, uint32_t, uint32_t,
+                                int, int);
+extern int     rtnl_u32_add_key_uint8(struct rtnl_cls *, uint8_t, uint8_t,
+                                      int, int);
+extern int     rtnl_u32_add_key_uint16(struct rtnl_cls *, uint16_t, uint16_t,
+                                       int, int);
+extern int     rtnl_u32_add_key_uint32(struct rtnl_cls *, uint32_t, uint32_t,
+                                       int, int);
+extern int     rtnl_u32_add_key_in_addr(struct rtnl_cls *, struct in_addr *,
+                                        uint8_t, int, int);
+extern int     rtnl_u32_add_key_in6_addr(struct rtnl_cls *, struct in6_addr *,
+                                         uint8_t, int, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link.h b/include/netlink/route/link.h
new file mode 100644 (file)
index 0000000..321a80d
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * netlink/route/link.h                Links (Interfaces)
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_H_
+#define NETLINK_LINK_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <linux/if.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @struct rtnl_link link.h "netlink/route/link.h"
+ * @brief Link object
+ * @implements nl_object
+ * @ingroup link
+ *
+ * @copydoc private_struct
+ */
+struct rtnl_link;
+
+/**
+ * @ingroup link
+ */
+typedef enum {
+       RTNL_LINK_RX_PACKETS,           /*!< Packets received */
+       RTNL_LINK_TX_PACKETS,           /*!< Packets sent */
+       RTNL_LINK_RX_BYTES,             /*!< Bytes received */
+       RTNL_LINK_TX_BYTES,             /*!< Bytes sent */
+       RTNL_LINK_RX_ERRORS,            /*!< Receive errors */
+       RTNL_LINK_TX_ERRORS,            /*!< Send errors */
+       RTNL_LINK_RX_DROPPED,           /*!< Received packets dropped */
+       RTNL_LINK_TX_DROPPED,           /*!< Packets dropped during transmit */
+       RTNL_LINK_RX_COMPRESSED,        /*!< Compressed packets received */
+       RTNL_LINK_TX_COMPRESSED,        /*!< Compressed packets sent */
+       RTNL_LINK_RX_FIFO_ERR,          /*!< Receive FIFO errors */
+       RTNL_LINK_TX_FIFO_ERR,          /*!< Send FIFO errors */
+       RTNL_LINK_RX_LEN_ERR,           /*!< Length errors */
+       RTNL_LINK_RX_OVER_ERR,          /*!< Over errors */
+       RTNL_LINK_RX_CRC_ERR,           /*!< CRC errors */
+       RTNL_LINK_RX_FRAME_ERR,         /*!< Frame errors */
+       RTNL_LINK_RX_MISSED_ERR,        /*!< Missed errors */
+       RTNL_LINK_TX_ABORT_ERR,         /*!< Aborted errors */
+       RTNL_LINK_TX_CARRIER_ERR,       /*!< Carrier errors */
+       RTNL_LINK_TX_HBEAT_ERR,         /*!< Heartbeat errors */
+       RTNL_LINK_TX_WIN_ERR,           /*!< Window errors */
+       RTNL_LINK_COLLISIONS,           /*!< Send collisions */
+       RTNL_LINK_MULTICAST,            /*!< Multicast */
+       RTNL_LINK_IP6_INPKTS,           /*!< IPv6 SNMP InReceives */
+       RTNL_LINK_IP6_INHDRERRORS,      /*!< IPv6 SNMP InHdrErrors */
+       RTNL_LINK_IP6_INTOOBIGERRORS,   /*!< IPv6 SNMP InTooBigErrors */
+       RTNL_LINK_IP6_INNOROUTES,       /*!< IPv6 SNMP InNoRoutes */
+       RTNL_LINK_IP6_INADDRERRORS,     /*!< IPv6 SNMP InAddrErrors */
+       RTNL_LINK_IP6_INUNKNOWNPROTOS,  /*!< IPv6 SNMP InUnknownProtos */
+       RTNL_LINK_IP6_INTRUNCATEDPKTS,  /*!< IPv6 SNMP InTruncatedPkts */
+       RTNL_LINK_IP6_INDISCARDS,       /*!< IPv6 SNMP InDiscards */
+       RTNL_LINK_IP6_INDELIVERS,       /*!< IPv6 SNMP InDelivers */
+       RTNL_LINK_IP6_OUTFORWDATAGRAMS, /*!< IPv6 SNMP OutForwDatagrams */
+       RTNL_LINK_IP6_OUTPKTS,          /*!< IPv6 SNMP OutRequests */
+       RTNL_LINK_IP6_OUTDISCARDS,      /*!< IPv6 SNMP OutDiscards */
+       RTNL_LINK_IP6_OUTNOROUTES,      /*!< IPv6 SNMP OutNoRoutes */
+       RTNL_LINK_IP6_REASMTIMEOUT,     /*!< IPv6 SNMP ReasmTimeout */
+       RTNL_LINK_IP6_REASMREQDS,       /*!< IPv6 SNMP ReasmReqds */
+       RTNL_LINK_IP6_REASMOKS,         /*!< IPv6 SNMP ReasmOKs */
+       RTNL_LINK_IP6_REASMFAILS,       /*!< IPv6 SNMP ReasmFails */
+       RTNL_LINK_IP6_FRAGOKS,          /*!< IPv6 SNMP FragOKs */
+       RTNL_LINK_IP6_FRAGFAILS,        /*!< IPv6 SNMP FragFails */
+       RTNL_LINK_IP6_FRAGCREATES,      /*!< IPv6 SNMP FragCreates */
+       RTNL_LINK_IP6_INMCASTPKTS,      /*!< IPv6 SNMP InMcastPkts */
+       RTNL_LINK_IP6_OUTMCASTPKTS,     /*!< IPv6 SNMP OutMcastPkts */
+       RTNL_LINK_IP6_INBCASTPKTS,      /*!< IPv6 SNMP InBcastPkts */
+       RTNL_LINK_IP6_OUTBCASTPKTS,     /*!< IPv6 SNMP OutBcastPkts */
+       RTNL_LINK_IP6_INOCTETS,         /*!< IPv6 SNMP InOctets */
+       RTNL_LINK_IP6_OUTOCTETS,        /*!< IPv6 SNMP OutOctets */
+       RTNL_LINK_IP6_INMCASTOCTETS,    /*!< IPv6 SNMP InMcastOctets */
+       RTNL_LINK_IP6_OUTMCASTOCTETS,   /*!< IPv6 SNMP OutMcastOctets */
+       RTNL_LINK_IP6_INBCASTOCTETS,    /*!< IPv6 SNMP InBcastOctets */
+       RTNL_LINK_IP6_OUTBCASTOCTETS,   /*!< IPv6 SNMP OutBcastOctets */
+       RTNL_LINK_ICMP6_INMSGS,         /*!< ICMPv6 SNMP InMsgs */
+       RTNL_LINK_ICMP6_INERRORS,       /*!< ICMPv6 SNMP InErrors */
+       RTNL_LINK_ICMP6_OUTMSGS,        /*!< ICMPv6 SNMP OutMsgs */
+       RTNL_LINK_ICMP6_OUTERRORS,      /*!< ICMPv6 SNMP OutErrors */
+       __RTNL_LINK_STATS_MAX,
+} rtnl_link_stat_id_t;
+
+#define RTNL_LINK_STATS_MAX (__RTNL_LINK_STATS_MAX - 1)
+
+extern struct rtnl_link *rtnl_link_alloc(void);
+extern void    rtnl_link_put(struct rtnl_link *);
+
+extern int     rtnl_link_alloc_cache(struct nl_sock *, int, 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 *);
+
+
+extern int     rtnl_link_build_add_request(struct rtnl_link *, int,
+                                           struct nl_msg **);
+extern int     rtnl_link_add(struct nl_sock *, 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_sock *, struct rtnl_link *,
+                                struct rtnl_link *, int);
+
+extern int     rtnl_link_build_delete_request(const struct rtnl_link *,
+                                              struct nl_msg **);
+extern int     rtnl_link_delete(struct nl_sock *, const struct rtnl_link *);
+extern int     rtnl_link_build_get_request(int, const char *,
+                                           struct nl_msg **);
+extern int     rtnl_link_get_kernel(struct nl_sock *, int, const char *,
+                                    struct rtnl_link **);
+
+/* 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 *);
+
+/* Name <-> Statistic Translations */
+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_operstate2str(uint8_t, char *, size_t);
+extern int     rtnl_link_str2operstate(const char *);
+
+extern char *  rtnl_link_mode2str(uint8_t, char *, size_t);
+extern int     rtnl_link_str2mode(const char *);
+
+/* Carrier State Translations */
+extern char *  rtnl_link_carrier2str(uint8_t, char *, size_t);
+extern int     rtnl_link_str2carrier(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_name(struct rtnl_link *, const char *);
+extern char *  rtnl_link_get_name(struct rtnl_link *);
+
+extern void    rtnl_link_set_group(struct rtnl_link *, uint32_t);
+extern uint32_t        rtnl_link_get_group(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_txqlen(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_txqlen(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_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_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_master(struct rtnl_link *, int);
+extern int     rtnl_link_get_master(struct rtnl_link *);
+
+extern void    rtnl_link_set_carrier(struct rtnl_link *, uint8_t);
+extern uint8_t rtnl_link_get_carrier(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 const char *    rtnl_link_get_ifalias(struct rtnl_link *);
+extern void            rtnl_link_set_ifalias(struct rtnl_link *, const char *);
+
+extern int             rtnl_link_get_num_vf(struct rtnl_link *, uint32_t *);
+
+extern uint64_t rtnl_link_get_stat(struct rtnl_link *, rtnl_link_stat_id_t);
+extern int     rtnl_link_set_stat(struct rtnl_link *, rtnl_link_stat_id_t,
+                                  const uint64_t);
+
+extern int     rtnl_link_set_type(struct rtnl_link *, const char *);
+extern char *  rtnl_link_get_type(struct rtnl_link *);
+
+extern void    rtnl_link_set_promiscuity(struct rtnl_link *, uint32_t);
+extern uint32_t        rtnl_link_get_promiscuity(struct rtnl_link *);
+
+extern void    rtnl_link_set_num_tx_queues(struct rtnl_link *, uint32_t);
+extern uint32_t        rtnl_link_get_num_tx_queues(struct rtnl_link *);
+
+extern void    rtnl_link_set_num_rx_queues(struct rtnl_link *, uint32_t);
+extern uint32_t        rtnl_link_get_num_rx_queues(struct rtnl_link *);
+
+extern int     rtnl_link_enslave_ifindex(struct nl_sock *, int, int);
+extern int     rtnl_link_enslave(struct nl_sock *, struct rtnl_link *,
+                                 struct rtnl_link *);
+extern int     rtnl_link_release_ifindex(struct nl_sock *, int);
+extern int     rtnl_link_release(struct nl_sock *, struct rtnl_link *);
+
+/* deprecated */
+extern int     rtnl_link_set_info_type(struct rtnl_link *, const char *) __attribute__((deprecated));
+extern char *  rtnl_link_get_info_type(struct rtnl_link *) __attribute__((deprecated));
+extern void    rtnl_link_set_weight(struct rtnl_link *, unsigned int) __attribute__((deprecated));
+extern unsigned int rtnl_link_get_weight(struct rtnl_link *) __attribute__((deprecated));
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/api.h b/include/netlink/route/link/api.h
new file mode 100644 (file)
index 0000000..03b1e5e
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * netlink/route/link/api.h    Link Modules API
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DUMMY_LINK_API_H_
+#define NETLINK_DUMMY_LINK_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#warning "You are including a deprecated header file, include <netlink/route/link.h>."
+
+#endif
diff --git a/include/netlink/route/link/bonding.h b/include/netlink/route/link/bonding.h
new file mode 100644 (file)
index 0000000..5c34662
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * netlink/route/link/bonding.h                Bonding Interface
+ *
+ *     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) 2011-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_BONDING_H_
+#define NETLINK_LINK_BONDING_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_link *rtnl_link_bond_alloc(void);
+
+extern int     rtnl_link_bond_add(struct nl_sock *, const char *,
+                                  struct rtnl_link *);
+
+extern int     rtnl_link_bond_enslave_ifindex(struct nl_sock *, int, int);
+extern int     rtnl_link_bond_enslave(struct nl_sock *, struct rtnl_link *,
+                                      struct rtnl_link *);
+
+extern int     rtnl_link_bond_release_ifindex(struct nl_sock *, int);
+extern int     rtnl_link_bond_release(struct nl_sock *, struct rtnl_link *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/netlink/route/link/bridge.h b/include/netlink/route/link/bridge.h
new file mode 100644 (file)
index 0000000..71dcc24
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * netlink/route/link/bridge.h         Bridge
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_BRIDGE_H_
+#define NETLINK_LINK_BRIDGE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Bridge flags
+ * @ingroup bridge
+ */
+enum rtnl_link_bridge_flags {
+       RTNL_BRIDGE_HAIRPIN_MODE        = 0x0001,
+       RTNL_BRIDGE_BPDU_GUARD          = 0x0002,
+       RTNL_BRIDGE_ROOT_BLOCK          = 0x0004,
+       RTNL_BRIDGE_FAST_LEAVE          = 0x0008,
+};
+
+extern struct rtnl_link *rtnl_link_bridge_alloc(void);
+
+extern int     rtnl_link_is_bridge(struct rtnl_link *);
+extern int     rtnl_link_bridge_has_ext_info(struct rtnl_link *);
+
+extern int     rtnl_link_bridge_set_port_state(struct rtnl_link *, uint8_t );
+extern int     rtnl_link_bridge_get_port_state(struct rtnl_link *);
+
+extern int     rtnl_link_bridge_set_priority(struct rtnl_link *, uint16_t);
+extern int     rtnl_link_bridge_get_priority(struct rtnl_link *);
+
+extern int     rtnl_link_bridge_set_cost(struct rtnl_link *, uint32_t);
+extern int     rtnl_link_bridge_get_cost(struct rtnl_link *, uint32_t *);
+
+extern int     rtnl_link_bridge_unset_flags(struct rtnl_link *, unsigned int);
+extern int     rtnl_link_bridge_set_flags(struct rtnl_link *, unsigned int);
+extern int     rtnl_link_bridge_get_flags(struct rtnl_link *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/netlink/route/link/can.h b/include/netlink/route/link/can.h
new file mode 100644 (file)
index 0000000..61c9f47
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * netlink/route/link/can.h            CAN interface
+ *
+ *     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) 2012 Benedikt Spranger <b.spranger@linutronix.de>
+ */
+
+#ifndef NETLINK_LINK_CAN_H_
+#define NETLINK_LINK_CAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <linux/can/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_link_is_can(struct rtnl_link *link);
+
+extern char *rtnl_link_can_ctrlmode2str(int, char *, size_t);
+extern int rtnl_link_can_str2ctrlmode(const char *);
+
+extern int rtnl_link_can_restart(struct rtnl_link *);
+extern int rtnl_link_can_freq(struct rtnl_link *, uint32_t *);
+extern int rtnl_link_can_state(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_can_berr_rx(struct rtnl_link *);
+extern int rtnl_link_can_berr_tx(struct rtnl_link *);
+extern int rtnl_link_can_berr(struct rtnl_link *, struct can_berr_counter *);
+
+extern int rtnl_link_can_get_bt_const(struct rtnl_link *,
+                                     struct can_bittiming_const *);
+extern int rtnl_link_can_get_bittiming(struct rtnl_link *,
+                                      struct can_bittiming *);
+extern int rtnl_link_can_set_bittiming(struct rtnl_link *,
+                                      struct can_bittiming *);
+
+extern int rtnl_link_can_get_bitrate(struct rtnl_link *, uint32_t *);
+extern int rtnl_link_can_set_bitrate(struct rtnl_link *, uint32_t);
+
+extern int rtnl_link_can_get_sample_point(struct rtnl_link *, uint32_t *);
+extern int rtnl_link_can_set_sample_point(struct rtnl_link *, uint32_t);
+
+extern int rtnl_link_can_get_restart_ms(struct rtnl_link *, uint32_t *);
+extern int rtnl_link_can_set_restart_ms(struct rtnl_link *, uint32_t);
+
+extern int rtnl_link_can_get_ctrlmode(struct rtnl_link *, uint32_t *);
+extern int rtnl_link_can_set_ctrlmode(struct rtnl_link *, uint32_t);
+extern int rtnl_link_can_unset_ctrlmode(struct rtnl_link *, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/inet.h b/include/netlink/route/link/inet.h
new file mode 100644 (file)
index 0000000..506542f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * netlink/route/link/inet.h   INET Link Module
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_INET_H_
+#define NETLINK_LINK_INET_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *    rtnl_link_inet_devconf2str(int, char *, size_t);
+extern int             rtnl_link_inet_str2devconf(const char *);
+
+extern int             rtnl_link_inet_get_conf(struct rtnl_link *,
+                                               const unsigned int, uint32_t *);
+extern int             rtnl_link_inet_set_conf(struct rtnl_link *,
+                                               const unsigned int, uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/info-api.h b/include/netlink/route/link/info-api.h
new file mode 100644 (file)
index 0000000..1087ad4
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * netlink/route/link/info-api.h       Link Modules API
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DUMMY_LINK_INFO_API_H_
+#define NETLINK_DUMMY_LINK_INFO_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#warning "You are including a deprecated header file, include <netlink/route/link.h>."
+
+#endif
diff --git a/include/netlink/route/link/vlan.h b/include/netlink/route/link/vlan.h
new file mode 100644 (file)
index 0000000..f274163
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * netlink/route/link/vlan.h           VLAN interface
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_VLAN_H_
+#define NETLINK_LINK_VLAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct vlan_map
+{
+       uint32_t                vm_from;
+       uint32_t                vm_to;
+};
+
+#define VLAN_PRIO_MAX 7
+
+extern struct rtnl_link *rtnl_link_vlan_alloc(void);
+
+extern int             rtnl_link_is_vlan(struct rtnl_link *);
+
+extern char *          rtnl_link_vlan_flags2str(int, char *, size_t);
+extern int             rtnl_link_vlan_str2flags(const char *);
+
+extern int             rtnl_link_vlan_set_id(struct rtnl_link *, uint16_t);
+extern int             rtnl_link_vlan_get_id(struct rtnl_link *);
+
+extern int             rtnl_link_vlan_set_flags(struct rtnl_link *,
+                                                unsigned int);
+extern int             rtnl_link_vlan_unset_flags(struct rtnl_link *,
+                                                  unsigned int);
+extern int             rtnl_link_vlan_get_flags(struct rtnl_link *);
+
+extern int             rtnl_link_vlan_set_ingress_map(struct rtnl_link *,
+                                                      int, uint32_t);
+extern uint32_t *      rtnl_link_vlan_get_ingress_map(struct rtnl_link *);
+
+extern int             rtnl_link_vlan_set_egress_map(struct rtnl_link *,
+                                                     uint32_t, int);
+extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *,
+                                                     int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/neighbour.h b/include/netlink/route/neighbour.h
new file mode 100644 (file)
index 0000000..1d1179b
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * netlink/route/neighbour.h   Neighbours
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_NEIGHBOUR_H_
+#define NETLINK_NEIGHBOUR_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_neigh;
+
+extern struct rtnl_neigh *rtnl_neigh_alloc(void);
+extern void    rtnl_neigh_put(struct rtnl_neigh *);
+
+extern int     rtnl_neigh_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern struct rtnl_neigh *rtnl_neigh_get(struct nl_cache *, int,
+                                              struct nl_addr *);
+
+extern int      rtnl_neigh_parse(struct nlmsghdr *, struct rtnl_neigh **);
+
+extern char *  rtnl_neigh_state2str(int, char *, size_t);
+extern int     rtnl_neigh_str2state(const char *);
+
+extern char *  rtnl_neigh_flags2str(int, char *, size_t);
+extern int     rtnl_neigh_str2flag(const char *);
+
+extern int     rtnl_neigh_add(struct nl_sock *, struct rtnl_neigh *, int);
+extern int     rtnl_neigh_build_add_request(struct rtnl_neigh *, int,
+                                            struct nl_msg **);
+
+extern int     rtnl_neigh_delete(struct nl_sock *, struct rtnl_neigh *, int);
+extern int     rtnl_neigh_build_delete_request(struct rtnl_neigh *, int,
+                                               struct nl_msg **);
+
+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 *,
+                                                      int);
+
+extern void                    rtnl_neigh_set_flags(struct rtnl_neigh *,
+                                                    unsigned int);
+extern void                    rtnl_neigh_unset_flags(struct rtnl_neigh *,
+                                                      unsigned int);
+extern unsigned int            rtnl_neigh_get_flags(struct rtnl_neigh *);
+
+extern void                    rtnl_neigh_set_ifindex(struct rtnl_neigh *,
+                                                      int);
+extern int                     rtnl_neigh_get_ifindex(struct rtnl_neigh *);
+
+extern void                    rtnl_neigh_set_lladdr(struct rtnl_neigh *,
+                                                     struct nl_addr *);
+extern struct nl_addr *                rtnl_neigh_get_lladdr(struct rtnl_neigh *);
+
+extern int                     rtnl_neigh_set_dst(struct rtnl_neigh *,
+                                                  struct nl_addr *);
+extern struct nl_addr *                rtnl_neigh_get_dst(struct rtnl_neigh *);
+
+extern void                    rtnl_neigh_set_type(struct rtnl_neigh *, int);
+extern int                     rtnl_neigh_get_type(struct rtnl_neigh *);
+
+extern void                    rtnl_neigh_set_family(struct rtnl_neigh *, int);
+extern int                     rtnl_neigh_get_family(struct rtnl_neigh *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/neightbl.h b/include/netlink/route/neightbl.h
new file mode 100644 (file)
index 0000000..412c3e9
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * netlink/route/neightbl.h    Neighbour Tables
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_NEIGHTBL_H_
+#define NETLINK_NEIGHTBL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_neightbl;
+
+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 int rtnl_neightbl_alloc_cache(struct nl_sock *, 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 int rtnl_neightbl_build_change_request(struct rtnl_neightbl *,
+                                             struct rtnl_neightbl *,
+                                             struct nl_msg **);
+extern int rtnl_neightbl_change(struct nl_sock *, struct rtnl_neightbl *,
+                               struct rtnl_neightbl *);
+
+extern void rtnl_neightbl_set_family(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_name(struct rtnl_neightbl *, const char *);
+extern void rtnl_neightbl_set_dev(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_app_probes(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl *,
+                                                 uint64_t);
+extern void rtnl_neightbl_set_retrans_time(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl *,
+                                              uint64_t);
+extern void rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl *, uint64_t);
+extern void rtnl_neightbl_set_locktime(struct rtnl_neightbl *, uint64_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/nexthop.h b/include/netlink/route/nexthop.h
new file mode 100644 (file)
index 0000000..2aa44dc
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * netlink/route/nexthop.h     Routing Nexthop
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ROUTE_NEXTHOP_H_
+#define NETLINK_ROUTE_NEXTHOP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/addr.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_nexthop;
+
+enum {
+       NH_DUMP_FROM_ONELINE = -2,
+       NH_DUMP_FROM_DETAILS = -1,
+       NH_DUMP_FROM_ENV = 0,
+       /* > 0 reserved for nexthop index */
+};
+
+extern struct rtnl_nexthop * rtnl_route_nh_alloc(void);
+extern struct rtnl_nexthop * rtnl_route_nh_clone(struct rtnl_nexthop *);
+extern void            rtnl_route_nh_free(struct rtnl_nexthop *);
+
+extern int             rtnl_route_nh_compare(struct rtnl_nexthop *,
+                                             struct rtnl_nexthop *,
+                                             uint32_t, int);
+
+extern void            rtnl_route_nh_dump(struct rtnl_nexthop *,
+                                          struct nl_dump_params *);
+
+extern void            rtnl_route_nh_set_weight(struct rtnl_nexthop *, uint8_t);
+extern uint8_t         rtnl_route_nh_get_weight(struct rtnl_nexthop *);
+extern void            rtnl_route_nh_set_ifindex(struct rtnl_nexthop *, int);
+extern int             rtnl_route_nh_get_ifindex(struct rtnl_nexthop *);
+extern void            rtnl_route_nh_set_gateway(struct rtnl_nexthop *,
+                                                 struct nl_addr *);
+extern struct nl_addr *        rtnl_route_nh_get_gateway(struct rtnl_nexthop *);
+extern void            rtnl_route_nh_set_flags(struct rtnl_nexthop *,
+                                               unsigned int);
+extern void            rtnl_route_nh_unset_flags(struct rtnl_nexthop *,
+                                                 unsigned int);
+extern unsigned int    rtnl_route_nh_get_flags(struct rtnl_nexthop *);
+extern void            rtnl_route_nh_set_realms(struct rtnl_nexthop *,
+                                                uint32_t);
+extern uint32_t                rtnl_route_nh_get_realms(struct rtnl_nexthop *);
+
+extern char *          rtnl_route_nh_flags2str(int, char *, size_t);
+extern int             rtnl_route_nh_str2flags(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/pktloc.h b/include/netlink/route/pktloc.h
new file mode 100644 (file)
index 0000000..c3768ce
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * netlink/route/pktloc.h         Packet Location Aliasing
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_PKTLOC_H_
+#define NETLINK_PKTLOC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_pktloc
+{
+       char *                  name;
+       uint8_t                 layer;
+       uint8_t                 shift;
+       uint16_t                offset;
+       uint16_t                align;
+       uint32_t                mask;
+       uint32_t                refcnt;
+
+       struct nl_list_head     list;
+};
+
+extern int     rtnl_pktloc_lookup(const char *, struct rtnl_pktloc **);
+extern struct rtnl_pktloc *rtnl_pktloc_alloc(void);
+extern void    rtnl_pktloc_put(struct rtnl_pktloc *);
+extern int     rtnl_pktloc_add(struct rtnl_pktloc *);
+extern void    rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *),
+                                   void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc.h b/include/netlink/route/qdisc.h
new file mode 100644 (file)
index 0000000..10b85c5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * netlink/route/qdisc.h         Queueing Disciplines
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_QDISC_H_
+#define NETLINK_QDISC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/tc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_qdisc;
+
+extern struct rtnl_qdisc *
+               rtnl_qdisc_alloc(void);
+extern void    rtnl_qdisc_put(struct rtnl_qdisc *);
+
+extern int     rtnl_qdisc_alloc_cache(struct nl_sock *, 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);
+
+extern int     rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int,
+                                            struct nl_msg **);
+extern int     rtnl_qdisc_add(struct nl_sock *, struct rtnl_qdisc *, int);
+
+extern int     rtnl_qdisc_build_update_request(struct rtnl_qdisc *,
+                                               struct rtnl_qdisc *,
+                                               int, struct nl_msg **);
+
+extern int     rtnl_qdisc_update(struct nl_sock *, struct rtnl_qdisc *,
+                                 struct rtnl_qdisc *, int);
+
+extern int     rtnl_qdisc_build_delete_request(struct rtnl_qdisc *,
+                                               struct nl_msg **);
+extern int     rtnl_qdisc_delete(struct nl_sock *, struct rtnl_qdisc *);
+
+/* Deprecated functions */
+extern void rtnl_qdisc_foreach_child(struct rtnl_qdisc *, struct nl_cache *,
+                                    void (*cb)(struct nl_object *, void *),
+                                    void *) __attribute__ ((deprecated));
+
+extern void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, struct nl_cache *,
+                                  void (*cb)(struct nl_object *, void *),
+                                  void *) __attribute__ ((deprecated));
+
+extern int rtnl_qdisc_build_change_request(struct rtnl_qdisc *,
+                                          struct rtnl_qdisc *,
+                                          struct nl_msg **)
+                                          __attribute__ ((deprecated));
+
+extern int rtnl_qdisc_change(struct nl_sock *, struct rtnl_qdisc *,
+                            struct rtnl_qdisc *) __attribute__ ((deprecated));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/cbq.h b/include/netlink/route/qdisc/cbq.h
new file mode 100644 (file)
index 0000000..3dbdd2d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * netlink/route/sch/cbq.h     Class Based Queueing
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_CBQ_H_
+#define NETLINK_CBQ_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char * nl_ovl_strategy2str(int, char *, size_t);
+extern int    nl_str2ovl_strategy(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/dsmark.h b/include/netlink/route/qdisc/dsmark.h
new file mode 100644 (file)
index 0000000..06bd9d3
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * netlink/route/sch/dsmark.h  DSMARK
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DSMARK_H_
+#define NETLINK_DSMARK_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int     rtnl_class_dsmark_set_bitmask(struct rtnl_class *, uint8_t);
+extern int     rtnl_class_dsmark_get_bitmask(struct rtnl_class *);
+
+extern int     rtnl_class_dsmark_set_value(struct rtnl_class *, uint8_t);
+extern int     rtnl_class_dsmark_get_value(struct rtnl_class *);
+
+extern int     rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *, uint16_t);
+extern int     rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *);
+
+extern int     rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *,
+                                                   uint16_t);
+extern int     rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *);
+
+extern int     rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *, int);
+extern int     rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/fifo.h b/include/netlink/route/qdisc/fifo.h
new file mode 100644 (file)
index 0000000..c033427
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * netlink/route/sch/fifo.c    FIFO Qdisc
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_FIFO_H_
+#define NETLINK_FIFO_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int     rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *, int);
+extern int     rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/htb.h b/include/netlink/route/qdisc/htb.h
new file mode 100644 (file)
index 0000000..c909f84
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * netlink/route/sch/htb.h     HTB Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2005 Petr Gotthard <petr.gotthard@siemens.com>
+ * Copyright (c) 2005 Siemens AG Oesterreich
+ */
+
+#ifndef NETLINK_HTB_H_
+#define NETLINK_HTB_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint32_t        rtnl_htb_get_rate2quantum(struct rtnl_qdisc *);
+extern int     rtnl_htb_set_rate2quantum(struct rtnl_qdisc *, uint32_t);
+extern uint32_t        rtnl_htb_get_defcls(struct rtnl_qdisc *);
+extern int     rtnl_htb_set_defcls(struct rtnl_qdisc *, uint32_t);
+
+extern uint32_t        rtnl_htb_get_prio(struct rtnl_class *);
+extern int     rtnl_htb_set_prio(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_rate(struct rtnl_class *);
+extern int     rtnl_htb_set_rate(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_ceil(struct rtnl_class *);
+extern int     rtnl_htb_set_ceil(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_rbuffer(struct rtnl_class *);
+extern int     rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_cbuffer(struct rtnl_class *);
+extern int     rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_quantum(struct rtnl_class *);
+extern int     rtnl_htb_set_quantum(struct rtnl_class *, uint32_t);
+extern int     rtnl_htb_get_level(struct rtnl_class *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/netem.h b/include/netlink/route/qdisc/netem.h
new file mode 100644 (file)
index 0000000..4b071bf
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * netlink/route/sch/netem.h           Network Emulator Qdisc
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_NETEM_H_
+#define NETLINK_NETEM_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void rtnl_netem_set_limit(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_limit(struct rtnl_qdisc *);
+
+/* Packet Re-ordering */
+extern void rtnl_netem_set_gap(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_gap(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *);
+
+/* Corruption */
+extern void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *);
+
+/* Packet Loss */
+extern void rtnl_netem_set_loss(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_loss(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *);
+
+/* Packet Duplication */
+extern void rtnl_netem_set_duplicate(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_duplicate(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *);
+
+/* Packet Delay */
+extern void rtnl_netem_set_delay(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_delay(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_jitter(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_jitter(struct rtnl_qdisc *);
+
+extern void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int);
+extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *);
+
+/* Delay Distribution */
+#define MAXDIST 65536
+extern int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *, const char *);
+extern int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *);
+extern int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *, int16_t **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/plug.h b/include/netlink/route/qdisc/plug.h
new file mode 100644 (file)
index 0000000..40f7e53
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * netlink/route/qdisc/plug.c  PLUG Qdisc
+ *
+ *     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) 2012 Shriram Rajagopalan <rshriram@cs.ubc.ca>
+ */
+
+#ifndef NETLINK_PLUG_H_
+#define NETLINK_PLUG_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int     rtnl_qdisc_plug_set_limit(struct rtnl_qdisc *, int);
+extern int     rtnl_qdisc_plug_buffer(struct rtnl_qdisc *);
+extern int     rtnl_qdisc_plug_release_one(struct rtnl_qdisc *);
+extern int     rtnl_qdisc_plug_release_indefinite(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/prio.h b/include/netlink/route/qdisc/prio.h
new file mode 100644 (file)
index 0000000..636a8f9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * netlink/route/sch/prio.c    PRIO Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_PRIO_H_
+#define NETLINK_PRIO_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Default Values
+ * @{
+ */
+
+/**
+ * Default number of bands.
+ * @ingroup prio
+ */
+#define QDISC_PRIO_DEFAULT_BANDS 3
+
+/**
+ * Default priority mapping.
+ * @ingroup prio
+ */
+#define QDISC_PRIO_DEFAULT_PRIOMAP \
+               { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }
+
+/** @} */
+
+extern void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *, int);
+extern int  rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *);
+extern int  rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *, uint8_t[], int);
+extern uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *);
+
+extern char *  rtnl_prio2str(int, char *, size_t);
+extern int     rtnl_str2prio(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/red.h b/include/netlink/route/qdisc/red.h
new file mode 100644 (file)
index 0000000..a4e8642
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * netlink/route/sch/red.h     RED Qdisc
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_RED_H_
+#define NETLINK_RED_H_
+
+#include <netlink/netlink.h>
+
+#endif
diff --git a/include/netlink/route/qdisc/sfq.h b/include/netlink/route/qdisc/sfq.h
new file mode 100644 (file)
index 0000000..77d2e29
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/sch/sfq.c     SFQ Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_SFQ_H_
+#define NETLINK_SFQ_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void    rtnl_sfq_set_quantum(struct rtnl_qdisc *, int);
+extern int     rtnl_sfq_get_quantum(struct rtnl_qdisc *);
+
+extern void    rtnl_sfq_set_limit(struct rtnl_qdisc *, int);
+extern int     rtnl_sfq_get_limit(struct rtnl_qdisc *);
+
+extern void    rtnl_sfq_set_perturb(struct rtnl_qdisc *, int);
+extern int     rtnl_sfq_get_perturb(struct rtnl_qdisc *);
+
+extern int     rtnl_sfq_get_divisor(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/tbf.h b/include/netlink/route/qdisc/tbf.h
new file mode 100644 (file)
index 0000000..ce31c54
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * netlink/route/sch/tbf.h     TBF Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_TBF_H_
+#define NETLINK_TBF_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *, int);
+extern int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *, int);
+extern int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *);
+
+extern void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *, int, int, int);
+extern int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *);
+
+extern int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *, int, int, int);
+extern int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *);
+extern int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h
new file mode 100644 (file)
index 0000000..477250d
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * netlink/route/route.h       Routes
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_ROUTE_H_
+#define NETLINK_ROUTE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/data.h>
+#include <netlink/route/nexthop.h>
+#include <netlink/route/rtnl.h>
+#include <linux/in_route.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @ingroup route
+ * When passed to rtnl_route_alloc_cache() the cache will
+ * correspond to the contents of the routing cache instead
+ * of the actual routes.
+ */
+#define ROUTE_CACHE_CONTENT    1
+
+struct rtnl_route;
+
+struct rtnl_rtcacheinfo
+{
+       uint32_t        rtci_clntref;
+       uint32_t        rtci_last_use;
+       uint32_t        rtci_expires;
+       int32_t         rtci_error;
+       uint32_t        rtci_used;
+       uint32_t        rtci_id;
+       uint32_t        rtci_ts;
+       uint32_t        rtci_tsage;
+};
+
+extern struct nl_object_ops route_obj_ops;
+
+extern struct rtnl_route *     rtnl_route_alloc(void);
+extern void    rtnl_route_put(struct rtnl_route *);
+extern int     rtnl_route_alloc_cache(struct nl_sock *, int, int,
+                                      struct nl_cache **);
+
+extern void    rtnl_route_get(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 int     rtnl_route_build_add_request(struct rtnl_route *, int,
+                                            struct nl_msg **);
+extern int     rtnl_route_add(struct nl_sock *, 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_sock *, 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_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,
+                                 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 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_metric2str(int, char *, size_t);
+extern int     rtnl_route_str2metric(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/rtnl.h b/include/netlink/route/rtnl.h
new file mode 100644 (file)
index 0000000..f551a5d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * netlink/route/rtnl.h                Routing Netlink
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_RTNL_H_
+#define NETLINK_RTNL_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Realms
+ * @{
+ */
+
+/**
+ * Mask specying the size of each realm part
+ * @ingroup rtnl
+ */
+#define RTNL_REALM_MASK (0xFFFF)
+
+/**
+ * Extract FROM realm from a realms field
+ */
+#define RTNL_REALM_FROM(realm) ((realm) >> 16)
+
+/**
+ * Extract TO realm from a realms field
+ */
+#define RTNL_REALM_TO(realm) ((realm) & RTNL_REALM_MASK)
+
+/**
+ * Build a realms field
+ */
+#define RTNL_MAKE_REALM(from, to) \
+       ((RTNL_REALM_TO(from) << 16) & RTNL_REALM_TO(to))
+
+/** @} */
+
+
+/* General */
+extern int             nl_rtgen_request(struct nl_sock *, int, int, int);
+
+/* Routing Type Translations */
+extern char *          nl_rtntype2str(int, char *, size_t);
+extern int             nl_str2rtntype(const char *);
+
+/* Scope Translations */
+extern char *          rtnl_scope2str(int, char *, size_t);
+extern int             rtnl_str2scope(const char *);
+
+/* Realms Translations */
+extern char *          rtnl_realms2str(uint32_t, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/rule.h b/include/netlink/route/rule.h
new file mode 100644 (file)
index 0000000..760b782
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * netlink/route/rule.h                Rules
+ *
+ *     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) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_RULE_H_
+#define NETLINK_RULE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/route/route.h>
+#include <linux/fib_rules.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_rule;
+
+/* General */
+extern struct rtnl_rule *      rtnl_rule_alloc(void);
+extern void                    rtnl_rule_put(struct rtnl_rule *);
+
+extern int     rtnl_rule_alloc_cache(struct nl_sock *, int,
+                                     struct nl_cache **);
+extern void rtnl_rule_dump(struct rtnl_rule *, FILE *, struct nl_dump_params *);
+
+extern int     rtnl_rule_build_add_request(struct rtnl_rule *, int,
+                                           struct nl_msg **);
+extern int rtnl_rule_add(struct nl_sock *, 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_sock *, struct rtnl_rule *, int);
+
+
+/* attribute modification */
+extern void            rtnl_rule_set_family(struct rtnl_rule *, int);
+extern int             rtnl_rule_get_family(struct rtnl_rule *);
+extern void            rtnl_rule_set_prio(struct rtnl_rule *, uint32_t);
+extern uint32_t                rtnl_rule_get_prio(struct rtnl_rule *);
+extern void            rtnl_rule_set_mark(struct rtnl_rule *, uint32_t);
+extern uint32_t                rtnl_rule_get_mark(struct rtnl_rule *);
+extern void            rtnl_rule_set_mask(struct rtnl_rule *, uint32_t);
+extern uint32_t                rtnl_rule_get_mask(struct rtnl_rule *);
+extern void            rtnl_rule_set_table(struct rtnl_rule *, uint32_t);
+extern uint32_t                rtnl_rule_get_table(struct rtnl_rule *);
+extern void            rtnl_rule_set_dsfield(struct rtnl_rule *, uint8_t);
+extern uint8_t         rtnl_rule_get_dsfield(struct rtnl_rule *);
+extern int             rtnl_rule_set_src(struct rtnl_rule *, struct nl_addr *);
+extern struct nl_addr *        rtnl_rule_get_src(struct rtnl_rule *);
+extern int             rtnl_rule_set_dst(struct rtnl_rule *, struct nl_addr *);
+extern struct nl_addr *        rtnl_rule_get_dst(struct rtnl_rule *);
+extern void            rtnl_rule_set_action(struct rtnl_rule *, uint8_t);
+extern uint8_t         rtnl_rule_get_action(struct rtnl_rule *);
+extern int             rtnl_rule_set_iif(struct rtnl_rule *, const char *);
+extern char *          rtnl_rule_get_iif(struct rtnl_rule *);
+extern int             rtnl_rule_set_oif(struct rtnl_rule *, const char *);
+extern char *          rtnl_rule_get_oif(struct rtnl_rule *);
+extern void            rtnl_rule_set_realms(struct rtnl_rule *, uint32_t);
+extern uint32_t                rtnl_rule_get_realms(struct rtnl_rule *);
+extern void            rtnl_rule_set_goto(struct rtnl_rule *, uint32_t);
+extern uint32_t                rtnl_rule_get_goto(struct rtnl_rule *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/tc-api.h b/include/netlink/route/tc-api.h
new file mode 100644 (file)
index 0000000..b7771b5
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * netlink/route/tc-api.h      Traffic Control API
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_DUMMY_TC_API_H_
+#define NETLINK_DUMMY_TC_API_H_
+
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
+#include <netlink/route/tc.h>
+
+#warning "You are including a deprecated header file, include <netlink/route/tc.h>."
+
+#endif
diff --git a/include/netlink/route/tc.h b/include/netlink/route/tc.h
new file mode 100644 (file)
index 0000000..836f7b1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * netlink/route/tc.h          Traffic Control
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_TC_H_
+#define NETLINK_TC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/data.h>
+#include <netlink/route/link.h>
+#include <linux/pkt_sched.h>
+#include <linux/pkt_cls.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum rtnl_tc_type {
+       RTNL_TC_TYPE_QDISC,
+       RTNL_TC_TYPE_CLASS,
+       RTNL_TC_TYPE_CLS,
+       __RTNL_TC_TYPE_MAX,
+};
+
+#define RTNL_TC_TYPE_MAX (__RTNL_TC_TYPE_MAX - 1)
+
+/**
+ * Compute tc handle based on major and minor parts
+ * @ingroup tc
+ */
+#define TC_HANDLE(maj, min)    (TC_H_MAJ((maj) << 16) | TC_H_MIN(min))
+
+/**
+ * Traffic control object
+ * @ingroup tc
+ */
+struct rtnl_tc;
+
+/**
+ * Macro to cast qdisc/class/classifier to tc object
+ * @ingroup tc
+ *
+ * @code
+ * rtnl_tc_set_mpu(TC_CAST(qdisc), 40);
+ * @endcode
+ */
+#define TC_CAST(ptr)           ((struct rtnl_tc *) (ptr))
+
+/**
+ * Traffic control statistical identifier
+ * @ingroup tc
+ *
+ * @code
+ * uint64_t n = rtnl_tc_get_stat(TC_CAST(class), RTNL_TC_PACKETS);
+ * @endcode
+ */
+enum rtnl_tc_stat {
+       RTNL_TC_PACKETS,        /**< Number of packets seen */
+       RTNL_TC_BYTES,          /**< Total bytes seen */
+       RTNL_TC_RATE_BPS,       /**< Current bits/s (rate estimator) */
+       RTNL_TC_RATE_PPS,       /**< Current packet/s (rate estimator) */
+       RTNL_TC_QLEN,           /**< Current queue length */
+       RTNL_TC_BACKLOG,        /**< Current backlog length */
+       RTNL_TC_DROPS,          /**< Total number of packets dropped */
+       RTNL_TC_REQUEUES,       /**< Total number of requeues */
+       RTNL_TC_OVERLIMITS,     /**< Total number of overlimits */
+       __RTNL_TC_STATS_MAX,
+};
+
+#define RTNL_TC_STATS_MAX (__RTNL_TC_STATS_MAX - 1)
+
+extern void            rtnl_tc_set_ifindex(struct rtnl_tc *, int);
+extern int             rtnl_tc_get_ifindex(struct rtnl_tc *);
+extern void            rtnl_tc_set_link(struct rtnl_tc *, struct rtnl_link *);
+extern struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *);
+extern void            rtnl_tc_set_mtu(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_mtu(struct rtnl_tc *);
+extern void            rtnl_tc_set_mpu(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_mpu(struct rtnl_tc *);
+extern void            rtnl_tc_set_overhead(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_overhead(struct rtnl_tc *);
+extern void            rtnl_tc_set_linktype(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_linktype(struct rtnl_tc *);
+extern void            rtnl_tc_set_handle(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_handle(struct rtnl_tc *);
+extern void            rtnl_tc_set_parent(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_parent(struct rtnl_tc *);
+extern int             rtnl_tc_set_kind(struct rtnl_tc *, const char *);
+extern char *          rtnl_tc_get_kind(struct rtnl_tc *);
+extern uint64_t                rtnl_tc_get_stat(struct rtnl_tc *, enum rtnl_tc_stat);
+
+extern int             rtnl_tc_calc_txtime(int, int);
+extern int             rtnl_tc_calc_bufsize(int, int);
+extern int             rtnl_tc_calc_cell_log(int);
+
+extern int             rtnl_tc_read_classid_file(void);
+extern char *          rtnl_tc_handle2str(uint32_t, char *, size_t);
+extern int             rtnl_tc_str2handle(const char *, uint32_t *);
+extern int             rtnl_classid_generate(const char *, uint32_t *,
+                                             uint32_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/socket.h b/include/netlink/socket.h
new file mode 100644 (file)
index 0000000..1007eba
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * netlink/socket.h            Netlink Socket
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_SOCKET_H_
+#define NETLINK_SOCKET_H_
+
+#include <netlink/types.h>
+#include <netlink/handlers.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct nl_sock *        nl_socket_alloc(void);
+extern struct nl_sock *        nl_socket_alloc_cb(struct nl_cb *);
+extern void            nl_socket_free(struct nl_sock *);
+
+extern uint32_t                nl_socket_get_local_port(const struct nl_sock *);
+extern void            nl_socket_set_local_port(struct nl_sock *, uint32_t);
+
+extern int             nl_socket_add_memberships(struct nl_sock *, int, ...);
+extern int             nl_socket_add_membership(struct nl_sock *, int);
+extern int             nl_socket_drop_memberships(struct nl_sock *, int, ...);
+extern int             nl_socket_drop_membership(struct nl_sock *,
+                                                         int);
+extern void            nl_join_groups(struct nl_sock *, int);
+
+
+extern uint32_t                nl_socket_get_peer_port(const struct nl_sock *);
+extern void            nl_socket_set_peer_port(struct nl_sock *,
+                                                       uint32_t);
+extern uint32_t        nl_socket_get_peer_groups(const struct nl_sock *sk);
+extern void            nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups);
+extern struct nl_cb *  nl_socket_get_cb(const struct nl_sock *);
+extern void            nl_socket_set_cb(struct nl_sock *,
+                                                struct nl_cb *);
+extern int             nl_socket_modify_cb(struct nl_sock *, enum nl_cb_type,
+                                           enum nl_cb_kind,
+                                           nl_recvmsg_msg_cb_t, void *);
+extern int nl_socket_modify_err_cb(struct nl_sock *, enum nl_cb_kind,
+                                  nl_recvmsg_err_cb_t, void *);
+
+extern int             nl_socket_set_buffer_size(struct nl_sock *, int, int);
+extern int             nl_socket_set_msg_buf_size(struct nl_sock *, size_t);
+extern size_t          nl_socket_get_msg_buf_size(struct nl_sock *);
+extern int             nl_socket_set_passcred(struct nl_sock *, int);
+extern int             nl_socket_recv_pktinfo(struct nl_sock *, int);
+
+extern void            nl_socket_disable_seq_check(struct nl_sock *);
+extern unsigned int    nl_socket_use_seq(struct nl_sock *);
+extern void            nl_socket_disable_auto_ack(struct nl_sock *);
+extern void            nl_socket_enable_auto_ack(struct nl_sock *);
+
+extern int             nl_socket_get_fd(const struct nl_sock *);
+extern int             nl_socket_set_nonblocking(const struct nl_sock *);
+extern void            nl_socket_enable_msg_peek(struct nl_sock *);
+extern void            nl_socket_disable_msg_peek(struct nl_sock *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/types.h b/include/netlink/types.h
new file mode 100644 (file)
index 0000000..09cc5bd
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * netlink/types.h             Definition of public types
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef __NETLINK_TYPES_H_
+#define __NETLINK_TYPES_H_
+
+#include <stdio.h>
+
+/**
+ * @ingroup utils
+ * Enumeration of dumping variations (dp_type)
+ */
+enum nl_dump_type {
+       NL_DUMP_LINE,           /**< Dump object briefly on one line */
+       NL_DUMP_DETAILS,        /**< Dump all attributes but no statistics */
+       NL_DUMP_STATS,          /**< Dump all attributes including statistics */
+       __NL_DUMP_MAX,
+};
+#define NL_DUMP_MAX (__NL_DUMP_MAX - 1)
+
+/**
+ * @ingroup utils
+ * Dumping parameters
+ */
+struct nl_dump_params
+{
+       /**
+        * Specifies the type of dump that is requested.
+        */
+       enum nl_dump_type       dp_type;
+
+       /**
+        * Specifies the number of whitespaces to be put in front
+        * of every new line (indentation).
+        */
+       int                     dp_prefix;
+
+       /**
+        * Causes the cache index to be printed for each element.
+        */
+       int                     dp_print_index;
+
+       /**
+        * Causes each element to be prefixed with the message type.
+        */
+       int                     dp_dump_msgtype;
+
+       /**
+        * A callback invoked for output
+        *
+        * Passed arguments are:
+        *  - dumping parameters
+        *  - string to append to the output
+        */
+       void                    (*dp_cb)(struct nl_dump_params *, char *);
+
+       /**
+        * A callback invoked for every new line, can be used to
+        * customize the indentation.
+        *
+        * Passed arguments are:
+        *  - dumping parameters
+        *  - line number starting from 0
+        */
+       void                    (*dp_nl_cb)(struct nl_dump_params *, int);
+
+       /**
+        * User data pointer, can be used to pass data to callbacks.
+        */
+       void                    *dp_data;
+
+       /**
+        * File descriptor the dumping output should go to
+        */
+       FILE *                  dp_fd;
+
+       /**
+        * Alternatively the output may be redirected into a buffer
+        */
+       char *                  dp_buf;
+
+       /**
+        * Length of the buffer dp_buf
+        */
+       size_t                  dp_buflen;
+
+       /**
+        * PRIVATE
+        * Set if a dump was performed prior to the actual dump handler.
+        */
+       int                     dp_pre_dump;
+
+       /**
+        * PRIVATE
+        * Owned by the current caller
+        */
+       int                     dp_ivar;
+
+       unsigned int            dp_line;
+};
+
+#endif
diff --git a/include/netlink/utils.h b/include/netlink/utils.h
new file mode 100644 (file)
index 0000000..502341a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * netlink/utils.h             Utility Functions
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_UTILS_H_
+#define NETLINK_UTILS_H_
+
+#include <netlink/netlink.h>
+#include <netlink/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Probability Constants
+ * @{
+ */
+
+/**
+ * Lower probability limit
+ * @ingroup utils
+ */
+#define NL_PROB_MIN 0x0
+
+/**
+ * Upper probability limit nl_dump_type
+ * @ingroup utils
+ */
+#define NL_PROB_MAX 0xffffffff
+
+/** @} */
+
+enum {
+       NL_BYTE_RATE,
+       NL_BIT_RATE,
+};
+
+/* unit pretty-printing */
+extern double  nl_cancel_down_bytes(unsigned long long, char **);
+extern double  nl_cancel_down_bits(unsigned long long, char **);
+extern int     nl_rate2str(unsigned long long, int, char *, size_t);
+extern double  nl_cancel_down_us(uint32_t, char **);
+
+/* generic unit translations */
+extern long    nl_size2int(const char *);
+extern char *  nl_size2str(const size_t, char *, const size_t);
+extern long    nl_prob2int(const char *);
+
+/* time translations */
+extern int     nl_get_user_hz(void);
+extern int     nl_get_psched_hz(void);
+extern uint32_t        nl_us2ticks(uint32_t);
+extern uint32_t        nl_ticks2us(uint32_t);
+extern int     nl_str2msec(const char *, uint64_t *);
+extern char *  nl_msec2str(uint64_t, char *, size_t);
+
+/* link layer protocol translations */
+extern char *  nl_llproto2str(int, char *, size_t);
+extern int     nl_str2llproto(const char *);
+
+/* ethernet protocol translations */
+extern char *  nl_ether_proto2str(int, char *, size_t);
+extern int     nl_str2ether_proto(const char *);
+
+/* IP protocol translations */
+extern char *  nl_ip_proto2str(int, char *, size_t);
+extern int     nl_str2ip_proto(const char *);
+
+/* Dumping helpers */
+extern void    nl_new_line(struct nl_dump_params *);
+extern void    nl_dump(struct nl_dump_params *, const char *, ...);
+extern void    nl_dump_line(struct nl_dump_params *, const char *, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/version.h b/include/netlink/version.h
new file mode 100644 (file)
index 0000000..ccb8bed
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * netlink/version.h   Versioning Information
+ *
+ *     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-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_VERSION_H_
+#define NETLINK_VERSION_H_
+
+/* Compile Time Versioning Information */
+
+#define LIBNL_STRING "libnl 3.2.22"
+#define LIBNL_VERSION "3.2.22"
+
+#define LIBNL_VER_MAJ          3
+#define LIBNL_VER_MIN          2
+#define LIBNL_VER_MIC          22
+#define LIBNL_VER(maj,min)     ((maj) << 8 | (min))
+#define LIBNL_VER_NUM          LIBNL_VER(LIBNL_VER_MAJ, LIBNL_VER_MIN)
+
+#define LIBNL_CURRENT          217
+#define LIBNL_REVISION         0
+#define LIBNL_AGE              17
+
+/* Run-time version information */
+
+extern const int        nl_ver_num;
+extern const int        nl_ver_maj;
+extern const int        nl_ver_min;
+extern const int        nl_ver_mic;
+
+#endif
diff --git a/include/netlink/version.h.in b/include/netlink/version.h.in
new file mode 100644 (file)
index 0000000..35bf2aa
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * netlink/version.h   Versioning Information
+ *
+ *     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-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_VERSION_H_
+#define NETLINK_VERSION_H_
+
+/* Compile Time Versioning Information */
+
+#define LIBNL_STRING "@PACKAGE_STRING@"
+#define LIBNL_VERSION "@PACKAGE_VERSION@"
+
+#define LIBNL_VER_MAJ          @MAJ_VERSION@
+#define LIBNL_VER_MIN          @MIN_VERSION@
+#define LIBNL_VER_MIC          @MIC_VERSION@
+#define LIBNL_VER(maj,min)     ((maj) << 8 | (min))
+#define LIBNL_VER_NUM          LIBNL_VER(LIBNL_VER_MAJ, LIBNL_VER_MIN)
+
+#define LIBNL_CURRENT          @LT_CURRENT@
+#define LIBNL_REVISION         @LT_REVISION@
+#define LIBNL_AGE              @LT_AGE@
+
+/* Run-time version information */
+
+extern const int        nl_ver_num;
+extern const int        nl_ver_maj;
+extern const int        nl_ver_min;
+extern const int        nl_ver_mic;
+
+#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644 (file)
index 0000000..677a89c
--- /dev/null
@@ -0,0 +1,118 @@
+# -*- Makefile -*-
+
+AM_CPPFLAGS  =                         \
+       -Wall \
+       -I${top_srcdir}/include \
+       -I${top_builddir}/include \
+       -I${builddir}/route \
+       -I${builddir}/route/cls \
+       -D_GNU_SOURCE \
+       -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
+
+AM_LDFLAGS = \
+       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+lib_LTLIBRARIES = \
+       libnl-3.la libnl-genl-3.la libnl-route-3.la libnl-nf-3.la
+
+libnl_3_la_SOURCES = \
+       addr.c attr.c cache.c cache_mngr.c cache_mngt.c data.c \
+       error.c handlers.c msg.c nl.c object.c socket.c utils.c \
+       version.c hash.c hashtable.c
+
+libnl_genl_3_la_LIBADD  = libnl-3.la
+libnl_genl_3_la_SOURCES = \
+       genl/ctrl.c genl/family.c genl/genl.c genl/mngt.c
+
+libnl_nf_3_la_LIBADD  = libnl-route-3.la
+libnl_nf_3_la_SOURCES = \
+       netfilter/ct.c netfilter/ct_obj.c netfilter/log.c \
+       netfilter/log_msg.c netfilter/log_msg_obj.c netfilter/log_obj.c \
+       netfilter/netfilter.c netfilter/nfnl.c netfilter/queue.c \
+       netfilter/queue_msg.c netfilter/queue_msg_obj.c netfilter/queue_obj.c \
+       netfilter/exp.c netfilter/exp_obj.c
+
+CLEANFILES = \
+       route/pktloc_grammar.c route/pktloc_grammar.h \
+       route/pktloc_syntax.c route/pktloc_syntax.h \
+       route/cls/ematch_grammar.c route/cls/ematch_grammar.h \
+       route/cls/ematch_syntax.c route/cls/ematch_syntax.h
+
+# Hack to avoid using ylwrap. It does not function correctly in combination
+# with --header-file=
+route/pktloc_grammar.c: route/pktloc_grammar.l
+       $(AM_V_GEN) $(FLEX) --header-file=route/pktloc_grammar.h $(LFLAGS) -o $@ $^
+
+route/pktloc_syntax.c: route/pktloc_syntax.y
+       $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $^
+
+route/cls/ematch_grammar.c: route/cls/ematch_grammar.l
+       $(AM_V_GEN) $(FLEX) --header-file=route/cls/ematch_grammar.h $(LFLAGS) -o $@ $^
+
+route/cls/ematch_syntax.c: route/cls/ematch_syntax.y
+       $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $^
+
+libnl_route_3_la_LIBADD  = libnl-3.la
+libnl_route_3_la_SOURCES = \
+       route/addr.c route/class.c route/cls.c route/link.c \
+       route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \
+       route/route.c route/route_obj.c route/route_utils.c route/rtnl.c \
+       route/rule.c route/tc.c route/classid.c \
+       \
+       route/cls/fw.c route/cls/police.c route/cls/u32.c route/cls/basic.c \
+       route/cls/cgroup.c \
+       \
+       route/cls/ematch.c \
+       route/cls/ematch/container.c route/cls/ematch/cmp.c \
+       route/cls/ematch/nbyte.c route/cls/ematch/text.c \
+       route/cls/ematch/meta.c \
+       \
+       route/link/api.c route/link/vlan.c route/link/dummy.c \
+       route/link/bridge.c route/link/inet6.c route/link/inet.c \
+       route/link/bonding.c route/link/can.c \
+       \
+       route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \
+       route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \
+       route/qdisc/prio.c route/qdisc/red.c route/qdisc/sfq.c \
+       route/qdisc/tbf.c route/qdisc/plug.c \
+       \
+       fib_lookup/lookup.c fib_lookup/request.c \
+       \
+       route/pktloc.c
+
+nodist_libnl_route_3_la_SOURCES = \
+       route/pktloc_syntax.c route/pktloc_syntax.h \
+       route/pktloc_grammar.c route/pktloc_grammar.h \
+       route/cls/ematch_syntax.c route/cls/ematch_syntax.h \
+       route/cls/ematch_grammar.c route/cls/ematch_grammar.h
+
+BUILT_SOURCES = \
+       route/cls/ematch_grammar.c \
+       route/cls/ematch_syntax.c \
+       route/pktloc_grammar.c \
+       route/pktloc_syntax.c
+
+EXTRA_DIST = \
+       route/pktloc_grammar.l \
+       route/pktloc_syntax.y \
+       route/cls/ematch_grammar.l \
+       route/cls/ematch_syntax.y
+
+if ENABLE_CLI
+nobase_pkglib_LTLIBRARIES = \
+       cli/qdisc/htb.la \
+       cli/qdisc/blackhole.la \
+       cli/qdisc/pfifo.la \
+       cli/qdisc/plug.la \
+       cli/qdisc/bfifo.la \
+       cli/cls/basic.la \
+       cli/cls/cgroup.la
+
+cli_qdisc_htb_la_LDFLAGS = -module -avoid-version
+cli_qdisc_blackhole_la_LDFLAGS = -module -avoid-version
+cli_qdisc_pfifo_la_LDFLAGS = -module -avoid-version
+cli_qdisc_plug_la_LDFLAGS = -module -avoid-version
+cli_qdisc_bfifo_la_LDFLAGS = -module -avoid-version
+cli_cls_basic_la_LDFLAGS = -module -avoid-version
+cli_cls_cgroup_la_LDFLAGS = -module -avoid-version
+endif
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644 (file)
index 0000000..bf6a68e
--- /dev/null
@@ -0,0 +1,1370 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lib
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(srcdir)/defs.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(nobase_pkglib_LTLIBRARIES)
+cli_cls_basic_la_LIBADD =
+cli_cls_basic_la_SOURCES = cli/cls/basic.c
+am__dirstamp = $(am__leading_dot)dirstamp
+cli_cls_basic_la_OBJECTS = cli/cls/basic.lo
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+cli_cls_basic_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(cli_cls_basic_la_LDFLAGS) $(LDFLAGS) \
+       -o $@
+@ENABLE_CLI_TRUE@am_cli_cls_basic_la_rpath = -rpath \
+@ENABLE_CLI_TRUE@      $(pkglibdir)/cli/cls
+cli_cls_cgroup_la_LIBADD =
+cli_cls_cgroup_la_SOURCES = cli/cls/cgroup.c
+cli_cls_cgroup_la_OBJECTS = cli/cls/cgroup.lo
+cli_cls_cgroup_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(cli_cls_cgroup_la_LDFLAGS) $(LDFLAGS) \
+       -o $@
+@ENABLE_CLI_TRUE@am_cli_cls_cgroup_la_rpath = -rpath \
+@ENABLE_CLI_TRUE@      $(pkglibdir)/cli/cls
+cli_qdisc_bfifo_la_LIBADD =
+cli_qdisc_bfifo_la_SOURCES = cli/qdisc/bfifo.c
+cli_qdisc_bfifo_la_OBJECTS = cli/qdisc/bfifo.lo
+cli_qdisc_bfifo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(cli_qdisc_bfifo_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@ENABLE_CLI_TRUE@am_cli_qdisc_bfifo_la_rpath = -rpath \
+@ENABLE_CLI_TRUE@      $(pkglibdir)/cli/qdisc
+cli_qdisc_blackhole_la_LIBADD =
+cli_qdisc_blackhole_la_SOURCES = cli/qdisc/blackhole.c
+cli_qdisc_blackhole_la_OBJECTS = cli/qdisc/blackhole.lo
+cli_qdisc_blackhole_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(cli_qdisc_blackhole_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@ENABLE_CLI_TRUE@am_cli_qdisc_blackhole_la_rpath = -rpath \
+@ENABLE_CLI_TRUE@      $(pkglibdir)/cli/qdisc
+cli_qdisc_htb_la_LIBADD =
+cli_qdisc_htb_la_SOURCES = cli/qdisc/htb.c
+cli_qdisc_htb_la_OBJECTS = cli/qdisc/htb.lo
+cli_qdisc_htb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(cli_qdisc_htb_la_LDFLAGS) $(LDFLAGS) \
+       -o $@
+@ENABLE_CLI_TRUE@am_cli_qdisc_htb_la_rpath = -rpath \
+@ENABLE_CLI_TRUE@      $(pkglibdir)/cli/qdisc
+cli_qdisc_pfifo_la_LIBADD =
+cli_qdisc_pfifo_la_SOURCES = cli/qdisc/pfifo.c
+cli_qdisc_pfifo_la_OBJECTS = cli/qdisc/pfifo.lo
+cli_qdisc_pfifo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(cli_qdisc_pfifo_la_LDFLAGS) \
+       $(LDFLAGS) -o $@
+@ENABLE_CLI_TRUE@am_cli_qdisc_pfifo_la_rpath = -rpath \
+@ENABLE_CLI_TRUE@      $(pkglibdir)/cli/qdisc
+cli_qdisc_plug_la_LIBADD =
+cli_qdisc_plug_la_SOURCES = cli/qdisc/plug.c
+cli_qdisc_plug_la_OBJECTS = cli/qdisc/plug.lo
+cli_qdisc_plug_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(AM_CFLAGS) $(CFLAGS) $(cli_qdisc_plug_la_LDFLAGS) $(LDFLAGS) \
+       -o $@
+@ENABLE_CLI_TRUE@am_cli_qdisc_plug_la_rpath = -rpath \
+@ENABLE_CLI_TRUE@      $(pkglibdir)/cli/qdisc
+libnl_3_la_LIBADD =
+am_libnl_3_la_OBJECTS = addr.lo attr.lo cache.lo cache_mngr.lo \
+       cache_mngt.lo data.lo error.lo handlers.lo msg.lo nl.lo \
+       object.lo socket.lo utils.lo version.lo hash.lo hashtable.lo
+libnl_3_la_OBJECTS = $(am_libnl_3_la_OBJECTS)
+libnl_genl_3_la_DEPENDENCIES = libnl-3.la
+am_libnl_genl_3_la_OBJECTS = genl/ctrl.lo genl/family.lo genl/genl.lo \
+       genl/mngt.lo
+libnl_genl_3_la_OBJECTS = $(am_libnl_genl_3_la_OBJECTS)
+libnl_nf_3_la_DEPENDENCIES = libnl-route-3.la
+am_libnl_nf_3_la_OBJECTS = netfilter/ct.lo netfilter/ct_obj.lo \
+       netfilter/log.lo netfilter/log_msg.lo netfilter/log_msg_obj.lo \
+       netfilter/log_obj.lo netfilter/netfilter.lo netfilter/nfnl.lo \
+       netfilter/queue.lo netfilter/queue_msg.lo \
+       netfilter/queue_msg_obj.lo netfilter/queue_obj.lo \
+       netfilter/exp.lo netfilter/exp_obj.lo
+libnl_nf_3_la_OBJECTS = $(am_libnl_nf_3_la_OBJECTS)
+libnl_route_3_la_DEPENDENCIES = libnl-3.la
+am_libnl_route_3_la_OBJECTS = route/addr.lo route/class.lo \
+       route/cls.lo route/link.lo route/neigh.lo route/neightbl.lo \
+       route/nexthop.lo route/qdisc.lo route/route.lo \
+       route/route_obj.lo route/route_utils.lo route/rtnl.lo \
+       route/rule.lo route/tc.lo route/classid.lo route/cls/fw.lo \
+       route/cls/police.lo route/cls/u32.lo route/cls/basic.lo \
+       route/cls/cgroup.lo route/cls/ematch.lo \
+       route/cls/ematch/container.lo route/cls/ematch/cmp.lo \
+       route/cls/ematch/nbyte.lo route/cls/ematch/text.lo \
+       route/cls/ematch/meta.lo route/link/api.lo route/link/vlan.lo \
+       route/link/dummy.lo route/link/bridge.lo route/link/inet6.lo \
+       route/link/inet.lo route/link/bonding.lo route/link/can.lo \
+       route/qdisc/blackhole.lo route/qdisc/cbq.lo \
+       route/qdisc/dsmark.lo route/qdisc/fifo.lo route/qdisc/htb.lo \
+       route/qdisc/netem.lo route/qdisc/prio.lo route/qdisc/red.lo \
+       route/qdisc/sfq.lo route/qdisc/tbf.lo route/qdisc/plug.lo \
+       fib_lookup/lookup.lo fib_lookup/request.lo route/pktloc.lo
+nodist_libnl_route_3_la_OBJECTS = route/pktloc_syntax.lo \
+       route/pktloc_grammar.lo route/cls/ematch_syntax.lo \
+       route/cls/ematch_grammar.lo
+libnl_route_3_la_OBJECTS = $(am_libnl_route_3_la_OBJECTS) \
+       $(nodist_libnl_route_3_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = cli/cls/basic.c cli/cls/cgroup.c cli/qdisc/bfifo.c \
+       cli/qdisc/blackhole.c cli/qdisc/htb.c cli/qdisc/pfifo.c \
+       cli/qdisc/plug.c $(libnl_3_la_SOURCES) \
+       $(libnl_genl_3_la_SOURCES) $(libnl_nf_3_la_SOURCES) \
+       $(libnl_route_3_la_SOURCES) $(nodist_libnl_route_3_la_SOURCES)
+DIST_SOURCES = cli/cls/basic.c cli/cls/cgroup.c cli/qdisc/bfifo.c \
+       cli/qdisc/blackhole.c cli/qdisc/htb.c cli/qdisc/pfifo.c \
+       cli/qdisc/plug.c $(libnl_3_la_SOURCES) \
+       $(libnl_genl_3_la_SOURCES) $(libnl_nf_3_la_SOURCES) \
+       $(libnl_route_3_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+       -Wall \
+       -I${top_srcdir}/include \
+       -I${top_builddir}/include \
+       -I${builddir}/route \
+       -I${builddir}/route/cls \
+       -D_GNU_SOURCE \
+       -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
+
+AM_LDFLAGS = \
+       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+lib_LTLIBRARIES = \
+       libnl-3.la libnl-genl-3.la libnl-route-3.la libnl-nf-3.la
+
+libnl_3_la_SOURCES = \
+       addr.c attr.c cache.c cache_mngr.c cache_mngt.c data.c \
+       error.c handlers.c msg.c nl.c object.c socket.c utils.c \
+       version.c hash.c hashtable.c
+
+libnl_genl_3_la_LIBADD = libnl-3.la
+libnl_genl_3_la_SOURCES = \
+       genl/ctrl.c genl/family.c genl/genl.c genl/mngt.c
+
+libnl_nf_3_la_LIBADD = libnl-route-3.la
+libnl_nf_3_la_SOURCES = \
+       netfilter/ct.c netfilter/ct_obj.c netfilter/log.c \
+       netfilter/log_msg.c netfilter/log_msg_obj.c netfilter/log_obj.c \
+       netfilter/netfilter.c netfilter/nfnl.c netfilter/queue.c \
+       netfilter/queue_msg.c netfilter/queue_msg_obj.c netfilter/queue_obj.c \
+       netfilter/exp.c netfilter/exp_obj.c
+
+CLEANFILES = \
+       route/pktloc_grammar.c route/pktloc_grammar.h \
+       route/pktloc_syntax.c route/pktloc_syntax.h \
+       route/cls/ematch_grammar.c route/cls/ematch_grammar.h \
+       route/cls/ematch_syntax.c route/cls/ematch_syntax.h
+
+libnl_route_3_la_LIBADD = libnl-3.la
+libnl_route_3_la_SOURCES = \
+       route/addr.c route/class.c route/cls.c route/link.c \
+       route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \
+       route/route.c route/route_obj.c route/route_utils.c route/rtnl.c \
+       route/rule.c route/tc.c route/classid.c \
+       \
+       route/cls/fw.c route/cls/police.c route/cls/u32.c route/cls/basic.c \
+       route/cls/cgroup.c \
+       \
+       route/cls/ematch.c \
+       route/cls/ematch/container.c route/cls/ematch/cmp.c \
+       route/cls/ematch/nbyte.c route/cls/ematch/text.c \
+       route/cls/ematch/meta.c \
+       \
+       route/link/api.c route/link/vlan.c route/link/dummy.c \
+       route/link/bridge.c route/link/inet6.c route/link/inet.c \
+       route/link/bonding.c route/link/can.c \
+       \
+       route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \
+       route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \
+       route/qdisc/prio.c route/qdisc/red.c route/qdisc/sfq.c \
+       route/qdisc/tbf.c route/qdisc/plug.c \
+       \
+       fib_lookup/lookup.c fib_lookup/request.c \
+       \
+       route/pktloc.c
+
+nodist_libnl_route_3_la_SOURCES = \
+       route/pktloc_syntax.c route/pktloc_syntax.h \
+       route/pktloc_grammar.c route/pktloc_grammar.h \
+       route/cls/ematch_syntax.c route/cls/ematch_syntax.h \
+       route/cls/ematch_grammar.c route/cls/ematch_grammar.h
+
+BUILT_SOURCES = \
+       route/cls/ematch_grammar.c \
+       route/cls/ematch_syntax.c \
+       route/pktloc_grammar.c \
+       route/pktloc_syntax.c
+
+EXTRA_DIST = \
+       route/pktloc_grammar.l \
+       route/pktloc_syntax.y \
+       route/cls/ematch_grammar.l \
+       route/cls/ematch_syntax.y
+
+@ENABLE_CLI_TRUE@nobase_pkglib_LTLIBRARIES = \
+@ENABLE_CLI_TRUE@      cli/qdisc/htb.la \
+@ENABLE_CLI_TRUE@      cli/qdisc/blackhole.la \
+@ENABLE_CLI_TRUE@      cli/qdisc/pfifo.la \
+@ENABLE_CLI_TRUE@      cli/qdisc/plug.la \
+@ENABLE_CLI_TRUE@      cli/qdisc/bfifo.la \
+@ENABLE_CLI_TRUE@      cli/cls/basic.la \
+@ENABLE_CLI_TRUE@      cli/cls/cgroup.la
+
+@ENABLE_CLI_TRUE@cli_qdisc_htb_la_LDFLAGS = -module -avoid-version
+@ENABLE_CLI_TRUE@cli_qdisc_blackhole_la_LDFLAGS = -module -avoid-version
+@ENABLE_CLI_TRUE@cli_qdisc_pfifo_la_LDFLAGS = -module -avoid-version
+@ENABLE_CLI_TRUE@cli_qdisc_plug_la_LDFLAGS = -module -avoid-version
+@ENABLE_CLI_TRUE@cli_qdisc_bfifo_la_LDFLAGS = -module -avoid-version
+@ENABLE_CLI_TRUE@cli_cls_basic_la_LDFLAGS = -module -avoid-version
+@ENABLE_CLI_TRUE@cli_cls_cgroup_la_LDFLAGS = -module -avoid-version
+all: $(BUILT_SOURCES) defs.h
+       $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign lib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+defs.h: stamp-h1
+       @if test ! -f $@; then rm -f stamp-h1; else :; fi
+       @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
+
+stamp-h1: $(srcdir)/defs.h.in $(top_builddir)/config.status
+       @rm -f stamp-h1
+       cd $(top_builddir) && $(SHELL) ./config.status lib/defs.h
+$(srcdir)/defs.h.in:  $(am__configure_deps) 
+       ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+       rm -f stamp-h1
+       touch $@
+
+distclean-hdr:
+       -rm -f defs.h stamp-h1
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       list2=; for p in $$list; do \
+         if test -f $$p; then \
+           list2="$$list2 $$p"; \
+         else :; fi; \
+       done; \
+       test -z "$$list2" || { \
+         echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+       }
+
+uninstall-libLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+       done
+
+clean-libLTLIBRARIES:
+       -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+install-nobase_pkglibLTLIBRARIES: $(nobase_pkglib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       @list='$(nobase_pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)"  || list=; \
+       if test -n "$$list"; then \
+           echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+           $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+       fi; \
+       for p in $$list; do if test -f "$$p"; then echo "$$p $$p"; else :; fi; done | \
+       sed '/ .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+       $(AWK) 'BEGIN { cur = "." } \
+         { if ($$2 == cur) { files = files " " $$1 } \
+           else { print cur, files; files = $$1; cur = $$2 } } \
+         END { print cur, files }' | \
+       while read dir files; do \
+         test -z "$$files" || { \
+           test "x$$dir" = x. || { \
+             echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)/$$dir'"; \
+             $(MKDIR_P) "$(DESTDIR)$(pkglibdir)/$$dir"; }; \
+           echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$files '$(DESTDIR)$(pkglibdir)/$$dir'"; \
+           $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$files "$(DESTDIR)$(pkglibdir)/$$dir" || exit $$?; \
+         }; \
+       done
+
+uninstall-nobase_pkglibLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(nobase_pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+       for p in $$list; do \
+         f=$$p; \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+       done
+
+clean-nobase_pkglibLTLIBRARIES:
+       -test -z "$(nobase_pkglib_LTLIBRARIES)" || rm -f $(nobase_pkglib_LTLIBRARIES)
+       @list='$(nobase_pkglib_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+cli/cls/$(am__dirstamp):
+       @$(MKDIR_P) cli/cls
+       @: > cli/cls/$(am__dirstamp)
+cli/cls/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) cli/cls/$(DEPDIR)
+       @: > cli/cls/$(DEPDIR)/$(am__dirstamp)
+cli/cls/basic.lo: cli/cls/$(am__dirstamp) \
+       cli/cls/$(DEPDIR)/$(am__dirstamp)
+cli/cls/basic.la: $(cli_cls_basic_la_OBJECTS) $(cli_cls_basic_la_DEPENDENCIES) $(EXTRA_cli_cls_basic_la_DEPENDENCIES) cli/cls/$(am__dirstamp)
+       $(AM_V_CCLD)$(cli_cls_basic_la_LINK) $(am_cli_cls_basic_la_rpath) $(cli_cls_basic_la_OBJECTS) $(cli_cls_basic_la_LIBADD) $(LIBS)
+cli/cls/cgroup.lo: cli/cls/$(am__dirstamp) \
+       cli/cls/$(DEPDIR)/$(am__dirstamp)
+cli/cls/cgroup.la: $(cli_cls_cgroup_la_OBJECTS) $(cli_cls_cgroup_la_DEPENDENCIES) $(EXTRA_cli_cls_cgroup_la_DEPENDENCIES) cli/cls/$(am__dirstamp)
+       $(AM_V_CCLD)$(cli_cls_cgroup_la_LINK) $(am_cli_cls_cgroup_la_rpath) $(cli_cls_cgroup_la_OBJECTS) $(cli_cls_cgroup_la_LIBADD) $(LIBS)
+cli/qdisc/$(am__dirstamp):
+       @$(MKDIR_P) cli/qdisc
+       @: > cli/qdisc/$(am__dirstamp)
+cli/qdisc/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) cli/qdisc/$(DEPDIR)
+       @: > cli/qdisc/$(DEPDIR)/$(am__dirstamp)
+cli/qdisc/bfifo.lo: cli/qdisc/$(am__dirstamp) \
+       cli/qdisc/$(DEPDIR)/$(am__dirstamp)
+cli/qdisc/bfifo.la: $(cli_qdisc_bfifo_la_OBJECTS) $(cli_qdisc_bfifo_la_DEPENDENCIES) $(EXTRA_cli_qdisc_bfifo_la_DEPENDENCIES) cli/qdisc/$(am__dirstamp)
+       $(AM_V_CCLD)$(cli_qdisc_bfifo_la_LINK) $(am_cli_qdisc_bfifo_la_rpath) $(cli_qdisc_bfifo_la_OBJECTS) $(cli_qdisc_bfifo_la_LIBADD) $(LIBS)
+cli/qdisc/blackhole.lo: cli/qdisc/$(am__dirstamp) \
+       cli/qdisc/$(DEPDIR)/$(am__dirstamp)
+cli/qdisc/blackhole.la: $(cli_qdisc_blackhole_la_OBJECTS) $(cli_qdisc_blackhole_la_DEPENDENCIES) $(EXTRA_cli_qdisc_blackhole_la_DEPENDENCIES) cli/qdisc/$(am__dirstamp)
+       $(AM_V_CCLD)$(cli_qdisc_blackhole_la_LINK) $(am_cli_qdisc_blackhole_la_rpath) $(cli_qdisc_blackhole_la_OBJECTS) $(cli_qdisc_blackhole_la_LIBADD) $(LIBS)
+cli/qdisc/htb.lo: cli/qdisc/$(am__dirstamp) \
+       cli/qdisc/$(DEPDIR)/$(am__dirstamp)
+cli/qdisc/htb.la: $(cli_qdisc_htb_la_OBJECTS) $(cli_qdisc_htb_la_DEPENDENCIES) $(EXTRA_cli_qdisc_htb_la_DEPENDENCIES) cli/qdisc/$(am__dirstamp)
+       $(AM_V_CCLD)$(cli_qdisc_htb_la_LINK) $(am_cli_qdisc_htb_la_rpath) $(cli_qdisc_htb_la_OBJECTS) $(cli_qdisc_htb_la_LIBADD) $(LIBS)
+cli/qdisc/pfifo.lo: cli/qdisc/$(am__dirstamp) \
+       cli/qdisc/$(DEPDIR)/$(am__dirstamp)
+cli/qdisc/pfifo.la: $(cli_qdisc_pfifo_la_OBJECTS) $(cli_qdisc_pfifo_la_DEPENDENCIES) $(EXTRA_cli_qdisc_pfifo_la_DEPENDENCIES) cli/qdisc/$(am__dirstamp)
+       $(AM_V_CCLD)$(cli_qdisc_pfifo_la_LINK) $(am_cli_qdisc_pfifo_la_rpath) $(cli_qdisc_pfifo_la_OBJECTS) $(cli_qdisc_pfifo_la_LIBADD) $(LIBS)
+cli/qdisc/plug.lo: cli/qdisc/$(am__dirstamp) \
+       cli/qdisc/$(DEPDIR)/$(am__dirstamp)
+cli/qdisc/plug.la: $(cli_qdisc_plug_la_OBJECTS) $(cli_qdisc_plug_la_DEPENDENCIES) $(EXTRA_cli_qdisc_plug_la_DEPENDENCIES) cli/qdisc/$(am__dirstamp)
+       $(AM_V_CCLD)$(cli_qdisc_plug_la_LINK) $(am_cli_qdisc_plug_la_rpath) $(cli_qdisc_plug_la_OBJECTS) $(cli_qdisc_plug_la_LIBADD) $(LIBS)
+libnl-3.la: $(libnl_3_la_OBJECTS) $(libnl_3_la_DEPENDENCIES) $(EXTRA_libnl_3_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libnl_3_la_OBJECTS) $(libnl_3_la_LIBADD) $(LIBS)
+genl/$(am__dirstamp):
+       @$(MKDIR_P) genl
+       @: > genl/$(am__dirstamp)
+genl/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) genl/$(DEPDIR)
+       @: > genl/$(DEPDIR)/$(am__dirstamp)
+genl/ctrl.lo: genl/$(am__dirstamp) genl/$(DEPDIR)/$(am__dirstamp)
+genl/family.lo: genl/$(am__dirstamp) genl/$(DEPDIR)/$(am__dirstamp)
+genl/genl.lo: genl/$(am__dirstamp) genl/$(DEPDIR)/$(am__dirstamp)
+genl/mngt.lo: genl/$(am__dirstamp) genl/$(DEPDIR)/$(am__dirstamp)
+libnl-genl-3.la: $(libnl_genl_3_la_OBJECTS) $(libnl_genl_3_la_DEPENDENCIES) $(EXTRA_libnl_genl_3_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libnl_genl_3_la_OBJECTS) $(libnl_genl_3_la_LIBADD) $(LIBS)
+netfilter/$(am__dirstamp):
+       @$(MKDIR_P) netfilter
+       @: > netfilter/$(am__dirstamp)
+netfilter/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) netfilter/$(DEPDIR)
+       @: > netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/ct.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/ct_obj.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/log.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/log_msg.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/log_msg_obj.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/log_obj.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/netfilter.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/nfnl.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/queue.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/queue_msg.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/queue_msg_obj.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/queue_obj.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/exp.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+netfilter/exp_obj.lo: netfilter/$(am__dirstamp) \
+       netfilter/$(DEPDIR)/$(am__dirstamp)
+libnl-nf-3.la: $(libnl_nf_3_la_OBJECTS) $(libnl_nf_3_la_DEPENDENCIES) $(EXTRA_libnl_nf_3_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libnl_nf_3_la_OBJECTS) $(libnl_nf_3_la_LIBADD) $(LIBS)
+route/$(am__dirstamp):
+       @$(MKDIR_P) route
+       @: > route/$(am__dirstamp)
+route/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) route/$(DEPDIR)
+       @: > route/$(DEPDIR)/$(am__dirstamp)
+route/addr.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/class.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/cls.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/link.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/neigh.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/neightbl.lo: route/$(am__dirstamp) \
+       route/$(DEPDIR)/$(am__dirstamp)
+route/nexthop.lo: route/$(am__dirstamp) \
+       route/$(DEPDIR)/$(am__dirstamp)
+route/qdisc.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/route.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/route_obj.lo: route/$(am__dirstamp) \
+       route/$(DEPDIR)/$(am__dirstamp)
+route/route_utils.lo: route/$(am__dirstamp) \
+       route/$(DEPDIR)/$(am__dirstamp)
+route/rtnl.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/rule.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/tc.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/classid.lo: route/$(am__dirstamp) \
+       route/$(DEPDIR)/$(am__dirstamp)
+route/cls/$(am__dirstamp):
+       @$(MKDIR_P) route/cls
+       @: > route/cls/$(am__dirstamp)
+route/cls/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) route/cls/$(DEPDIR)
+       @: > route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/fw.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/police.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/u32.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/basic.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/cgroup.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch/$(am__dirstamp):
+       @$(MKDIR_P) route/cls/ematch
+       @: > route/cls/ematch/$(am__dirstamp)
+route/cls/ematch/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) route/cls/ematch/$(DEPDIR)
+       @: > route/cls/ematch/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch/container.lo: route/cls/ematch/$(am__dirstamp) \
+       route/cls/ematch/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch/cmp.lo: route/cls/ematch/$(am__dirstamp) \
+       route/cls/ematch/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch/nbyte.lo: route/cls/ematch/$(am__dirstamp) \
+       route/cls/ematch/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch/text.lo: route/cls/ematch/$(am__dirstamp) \
+       route/cls/ematch/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch/meta.lo: route/cls/ematch/$(am__dirstamp) \
+       route/cls/ematch/$(DEPDIR)/$(am__dirstamp)
+route/link/$(am__dirstamp):
+       @$(MKDIR_P) route/link
+       @: > route/link/$(am__dirstamp)
+route/link/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) route/link/$(DEPDIR)
+       @: > route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/api.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/vlan.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/dummy.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/bridge.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/inet6.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/inet.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/bonding.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/link/can.lo: route/link/$(am__dirstamp) \
+       route/link/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/$(am__dirstamp):
+       @$(MKDIR_P) route/qdisc
+       @: > route/qdisc/$(am__dirstamp)
+route/qdisc/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) route/qdisc/$(DEPDIR)
+       @: > route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/blackhole.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/cbq.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/dsmark.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/fifo.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/htb.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/netem.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/prio.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/red.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/sfq.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/tbf.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+route/qdisc/plug.lo: route/qdisc/$(am__dirstamp) \
+       route/qdisc/$(DEPDIR)/$(am__dirstamp)
+fib_lookup/$(am__dirstamp):
+       @$(MKDIR_P) fib_lookup
+       @: > fib_lookup/$(am__dirstamp)
+fib_lookup/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) fib_lookup/$(DEPDIR)
+       @: > fib_lookup/$(DEPDIR)/$(am__dirstamp)
+fib_lookup/lookup.lo: fib_lookup/$(am__dirstamp) \
+       fib_lookup/$(DEPDIR)/$(am__dirstamp)
+fib_lookup/request.lo: fib_lookup/$(am__dirstamp) \
+       fib_lookup/$(DEPDIR)/$(am__dirstamp)
+route/pktloc.lo: route/$(am__dirstamp) route/$(DEPDIR)/$(am__dirstamp)
+route/pktloc_syntax.lo: route/$(am__dirstamp) \
+       route/$(DEPDIR)/$(am__dirstamp)
+route/pktloc_grammar.lo: route/$(am__dirstamp) \
+       route/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch_syntax.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+route/cls/ematch_grammar.lo: route/cls/$(am__dirstamp) \
+       route/cls/$(DEPDIR)/$(am__dirstamp)
+libnl-route-3.la: $(libnl_route_3_la_OBJECTS) $(libnl_route_3_la_DEPENDENCIES) $(EXTRA_libnl_route_3_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libnl_route_3_la_OBJECTS) $(libnl_route_3_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+       -rm -f cli/cls/basic.$(OBJEXT)
+       -rm -f cli/cls/basic.lo
+       -rm -f cli/cls/cgroup.$(OBJEXT)
+       -rm -f cli/cls/cgroup.lo
+       -rm -f cli/qdisc/bfifo.$(OBJEXT)
+       -rm -f cli/qdisc/bfifo.lo
+       -rm -f cli/qdisc/blackhole.$(OBJEXT)
+       -rm -f cli/qdisc/blackhole.lo
+       -rm -f cli/qdisc/htb.$(OBJEXT)
+       -rm -f cli/qdisc/htb.lo
+       -rm -f cli/qdisc/pfifo.$(OBJEXT)
+       -rm -f cli/qdisc/pfifo.lo
+       -rm -f cli/qdisc/plug.$(OBJEXT)
+       -rm -f cli/qdisc/plug.lo
+       -rm -f fib_lookup/lookup.$(OBJEXT)
+       -rm -f fib_lookup/lookup.lo
+       -rm -f fib_lookup/request.$(OBJEXT)
+       -rm -f fib_lookup/request.lo
+       -rm -f genl/ctrl.$(OBJEXT)
+       -rm -f genl/ctrl.lo
+       -rm -f genl/family.$(OBJEXT)
+       -rm -f genl/family.lo
+       -rm -f genl/genl.$(OBJEXT)
+       -rm -f genl/genl.lo
+       -rm -f genl/mngt.$(OBJEXT)
+       -rm -f genl/mngt.lo
+       -rm -f netfilter/ct.$(OBJEXT)
+       -rm -f netfilter/ct.lo
+       -rm -f netfilter/ct_obj.$(OBJEXT)
+       -rm -f netfilter/ct_obj.lo
+       -rm -f netfilter/exp.$(OBJEXT)
+       -rm -f netfilter/exp.lo
+       -rm -f netfilter/exp_obj.$(OBJEXT)
+       -rm -f netfilter/exp_obj.lo
+       -rm -f netfilter/log.$(OBJEXT)
+       -rm -f netfilter/log.lo
+       -rm -f netfilter/log_msg.$(OBJEXT)
+       -rm -f netfilter/log_msg.lo
+       -rm -f netfilter/log_msg_obj.$(OBJEXT)
+       -rm -f netfilter/log_msg_obj.lo
+       -rm -f netfilter/log_obj.$(OBJEXT)
+       -rm -f netfilter/log_obj.lo
+       -rm -f netfilter/netfilter.$(OBJEXT)
+       -rm -f netfilter/netfilter.lo
+       -rm -f netfilter/nfnl.$(OBJEXT)
+       -rm -f netfilter/nfnl.lo
+       -rm -f netfilter/queue.$(OBJEXT)
+       -rm -f netfilter/queue.lo
+       -rm -f netfilter/queue_msg.$(OBJEXT)
+       -rm -f netfilter/queue_msg.lo
+       -rm -f netfilter/queue_msg_obj.$(OBJEXT)
+       -rm -f netfilter/queue_msg_obj.lo
+       -rm -f netfilter/queue_obj.$(OBJEXT)
+       -rm -f netfilter/queue_obj.lo
+       -rm -f route/addr.$(OBJEXT)
+       -rm -f route/addr.lo
+       -rm -f route/class.$(OBJEXT)
+       -rm -f route/class.lo
+       -rm -f route/classid.$(OBJEXT)
+       -rm -f route/classid.lo
+       -rm -f route/cls.$(OBJEXT)
+       -rm -f route/cls.lo
+       -rm -f route/cls/basic.$(OBJEXT)
+       -rm -f route/cls/basic.lo
+       -rm -f route/cls/cgroup.$(OBJEXT)
+       -rm -f route/cls/cgroup.lo
+       -rm -f route/cls/ematch.$(OBJEXT)
+       -rm -f route/cls/ematch.lo
+       -rm -f route/cls/ematch/cmp.$(OBJEXT)
+       -rm -f route/cls/ematch/cmp.lo
+       -rm -f route/cls/ematch/container.$(OBJEXT)
+       -rm -f route/cls/ematch/container.lo
+       -rm -f route/cls/ematch/meta.$(OBJEXT)
+       -rm -f route/cls/ematch/meta.lo
+       -rm -f route/cls/ematch/nbyte.$(OBJEXT)
+       -rm -f route/cls/ematch/nbyte.lo
+       -rm -f route/cls/ematch/text.$(OBJEXT)
+       -rm -f route/cls/ematch/text.lo
+       -rm -f route/cls/ematch_grammar.$(OBJEXT)
+       -rm -f route/cls/ematch_grammar.lo
+       -rm -f route/cls/ematch_syntax.$(OBJEXT)
+       -rm -f route/cls/ematch_syntax.lo
+       -rm -f route/cls/fw.$(OBJEXT)
+       -rm -f route/cls/fw.lo
+       -rm -f route/cls/police.$(OBJEXT)
+       -rm -f route/cls/police.lo
+       -rm -f route/cls/u32.$(OBJEXT)
+       -rm -f route/cls/u32.lo
+       -rm -f route/link.$(OBJEXT)
+       -rm -f route/link.lo
+       -rm -f route/link/api.$(OBJEXT)
+       -rm -f route/link/api.lo
+       -rm -f route/link/bonding.$(OBJEXT)
+       -rm -f route/link/bonding.lo
+       -rm -f route/link/bridge.$(OBJEXT)
+       -rm -f route/link/bridge.lo
+       -rm -f route/link/can.$(OBJEXT)
+       -rm -f route/link/can.lo
+       -rm -f route/link/dummy.$(OBJEXT)
+       -rm -f route/link/dummy.lo
+       -rm -f route/link/inet.$(OBJEXT)
+       -rm -f route/link/inet.lo
+       -rm -f route/link/inet6.$(OBJEXT)
+       -rm -f route/link/inet6.lo
+       -rm -f route/link/vlan.$(OBJEXT)
+       -rm -f route/link/vlan.lo
+       -rm -f route/neigh.$(OBJEXT)
+       -rm -f route/neigh.lo
+       -rm -f route/neightbl.$(OBJEXT)
+       -rm -f route/neightbl.lo
+       -rm -f route/nexthop.$(OBJEXT)
+       -rm -f route/nexthop.lo
+       -rm -f route/pktloc.$(OBJEXT)
+       -rm -f route/pktloc.lo
+       -rm -f route/pktloc_grammar.$(OBJEXT)
+       -rm -f route/pktloc_grammar.lo
+       -rm -f route/pktloc_syntax.$(OBJEXT)
+       -rm -f route/pktloc_syntax.lo
+       -rm -f route/qdisc.$(OBJEXT)
+       -rm -f route/qdisc.lo
+       -rm -f route/qdisc/blackhole.$(OBJEXT)
+       -rm -f route/qdisc/blackhole.lo
+       -rm -f route/qdisc/cbq.$(OBJEXT)
+       -rm -f route/qdisc/cbq.lo
+       -rm -f route/qdisc/dsmark.$(OBJEXT)
+       -rm -f route/qdisc/dsmark.lo
+       -rm -f route/qdisc/fifo.$(OBJEXT)
+       -rm -f route/qdisc/fifo.lo
+       -rm -f route/qdisc/htb.$(OBJEXT)
+       -rm -f route/qdisc/htb.lo
+       -rm -f route/qdisc/netem.$(OBJEXT)
+       -rm -f route/qdisc/netem.lo
+       -rm -f route/qdisc/plug.$(OBJEXT)
+       -rm -f route/qdisc/plug.lo
+       -rm -f route/qdisc/prio.$(OBJEXT)
+       -rm -f route/qdisc/prio.lo
+       -rm -f route/qdisc/red.$(OBJEXT)
+       -rm -f route/qdisc/red.lo
+       -rm -f route/qdisc/sfq.$(OBJEXT)
+       -rm -f route/qdisc/sfq.lo
+       -rm -f route/qdisc/tbf.$(OBJEXT)
+       -rm -f route/qdisc/tbf.lo
+       -rm -f route/route.$(OBJEXT)
+       -rm -f route/route.lo
+       -rm -f route/route_obj.$(OBJEXT)
+       -rm -f route/route_obj.lo
+       -rm -f route/route_utils.$(OBJEXT)
+       -rm -f route/route_utils.lo
+       -rm -f route/rtnl.$(OBJEXT)
+       -rm -f route/rtnl.lo
+       -rm -f route/rule.$(OBJEXT)
+       -rm -f route/rule.lo
+       -rm -f route/tc.$(OBJEXT)
+       -rm -f route/tc.lo
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_mngr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_mngt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handlers.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashtable.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@cli/cls/$(DEPDIR)/basic.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@cli/cls/$(DEPDIR)/cgroup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@cli/qdisc/$(DEPDIR)/bfifo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@cli/qdisc/$(DEPDIR)/blackhole.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@cli/qdisc/$(DEPDIR)/htb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@cli/qdisc/$(DEPDIR)/pfifo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@cli/qdisc/$(DEPDIR)/plug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@fib_lookup/$(DEPDIR)/lookup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@fib_lookup/$(DEPDIR)/request.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@genl/$(DEPDIR)/ctrl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@genl/$(DEPDIR)/family.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@genl/$(DEPDIR)/genl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@genl/$(DEPDIR)/mngt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/ct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/ct_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/exp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/exp_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/log_msg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/log_msg_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/log_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/netfilter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/nfnl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/queue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/queue_msg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/queue_msg_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@netfilter/$(DEPDIR)/queue_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/addr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/class.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/classid.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/cls.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/link.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/neigh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/neightbl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/nexthop.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/pktloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/pktloc_grammar.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/pktloc_syntax.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/qdisc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/route.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/route_obj.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/route_utils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/rtnl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/rule.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/$(DEPDIR)/tc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/basic.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/cgroup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/ematch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/ematch_grammar.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/ematch_syntax.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/fw.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/police.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/$(DEPDIR)/u32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/ematch/$(DEPDIR)/cmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/ematch/$(DEPDIR)/container.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/ematch/$(DEPDIR)/meta.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/ematch/$(DEPDIR)/nbyte.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/cls/ematch/$(DEPDIR)/text.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/api.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/bonding.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/bridge.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/can.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/dummy.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/inet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/inet6.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/link/$(DEPDIR)/vlan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/blackhole.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/cbq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/dsmark.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/fifo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/htb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/netem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/plug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/prio.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/red.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/sfq.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@route/qdisc/$(DEPDIR)/tbf.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+       -rm -rf cli/cls/.libs cli/cls/_libs
+       -rm -rf cli/qdisc/.libs cli/qdisc/_libs
+       -rm -rf fib_lookup/.libs fib_lookup/_libs
+       -rm -rf genl/.libs genl/_libs
+       -rm -rf netfilter/.libs netfilter/_libs
+       -rm -rf route/.libs route/_libs
+       -rm -rf route/cls/.libs route/cls/_libs
+       -rm -rf route/cls/ematch/.libs route/cls/ematch/_libs
+       -rm -rf route/link/.libs route/link/_libs
+       -rm -rf route/qdisc/.libs route/qdisc/_libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES) defs.h.in $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS) defs.h.in $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES) defs.h.in $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS) defs.h.in $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) defs.h
+installdirs:
+       for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkglibdir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+       -rm -f cli/cls/$(DEPDIR)/$(am__dirstamp)
+       -rm -f cli/cls/$(am__dirstamp)
+       -rm -f cli/qdisc/$(DEPDIR)/$(am__dirstamp)
+       -rm -f cli/qdisc/$(am__dirstamp)
+       -rm -f fib_lookup/$(DEPDIR)/$(am__dirstamp)
+       -rm -f fib_lookup/$(am__dirstamp)
+       -rm -f genl/$(DEPDIR)/$(am__dirstamp)
+       -rm -f genl/$(am__dirstamp)
+       -rm -f netfilter/$(DEPDIR)/$(am__dirstamp)
+       -rm -f netfilter/$(am__dirstamp)
+       -rm -f route/$(DEPDIR)/$(am__dirstamp)
+       -rm -f route/$(am__dirstamp)
+       -rm -f route/cls/$(DEPDIR)/$(am__dirstamp)
+       -rm -f route/cls/$(am__dirstamp)
+       -rm -f route/cls/ematch/$(DEPDIR)/$(am__dirstamp)
+       -rm -f route/cls/ematch/$(am__dirstamp)
+       -rm -f route/link/$(DEPDIR)/$(am__dirstamp)
+       -rm -f route/link/$(am__dirstamp)
+       -rm -f route/qdisc/$(DEPDIR)/$(am__dirstamp)
+       -rm -f route/qdisc/$(am__dirstamp)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+       clean-nobase_pkglibLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR) cli/cls/$(DEPDIR) cli/qdisc/$(DEPDIR) fib_lookup/$(DEPDIR) genl/$(DEPDIR) netfilter/$(DEPDIR) route/$(DEPDIR) route/cls/$(DEPDIR) route/cls/ematch/$(DEPDIR) route/link/$(DEPDIR) route/qdisc/$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES \
+       install-nobase_pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR) cli/cls/$(DEPDIR) cli/qdisc/$(DEPDIR) fib_lookup/$(DEPDIR) genl/$(DEPDIR) netfilter/$(DEPDIR) route/$(DEPDIR) route/cls/$(DEPDIR) route/cls/ematch/$(DEPDIR) route/link/$(DEPDIR) route/qdisc/$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES \
+       uninstall-nobase_pkglibLTLIBRARIES
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-libLTLIBRARIES clean-libtool \
+       clean-nobase_pkglibLTLIBRARIES ctags distclean \
+       distclean-compile distclean-generic distclean-hdr \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-libLTLIBRARIES install-man \
+       install-nobase_pkglibLTLIBRARIES install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am uninstall-libLTLIBRARIES \
+       uninstall-nobase_pkglibLTLIBRARIES
+
+
+# Hack to avoid using ylwrap. It does not function correctly in combination
+# with --header-file=
+route/pktloc_grammar.c: route/pktloc_grammar.l
+       $(AM_V_GEN) $(FLEX) --header-file=route/pktloc_grammar.h $(LFLAGS) -o $@ $^
+
+route/pktloc_syntax.c: route/pktloc_syntax.y
+       $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $^
+
+route/cls/ematch_grammar.c: route/cls/ematch_grammar.l
+       $(AM_V_GEN) $(FLEX) --header-file=route/cls/ematch_grammar.h $(LFLAGS) -o $@ $^
+
+route/cls/ematch_syntax.c: route/cls/ematch_syntax.y
+       $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $^
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/addr.c b/lib/addr.c
new file mode 100644 (file)
index 0000000..86e7e58
--- /dev/null
@@ -0,0 +1,1067 @@
+/*
+ * lib/addr.c          Network Address
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core_types
+ * @defgroup addr Network Address
+ *
+ * Abstract data type representing any kind of network address
+ *
+ * Related sections in the development guide:
+ * - @core_doc{_abstract_address, Network Addresses}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/addr.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/addr.h>
+#include <linux/socket.h>
+
+/* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote
+ * this, probably Alexey. */
+static inline uint16_t dn_ntohs(uint16_t addr)
+{
+       union {
+               uint8_t byte[2];
+               uint16_t word;
+       } u = {
+               .word = addr,
+       };
+
+       return ((uint16_t) u.byte[0]) | (((uint16_t) u.byte[1]) << 8);
+}
+
+static inline int do_digit(char *str, uint16_t *addr, uint16_t scale,
+                          size_t *pos, size_t len, int *started)
+{
+       uint16_t tmp = *addr / scale;
+
+       if (*pos == len)
+               return 1;
+
+       if (((tmp) > 0) || *started || (scale == 1)) {
+               *str = tmp + '0';
+               *started = 1;
+               (*pos)++;
+               *addr -= (tmp * scale);
+       }
+
+       return 0;
+}
+
+static const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str,
+                            size_t len)
+{
+       uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf);
+       uint16_t area = addr >> 10;
+       size_t pos = 0;
+       int started = 0;
+
+       if (addrlen != 2)
+               return NULL;
+
+       addr &= 0x03ff;
+
+       if (len == 0)
+               return str;
+
+       if (do_digit(str + pos, &area, 10, &pos, len, &started))
+               return str;
+
+       if (do_digit(str + pos, &area, 1, &pos, len, &started))
+               return str;
+
+       if (pos == len)
+               return str;
+
+       *(str + pos) = '.';
+       pos++;
+       started = 0;
+
+       if (do_digit(str + pos, &addr, 1000, &pos, len, &started))
+               return str;
+
+       if (do_digit(str + pos, &addr, 100, &pos, len, &started))
+               return str;
+
+       if (do_digit(str + pos, &addr, 10, &pos, len, &started))
+               return str;
+
+       if (do_digit(str + pos, &addr, 1, &pos, len, &started))
+               return str;
+
+       if (pos == len)
+               return str;
+
+       *(str + pos) = 0;
+
+       return str;
+}
+
+static int dnet_num(const char *src, uint16_t * dst)
+{
+       int rv = 0;
+       int tmp;
+       *dst = 0;
+
+       while ((tmp = *src++) != 0) {
+               tmp -= '0';
+               if ((tmp < 0) || (tmp > 9))
+                       return rv;
+
+               rv++;
+               (*dst) *= 10;
+               (*dst) += tmp;
+       }
+
+       return rv;
+}
+
+static inline int dnet_pton(const char *src, char *addrbuf)
+{
+       uint16_t area = 0;
+       uint16_t node = 0;
+       int pos;
+
+       pos = dnet_num(src, &area);
+       if ((pos == 0) || (area > 63) ||
+           ((*(src + pos) != '.') && (*(src + pos) != ',')))
+               return -NLE_INVAL;
+
+       pos = dnet_num(src + pos + 1, &node);
+       if ((pos == 0) || (node > 1023))
+               return -NLE_INVAL;
+
+       *(uint16_t *)addrbuf = dn_ntohs((area << 10) | node);
+
+       return 1;
+}
+
+static void addr_destroy(struct nl_addr *addr)
+{
+       if (!addr)
+               return;
+
+       if (addr->a_refcnt != 1)
+               BUG();
+
+       free(addr);
+}
+
+/**
+ * @name Creating Abstract Network Addresses
+ * @{
+ */
+
+/**
+ * Allocate empty abstract address
+ * @arg maxsize                Upper limit of the binary address to be stored
+ *
+ * The new address object will be empty with a prefix length of 0 and will
+ * be capable of holding binary addresses up to the specified limit.
+ *
+ * @see nl_addr_build()
+ * @see nl_addr_parse()
+ * @see nl_addr_put()
+ *
+ * @return Allocated address object or NULL upon failure.
+ */
+struct nl_addr *nl_addr_alloc(size_t maxsize)
+{
+       struct nl_addr *addr;
+       
+       addr = calloc(1, sizeof(*addr) + maxsize);
+       if (!addr)
+               return NULL;
+
+       addr->a_refcnt = 1;
+       addr->a_maxsize = maxsize;
+
+       return addr;
+}
+
+/**
+ * Allocate abstract address based on a binary address.
+ * @arg family         Address family
+ * @arg buf            Binary address
+ * @arg size           Length of binary address
+ *
+ * This function will allocate an abstract address capable of holding the
+ * binary address specified. The prefix length will be set to the full
+ * length of the binary address provided.
+ *
+ * @see nl_addr_alloc()
+ * @see nl_addr_alloc_attr()
+ * @see nl_addr_parse()
+ * @see nl_addr_put()
+ *
+ * @return Allocated address object or NULL upon failure.
+ */
+struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
+{
+       struct nl_addr *addr;
+
+       addr = nl_addr_alloc(size);
+       if (!addr)
+               return NULL;
+
+       addr->a_family = family;
+       addr->a_len = size;
+       addr->a_prefixlen = size*8;
+
+       if (size)
+               memcpy(addr->a_addr, buf, size);
+
+       return addr;
+}
+
+/**
+ * Allocate abstract address based on Netlink attribute.
+ * @arg nla            Netlink attribute
+ * @arg family         Address family.
+ *
+ * Allocates an abstract address based on the specified Netlink attribute
+ * by interpreting the payload of the Netlink attribute as the binary
+ * address.
+ *
+ * This function is identical to:
+ * @code
+ * nl_addr_build(family, nla_data(nla), nla_len(nla));
+ * @endcode
+ *
+ * @see nl_addr_alloc()
+ * @see nl_addr_build()
+ * @see nl_addr_parse()
+ * @see nl_addr_put()
+ *
+ * @return Allocated address object or NULL upon failure.
+ */
+struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family)
+{
+       return nl_addr_build(family, nla_data(nla), nla_len(nla));
+}
+
+/**
+ * Allocate abstract address based on 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
+ *  Format                      Len                Family
+ *  ----------------------------------------------------------------
+ *  IPv6 address format         16                 AF_INET6
+ *  ddd.ddd.ddd.ddd             4                  AF_INET
+ *  HH:HH:HH:HH:HH:HH           6                  AF_LLC
+ *  AA{.|,}NNNN                 2                  AF_DECnet
+ *  HH:HH:HH:...                variable           AF_UNSPEC
+ * @endcode
+ *
+ *  Special values:
+ *    - none: All bits and length set to 0.
+ *    - {default|all|any}: All bits set to 0, length based on hint or
+ *                         AF_INET if no hint is given.
+ *
+ * The prefix length may be appened at the end prefixed with a
+ * slash, e.g. 10.0.0.0/8.
+ *
+ * @see nl_addr_alloc()
+ * @see nl_addr_build()
+ * @see nl_addr_put()
+ *
+ * @return 0 on success or a negative error code.
+ */
+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];
+       struct nl_addr *addr = NULL; /* gcc ain't that smart */
+
+       str = strdup(addrstr);
+       if (!str) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       prefix = strchr(str, '/');
+       if (prefix)
+               *prefix = '\0';
+
+       if (!strcasecmp(str, "none")) {
+               family = hint;
+               goto prefix;
+       }
+
+       if (!strcasecmp(str, "default") ||
+           !strcasecmp(str, "all") ||
+           !strcasecmp(str, "any")) {
+
+               len = 0;
+
+               switch (hint) {
+                       case AF_INET:
+                       case AF_UNSPEC:
+                               /* Kind of a hack, we assume that if there is
+                                * no hint given the user wants to have a IPv4
+                                * address given back. */
+                               family = AF_INET;
+                               goto prefix;
+
+                       case AF_INET6:
+                               family = AF_INET6;
+                               goto prefix;
+
+                       case AF_LLC:
+                               family = AF_LLC;
+                               goto prefix;
+
+                       default:
+                               err = -NLE_AF_NOSUPPORT;
+                               goto errout;
+               }
+       }
+
+       copy = 1;
+
+       if (hint == AF_INET || hint == AF_UNSPEC) {
+               if (inet_pton(AF_INET, str, buf) > 0) {
+                       family = AF_INET;
+                       len = 4;
+                       goto prefix;
+               }
+               if (hint == AF_INET) {
+                       err = -NLE_NOADDR;
+                       goto errout;
+               }
+       }
+
+       if (hint == AF_INET6 || hint == AF_UNSPEC) {
+               if (inet_pton(AF_INET6, str, buf) > 0) {
+                       family = AF_INET6;
+                       len = 16;
+                       goto prefix;
+               }
+               if (hint == AF_INET6) {
+                       err = -NLE_NOADDR;
+                       goto errout;
+               }
+       }
+
+       if ((hint == AF_LLC || hint == AF_UNSPEC) && strchr(str, ':')) {
+               unsigned int a, b, c, d, e, f;
+
+               if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+                   &a, &b, &c, &d, &e, &f) == 6) {
+                       family = AF_LLC;
+                       len = 6;
+                       buf[0] = (unsigned char) a;
+                       buf[1] = (unsigned char) b;
+                       buf[2] = (unsigned char) c;
+                       buf[3] = (unsigned char) d;
+                       buf[4] = (unsigned char) e;
+                       buf[5] = (unsigned char) f;
+                       goto prefix;
+               }
+
+               if (hint == AF_LLC) {
+                       err = -NLE_NOADDR;
+                       goto errout;
+               }
+       }
+
+       if ((hint == AF_DECnet || hint == AF_UNSPEC) &&
+           (strchr(str, '.') || strchr(str, ','))) {
+               if (dnet_pton(str, buf) > 0) {
+                       family = AF_DECnet;
+                       len = 2;
+                       goto prefix;
+               }
+               if (hint == AF_DECnet) {
+                       err = -NLE_NOADDR;
+                       goto errout;
+               }
+       }
+
+       if (hint == AF_UNSPEC && strchr(str, ':')) {
+               size_t i = 0;
+               char *s = str, *p;
+               for (;;) {
+                       long l = strtol(s, &p, 16);
+
+                       if (s == p || l > 0xff || i >= sizeof(buf)) {
+                               err = -NLE_INVAL;
+                               goto errout;
+                       }
+
+                       buf[i++] = (unsigned char) l;
+                       if (*p == '\0')
+                               break;
+                       s = ++p;
+               }
+
+               len = i;
+               family = AF_UNSPEC;
+               goto prefix;
+       }
+
+       err = -NLE_NOADDR;
+       goto errout;
+
+prefix:
+       addr = nl_addr_alloc(len);
+       if (!addr) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       nl_addr_set_family(addr, family);
+
+       if (copy)
+               nl_addr_set_binary_addr(addr, buf, len);
+
+       if (prefix) {
+               char *p;
+               long pl = strtol(++prefix, &p, 0);
+               if (p == prefix) {
+                       addr_destroy(addr);
+                       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;
+}
+
+/**
+ * Clone existing abstract address object
+ * @arg addr           Abstract address object
+ *
+ * Allocates new abstract address representing an identical clone of an
+ * existing address.
+ *
+ * @see nl_addr_alloc()
+ * @see nl_addr_put()
+ *
+ * @return Allocated abstract address or NULL upon failure.
+ */
+struct nl_addr *nl_addr_clone(struct nl_addr *addr)
+{
+       struct nl_addr *new;
+
+       new = nl_addr_build(addr->a_family, addr->a_addr, addr->a_len);
+       if (new)
+               new->a_prefixlen = addr->a_prefixlen;
+
+       return new;
+}
+
+/** @} */
+
+/**
+ * @name Managing Usage References
+ * @{
+ */
+
+/**
+ * Increase the reference counter of an abstract address
+ * @arg addr           Abstract address
+ *
+ * Increases the reference counter of the address and thus prevents the
+ * release of the memory resources until the reference is given back
+ * using the function nl_addr_put().
+ *
+ * @see nl_addr_put()
+ *
+ * @return Pointer to the existing abstract address
+ */
+struct nl_addr *nl_addr_get(struct nl_addr *addr)
+{
+       addr->a_refcnt++;
+
+       return addr;
+}
+
+/**
+ * Decrease the reference counter of an abstract address
+ * @arg addr           Abstract addr
+ *
+ * @note The resources of the abstract address will be freed after the
+ *       last reference to the address has been returned.
+ *
+ * @see nl_addr_get()
+ */
+void nl_addr_put(struct nl_addr *addr)
+{
+       if (!addr)
+               return;
+
+       if (addr->a_refcnt == 1)
+               addr_destroy(addr);
+       else
+               addr->a_refcnt--;
+}
+
+/**
+ * Check whether an abstract address is shared.
+ * @arg addr           Abstract address object.
+ *
+ * @return Non-zero if the abstract address is shared, otherwise 0.
+ */
+int nl_addr_shared(struct nl_addr *addr)
+{
+       return addr->a_refcnt > 1;
+}
+
+/** @} */
+
+/**
+ * @name Miscellaneous
+ * @{
+ */
+
+/**
+ * Compare abstract addresses
+ * @arg a              An abstract address
+ * @arg b              Another abstract address
+ *
+ * Verifies whether the address family, address length, prefix length, and
+ * binary addresses of two abstract addresses matches.
+ *
+ * @note This function will *not* respect the prefix length in the sense
+ *       that only the actual prefix will be compared. Please refer to the
+ *       nl_addr_cmp_prefix() function if you require this functionality.
+ *
+ * @see nl_addr_cmp_prefix()
+ *
+ * @return Integer less than, equal to or greather than zero if the two
+ *         addresses match.
+ */
+int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
+{
+       int d = a->a_family - b->a_family;
+
+       if (d == 0) {
+               d = a->a_len - b->a_len;
+
+               if (a->a_len && d == 0) {
+                       d = memcmp(a->a_addr, b->a_addr, a->a_len);
+
+                       if (d == 0)
+                               return (a->a_prefixlen - b->a_prefixlen);
+               }
+       }
+
+       return d;
+}
+
+/**
+ * Compare the prefix of two abstract addresses
+ * @arg a              An abstract address
+ * @arg b              Another abstract address
+ *
+ * Verifies whether the address family and the binary address covered by
+ * the smaller prefix length of the two abstract addresses matches.
+ *
+ * @see nl_addr_cmp()
+ *
+ * @return Integer less than, equal to or greather than zero if the two
+ *         addresses match.
+ */
+int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
+{
+       int d = a->a_family - b->a_family;
+
+       if (d == 0) {
+               int len = min(a->a_prefixlen, b->a_prefixlen);
+               int bytes = len / 8;
+
+               d = memcmp(a->a_addr, b->a_addr, bytes);
+               if (d == 0 && (len % 8) != 0) {
+                       int mask = (0xFF00 >> (len % 8)) & 0xFF;
+
+                       d = (a->a_addr[bytes] & mask) -
+                           (b->a_addr[bytes] & mask);
+               }
+       }
+
+       return d;
+}
+
+/**
+ * Returns true if the address consists of all zeros
+ * @arg addr           Abstract address
+ *
+ * @return 1 if the binary address consists of all zeros, 0 otherwise.
+ */
+int nl_addr_iszero(struct nl_addr *addr)
+{
+       unsigned int i;
+
+       for (i = 0; i < addr->a_len; i++)
+               if (addr->a_addr[i])
+                       return 0;
+
+       return 1;
+}
+
+/**
+ * Check if address string is parseable for a specific address family
+ * @arg addr           Address represented as character string.
+ * @arg family         Desired address family.
+ *
+ * @return 1 if the address is parseable assuming the specified address family,
+ *         otherwise 0 is returned.
+ */
+int nl_addr_valid(char *addr, int family)
+{
+       int ret;
+       char buf[32];
+
+       switch (family) {
+       case AF_INET:
+       case AF_INET6:
+               ret = inet_pton(family, addr, buf);
+               if (ret <= 0)
+                       return 0;
+               break;
+
+       case AF_DECnet:
+               ret = dnet_pton(addr, buf);
+               if (ret <= 0)
+                       return 0;
+               break;
+
+       case AF_LLC:
+               if (sscanf(addr, "%*02x:%*02x:%*02x:%*02x:%*02x:%*02x") != 6)
+                       return 0;
+               break;
+       }
+
+       return 1;
+}
+
+/**
+ * Guess address family of abstract address based on address size
+ * @arg addr           Abstract address object.
+ *
+ * @return Numeric address family or AF_UNSPEC
+ */
+int nl_addr_guess_family(struct nl_addr *addr)
+{
+       switch (addr->a_len) {
+               case 4:
+                       return AF_INET;
+               case 6:
+                       return AF_LLC;
+               case 16:
+                       return AF_INET6;
+               default:
+                       return AF_UNSPEC;
+       }
+}
+
+/**
+ * Fill out sockaddr structure with values from abstract address object.
+ * @arg addr           Abstract address object.
+ * @arg sa             Destination sockaddr structure buffer.
+ * @arg salen          Length of sockaddr structure buffer.
+ *
+ * Fills out the specified sockaddr structure with the data found in the
+ * specified abstract address. The salen argument needs to be set to the
+ * size of sa but will be modified to the actual size used during before
+ * the function exits.
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
+                         socklen_t *salen)
+{
+       switch (addr->a_family) {
+       case AF_INET: {
+               struct sockaddr_in *sai = (struct sockaddr_in *) sa;
+
+               if (*salen < sizeof(*sai))
+                       return -NLE_INVAL;
+
+               sai->sin_family = addr->a_family;
+               memcpy(&sai->sin_addr, addr->a_addr, 4);
+               *salen = sizeof(*sai);
+       }
+               break;
+
+       case AF_INET6: {
+               struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
+
+               if (*salen < sizeof(*sa6))
+                       return -NLE_INVAL;
+
+               sa6->sin6_family = addr->a_family;
+               memcpy(&sa6->sin6_addr, addr->a_addr, 16);
+               *salen = sizeof(*sa6);
+       }
+               break;
+
+       default:
+               return -NLE_INVAL;
+       }
+
+       return 0;
+}
+
+
+/** @} */
+
+/**
+ * @name Getting Information About Addresses
+ * @{
+ */
+
+/**
+ * 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.
+ *
+ * @note The caller is responsible for freeing the linked list using the
+ *       interface provided by getaddrinfo(3).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
+{
+       int err;
+       char buf[INET6_ADDRSTRLEN+5];
+       struct addrinfo hint = {
+               .ai_flags = AI_NUMERICHOST,
+               .ai_family = addr->a_family,
+       };
+
+       nl_addr2str(addr, buf, sizeof(buf));
+
+       err = getaddrinfo(buf, NULL, &hint, result);
+       if (err != 0) {
+               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 0;
+}
+
+/**
+ * Resolve abstract address object to a name using getnameinfo().
+ * @arg addr           Abstract address object.
+ * @arg host           Destination buffer for host name.
+ * @arg hostlen                Length of destination buffer.
+ *
+ * Resolves the abstract address to a name and writes the looked up result
+ * into the host buffer. getnameinfo() is used to perform the lookup and
+ * is put into NI_NAMEREQD mode so the function will fail if the lookup
+ * couldn't be performed.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen)
+{
+       int err;
+       struct sockaddr_in6 buf;
+       socklen_t salen = sizeof(buf);
+
+       err = nl_addr_fill_sockaddr(addr, (struct sockaddr *) &buf, &salen);
+       if (err < 0)
+               return err;
+
+       err = getnameinfo((struct sockaddr *) &buf, salen, host, hostlen,
+                         NULL, 0, NI_NAMEREQD);
+       if (err < 0)
+               return nl_syserr2nlerr(err);
+
+       return 0;
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+/**
+ * Set address family
+ * @arg addr           Abstract address object
+ * @arg family         Address family
+ *
+ * @see nl_addr_get_family()
+ */
+void nl_addr_set_family(struct nl_addr *addr, int family)
+{
+       addr->a_family = family;
+}
+
+/**
+ * Return address family
+ * @arg addr           Abstract address object
+ *
+ * @see nl_addr_set_family()
+ *
+ * @return The numeric address family or `AF_UNSPEC`
+ */
+int nl_addr_get_family(struct nl_addr *addr)
+{
+       return addr->a_family;
+}
+
+/**
+ * Set binary address of abstract address object.
+ * @arg addr           Abstract address object.
+ * @arg buf            Buffer containing binary address.
+ * @arg len            Length of buffer containing binary address.
+ *
+ * Modifies the binary address portion of the abstract address. The
+ * abstract address must be capable of holding the required amount
+ * or this function will fail.
+ *
+ * @note This function will *not* modify the prefix length. It is within
+ *       the responsibility of the caller to set the prefix length to the
+ *       desirable length.
+ *
+ * @see nl_addr_alloc()
+ * @see nl_addr_get_binary_addr()
+ * @see nl_addr_get_len()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
+{
+       if (len > addr->a_maxsize)
+               return -NLE_RANGE;
+
+       addr->a_len = len;
+       memset(addr->a_addr, 0, addr->a_maxsize);
+
+       if (len)
+               memcpy(addr->a_addr, buf, len);
+
+       return 0;
+}
+
+/**
+ * Get binary address of abstract address object.
+ * @arg addr           Abstract address object.
+ *
+ * @see nl_addr_set_binary_addr()
+ * @see nl_addr_get_len()
+ *
+ * @return Pointer to binary address of length nl_addr_get_len()
+ */
+void *nl_addr_get_binary_addr(struct nl_addr *addr)
+{
+       return addr->a_addr;
+}
+
+/**
+ * Get length of binary address of abstract address object.
+ * @arg addr           Abstract address object.
+ *
+ * @see nl_addr_get_binary_addr()
+ * @see nl_addr_set_binary_addr()
+ */
+unsigned int nl_addr_get_len(struct nl_addr *addr)
+{
+       return addr->a_len;
+}
+
+/**
+ * Set the prefix length of an abstract address
+ * @arg addr           Abstract address object
+ * @arg prefixlen      New prefix length
+ *
+ * @see nl_addr_get_prefixlen()
+ */
+void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
+{
+       addr->a_prefixlen = prefixlen;
+}
+
+/**
+ * Return prefix length of abstract address object.
+ * @arg addr           Abstract address object
+ *
+ * @see nl_addr_set_prefixlen()
+ */
+unsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
+{
+       return addr->a_prefixlen;
+}
+
+/** @} */
+
+/**
+ * @name Translations to Strings
+ * @{
+ */
+
+/**
+ * Convert abstract address object to character string.
+ * @arg addr           Abstract address object.
+ * @arg buf            Destination buffer.
+ * @arg size           Size of destination buffer.
+ *
+ * Converts an abstract address to a character string and stores
+ * the result in the specified destination buffer.
+ *
+ * @return Address represented in ASCII stored in destination buffer.
+ */
+char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
+{
+       unsigned int i;
+       char tmp[16];
+
+       if (!addr || !addr->a_len) {
+               snprintf(buf, size, "none");
+               if (addr)
+                       goto prefix;
+               else
+                       return buf;
+       }
+
+       switch (addr->a_family) {
+               case AF_INET:
+                       inet_ntop(AF_INET, addr->a_addr, buf, size);
+                       break;
+
+               case AF_INET6:
+                       inet_ntop(AF_INET6, addr->a_addr, buf, size);
+                       break;
+
+               case AF_DECnet:
+                       dnet_ntop(addr->a_addr, addr->a_len, buf, size);
+                       break;
+
+               case AF_LLC:
+               default:
+                       snprintf(buf, size, "%02x",
+                                (unsigned char) addr->a_addr[0]);
+                       for (i = 1; i < addr->a_len; i++) {
+                               snprintf(tmp, sizeof(tmp), ":%02x",
+                                        (unsigned char) addr->a_addr[i]);
+                               strncat(buf, tmp, size - strlen(buf) - 1);
+                       }
+                       break;
+       }
+
+prefix:
+       if (addr->a_prefixlen != (8 * addr->a_len)) {
+               snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
+               strncat(buf, tmp, size - strlen(buf) - 1);
+       }
+
+       return buf;
+}
+
+/** @} */
+
+/**
+ * @name Address Family Transformations
+ * @{
+ */
+
+static const struct trans_tbl afs[] = {
+       __ADD(AF_UNSPEC,unspec)
+       __ADD(AF_UNIX,unix)
+       __ADD(AF_INET,inet)
+       __ADD(AF_AX25,ax25)
+       __ADD(AF_IPX,ipx)
+       __ADD(AF_APPLETALK,appletalk)
+       __ADD(AF_NETROM,netrom)
+       __ADD(AF_BRIDGE,bridge)
+       __ADD(AF_ATMPVC,atmpvc)
+       __ADD(AF_X25,x25)
+       __ADD(AF_INET6,inet6)
+       __ADD(AF_ROSE,rose)
+       __ADD(AF_DECnet,decnet)
+       __ADD(AF_NETBEUI,netbeui)
+       __ADD(AF_SECURITY,security)
+       __ADD(AF_KEY,key)
+       __ADD(AF_NETLINK,netlink)
+       __ADD(AF_PACKET,packet)
+       __ADD(AF_ASH,ash)
+       __ADD(AF_ECONET,econet)
+       __ADD(AF_ATMSVC,atmsvc)
+       __ADD(AF_RDS,rds)
+       __ADD(AF_SNA,sna)
+       __ADD(AF_IRDA,irda)
+       __ADD(AF_PPPOX,pppox)
+       __ADD(AF_WANPIPE,wanpipe)
+       __ADD(AF_LLC,llc)
+       __ADD(AF_CAN,can)
+       __ADD(AF_TIPC,tipc)
+       __ADD(AF_BLUETOOTH,bluetooth)
+       __ADD(AF_IUCV,iucv)
+       __ADD(AF_RXRPC,rxrpc)
+       __ADD(AF_ISDN,isdn)
+       __ADD(AF_PHONET,phonet)
+#ifdef AF_IEEE802154
+       __ADD(AF_IEEE802154,ieee802154)
+#endif
+#ifdef AF_CAIF
+       __ADD(AF_CAIF,caif)
+#endif
+#ifdef AF_ALG
+       __ADD(AF_ALG,alg)
+#endif
+#ifdef AF_NFC
+       __ADD(AF_NFC,nfc)
+#endif
+};
+
+char *nl_af2str(int family, char *buf, size_t size)
+{
+       return __type2str(family, buf, size, afs, ARRAY_SIZE(afs));
+}
+
+int nl_str2af(const char *name)
+{
+       int fam = __str2type(name, afs, ARRAY_SIZE(afs));
+       return fam >= 0 ? fam : -EINVAL;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/attr.c b/lib/attr.c
new file mode 100644 (file)
index 0000000..535f10c
--- /dev/null
@@ -0,0 +1,907 @@
+/*
+ * lib/attr.c          Netlink Attributes
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/addr.h>
+#include <netlink/attr.h>
+#include <netlink/msg.h>
+#include <linux/socket.h>
+
+/**
+ * @ingroup msg
+ * @defgroup attr Attributes
+ * Netlink Attributes Construction/Parsing Interface
+ *
+ * Related sections in the development guide:
+ * - @core_doc{core_attr,Netlink Attributes}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/attr.h>
+ * ~~~~
+ */
+
+/**
+ * @name Attribute Size Calculation
+ * @{
+ */
+
+/**
+ * Return size of attribute whithout padding.
+ * @arg payload                Payload length of attribute.
+ *
+ * @code
+ *    <-------- nla_attr_size(payload) --------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ * @endcode
+ *
+ * @return Size of attribute in bytes without padding.
+ */
+int nla_attr_size(int payload)
+{
+       return NLA_HDRLEN + payload;
+}
+
+/**
+ * Return size of attribute including padding.
+ * @arg payload                Payload length of attribute.
+ *
+ * @code
+ *    <----------- nla_total_size(payload) ----------->
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ * @endcode
+ *
+ * @return Size of attribute in bytes.
+ */
+int nla_total_size(int payload)
+{
+       return NLA_ALIGN(nla_attr_size(payload));
+}
+
+/**
+ * Return length of padding at the tail of the attribute.
+ * @arg payload                Payload length of attribute.
+ *
+ * @code
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *   | Attribute Header | Pad |     Payload      | Pad |
+ *   +------------------+- - -+- - - - - - - - - +- - -+
+ *                                                <--->  
+ * @endcode
+ *
+ * @return Length of padding in bytes.
+ */
+int nla_padlen(int payload)
+{
+       return nla_total_size(payload) - nla_attr_size(payload);
+}
+
+/** @} */
+
+/**
+ * @name Parsing Attributes
+ * @{
+ */
+
+/**
+ * Return type of the attribute.
+ * @arg nla            Attribute.
+ *
+ * @return Type of attribute.
+ */
+int nla_type(const struct nlattr *nla)
+{
+       return nla->nla_type & NLA_TYPE_MASK;
+}
+
+/**
+ * Return pointer to the payload section.
+ * @arg nla            Attribute.
+ *
+ * @return Pointer to start of payload section.
+ */
+void *nla_data(const struct nlattr *nla)
+{
+       return (char *) nla + NLA_HDRLEN;
+}
+
+/**
+ * Return length of the payload .
+ * @arg nla            Attribute
+ *
+ * @return Length of payload in bytes.
+ */
+int nla_len(const struct nlattr *nla)
+{
+       return nla->nla_len - NLA_HDRLEN;
+}
+
+/**
+ * Check if the attribute header and payload can be accessed safely.
+ * @arg nla            Attribute of any kind.
+ * @arg remaining      Number of bytes remaining in attribute stream.
+ *
+ * Verifies that the header and payload do not exceed the number of
+ * bytes left in the attribute stream. This function must be called
+ * before access the attribute header or payload when iterating over
+ * the attribute stream using nla_next().
+ *
+ * @return True if the attribute can be accessed safely, false otherwise.
+ */
+int nla_ok(const struct nlattr *nla, int remaining)
+{
+       return remaining >= sizeof(*nla) &&
+              nla->nla_len >= sizeof(*nla) &&
+              nla->nla_len <= remaining;
+}
+
+/**
+ * Return next attribute in a stream of attributes.
+ * @arg nla            Attribute of any kind.
+ * @arg remaining      Variable to count remaining bytes in stream.
+ *
+ * Calculates the offset to the next attribute based on the attribute
+ * given. The attribute provided is assumed to be accessible, the
+ * caller is responsible to use nla_ok() beforehand. The offset (length
+ * of specified attribute including padding) is then subtracted from
+ * the remaining bytes variable and a pointer to the next attribute is
+ * returned.
+ *
+ * nla_next() can be called as long as remainig is >0.
+ *
+ * @return Pointer to next attribute.
+ */
+struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+       int totlen = NLA_ALIGN(nla->nla_len);
+
+       *remaining -= totlen;
+       return (struct nlattr *) ((char *) nla + totlen);
+}
+
+static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
+       [NLA_U8]        = sizeof(uint8_t),
+       [NLA_U16]       = sizeof(uint16_t),
+       [NLA_U32]       = sizeof(uint32_t),
+       [NLA_U64]       = sizeof(uint64_t),
+       [NLA_STRING]    = 1,
+       [NLA_FLAG]      = 0,
+};
+
+static int validate_nla(struct nlattr *nla, int maxtype,
+                       struct nla_policy *policy)
+{
+       struct nla_policy *pt;
+       unsigned int minlen = 0;
+       int type = nla_type(nla);
+
+       if (type <= 0 || type > maxtype)
+               return 0;
+
+       pt = &policy[type];
+
+       if (pt->type > NLA_TYPE_MAX)
+               BUG();
+
+       if (pt->minlen)
+               minlen = pt->minlen;
+       else if (pt->type != NLA_UNSPEC)
+               minlen = nla_attr_minlen[pt->type];
+
+       if (nla_len(nla) < minlen)
+               return -NLE_RANGE;
+
+       if (pt->maxlen && nla_len(nla) > pt->maxlen)
+               return -NLE_RANGE;
+
+       if (pt->type == NLA_STRING) {
+               char *data = nla_data(nla);
+               if (data[nla_len(nla) - 1] != '\0')
+                       return -NLE_INVAL;
+       }
+
+       return 0;
+}
+
+
+/**
+ * Create attribute index based on a stream of attributes.
+ * @arg tb             Index array to be filled (maxtype+1 elements).
+ * @arg maxtype                Maximum attribute type expected and accepted.
+ * @arg head           Head of attribute stream.
+ * @arg len            Length of attribute stream.
+ * @arg policy         Attribute validation policy.
+ *
+ * Iterates over the stream of attributes and stores a pointer to each
+ * attribute in the index array using the attribute type as index to
+ * the array. Attribute with a type greater than the maximum type
+ * specified will be silently ignored in order to maintain backwards
+ * compatibility. If \a policy is not NULL, the attribute will be
+ * validated using the specified policy.
+ *
+ * @see nla_validate
+ * @return 0 on success or a negative error code.
+ */
+int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
+             struct nla_policy *policy)
+{
+       struct nlattr *nla;
+       int rem, err;
+
+       memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+
+       nla_for_each_attr(nla, head, len, rem) {
+               int type = nla_type(nla);
+
+               /* Padding attributes */
+               if (type == 0)
+                       continue;
+
+               if (type > maxtype)
+                       continue;
+
+               if (policy) {
+                       err = validate_nla(nla, maxtype, policy);
+                       if (err < 0)
+                               goto errout;
+               }
+
+               if (tb[type])
+                       NL_DBG(1, "Attribute of type %#x found multiple times in message, "
+                                 "previous attribute is being ignored.\n", type);
+
+               tb[type] = nla;
+       }
+
+       if (rem > 0)
+               NL_DBG(1, "netlink: %d bytes leftover after parsing "
+                      "attributes.\n", rem);
+
+       err = 0;
+errout:
+       return err;
+}
+
+/**
+ * Validate a stream of attributes.
+ * @arg head           Head of attributes stream.
+ * @arg len            Length of attributes stream.
+ * @arg maxtype                Maximum attribute type expected and accepted.
+ * @arg policy         Validation policy.
+ *
+ * Iterates over the stream of attributes and validates each attribute
+ * one by one using the specified policy. Attributes with a type greater
+ * than the maximum type specified will be silently ignored in order to
+ * maintain backwards compatibility.
+ *
+ * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nla_validate(struct nlattr *head, int len, int maxtype,
+                struct nla_policy *policy)
+{
+       struct nlattr *nla;
+       int rem, err;
+
+       nla_for_each_attr(nla, head, len, rem) {
+               err = validate_nla(nla, maxtype, policy);
+               if (err < 0)
+                       goto errout;
+       }
+
+       err = 0;
+errout:
+       return err;
+}
+
+/**
+ * Find a single attribute in a stream of attributes.
+ * @arg head           Head of attributes stream.
+ * @arg len            Length of attributes stream.
+ * @arg attrtype       Attribute type to look for.
+ *
+ * Iterates over the stream of attributes and compares each type with
+ * the type specified. Returns the first attribute which matches the
+ * type.
+ *
+ * @return Pointer to attribute found or NULL.
+ */
+struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
+{
+       struct nlattr *nla;
+       int rem;
+
+       nla_for_each_attr(nla, head, len, rem)
+               if (nla_type(nla) == attrtype)
+                       return nla;
+
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Helper Functions
+ * @{
+ */
+
+/**
+ * Copy attribute payload to another memory area.
+ * @arg dest           Pointer to destination memory area.
+ * @arg src            Attribute
+ * @arg count          Number of bytes to copy at most.
+ *
+ * Note: The number of bytes copied is limited by the length of
+ *       the attribute payload.
+ *
+ * @return The number of bytes copied to dest.
+ */
+int nla_memcpy(void *dest, struct nlattr *src, int count)
+{
+       int minlen;
+
+       if (!src)
+               return 0;
+       
+       minlen = min_t(int, count, nla_len(src));
+       memcpy(dest, nla_data(src), minlen);
+
+       return minlen;
+}
+
+/**
+ * Copy string attribute payload to a buffer.
+ * @arg dst            Pointer to destination buffer.
+ * @arg nla            Attribute of type NLA_STRING.
+ * @arg dstsize                Size of destination buffer in bytes.
+ *
+ * Copies at most dstsize - 1 bytes to the destination buffer.
+ * The result is always a valid NUL terminated string. Unlike
+ * strlcpy the destination buffer is always padded out.
+ *
+ * @return The length of string attribute without the terminating NUL.
+ */
+size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
+{
+       size_t srclen = nla_len(nla);
+       char *src = nla_data(nla);
+
+       if (srclen > 0 && src[srclen - 1] == '\0')
+               srclen--;
+
+       if (dstsize > 0) {
+               size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
+
+               memset(dst, 0, dstsize);
+               memcpy(dst, src, len);
+       }
+
+       return srclen;
+}
+
+/**
+ * Compare attribute payload with memory area.
+ * @arg nla            Attribute.
+ * @arg data           Memory area to compare to.
+ * @arg size           Number of bytes to compare.
+ *
+ * @see memcmp(3)
+ * @return An integer less than, equal to, or greater than zero.
+ */
+int nla_memcmp(const struct nlattr *nla, const void *data, size_t size)
+{
+       int d = nla_len(nla) - size;
+
+       if (d == 0)
+               d = memcmp(nla_data(nla), data, size);
+
+       return d;
+}
+
+/**
+ * Compare string attribute payload with string
+ * @arg nla            Attribute of type NLA_STRING.
+ * @arg str            NUL terminated string.
+ *
+ * @see strcmp(3)
+ * @return An integer less than, equal to, or greater than zero.
+ */
+int nla_strcmp(const struct nlattr *nla, const char *str)
+{
+       int len = strlen(str) + 1;
+       int d = nla_len(nla) - len;
+
+       if (d == 0)
+               d = memcmp(nla_data(nla), str, len);
+
+       return d;
+}
+
+/** @} */
+
+/**
+ * @name Unspecific Attribute
+ * @{
+ */
+
+/**
+ * Reserve space for a attribute.
+ * @arg msg            Netlink Message.
+ * @arg attrtype       Attribute Type.
+ * @arg attrlen                Length of payload.
+ *
+ * Reserves room for a attribute in the specified netlink message and
+ * fills in the attribute header (type, length). Returns NULL if there
+ * is unsuficient space for the attribute.
+ *
+ * Any padding between payload and the start of the next attribute is
+ * zeroed out.
+ *
+ * @return Pointer to start of attribute or NULL on failure.
+ */
+struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
+{
+       struct nlattr *nla;
+       int tlen;
+       
+       tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
+
+       if (tlen > msg->nm_size)
+               return NULL;
+
+       nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+       nla->nla_type = attrtype;
+       nla->nla_len = nla_attr_size(attrlen);
+
+       if (attrlen)
+               memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
+       msg->nm_nlh->nlmsg_len = tlen;
+
+       NL_DBG(2, "msg %p: attr <%p> %d: Reserved %d (%d) bytes at offset +%td "
+                 "nlmsg_len=%d\n", msg, nla, nla->nla_type,
+                 nla_total_size(attrlen), attrlen,
+                 (void *) nla - nlmsg_data(msg->nm_nlh),
+                 msg->nm_nlh->nlmsg_len);
+
+       return nla;
+}
+
+/**
+ * Add a unspecific attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg datalen                Length of data to be used as payload.
+ * @arg data           Pointer to data to be used as attribute payload.
+ *
+ * Reserves room for a unspecific attribute and copies the provided data
+ * into the message as payload of the attribute. Returns an error if there
+ * is insufficient space for the attribute.
+ *
+ * @see nla_reserve
+ * @return 0 on success or a negative error code.
+ */
+int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
+{
+       struct nlattr *nla;
+
+       nla = nla_reserve(msg, attrtype, datalen);
+       if (!nla)
+               return -NLE_NOMEM;
+
+       if (datalen > 0) {
+               memcpy(nla_data(nla), data, datalen);
+               NL_DBG(2, "msg %p: attr <%p> %d: Wrote %d bytes at offset +%td\n",
+                      msg, nla, nla->nla_type, datalen,
+                      (void *) nla - nlmsg_data(msg->nm_nlh));
+       }
+
+       return 0;
+}
+
+/**
+ * Add abstract data as unspecific attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg data           Abstract data object.
+ *
+ * Equivalent to nla_put() except that the length of the payload is
+ * derived from the abstract data object.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_data(struct nl_msg *msg, int attrtype, struct nl_data *data)
+{
+       return nla_put(msg, attrtype, nl_data_get_size(data),
+                      nl_data_get(data));
+}
+
+/**
+ * Add abstract address as unspecific attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg addr           Abstract address object.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_addr(struct nl_msg *msg, int attrtype, struct nl_addr *addr)
+{
+       return nla_put(msg, attrtype, nl_addr_get_len(addr),
+                      nl_addr_get_binary_addr(addr));
+}
+
+/** @} */
+
+/**
+ * @name Integer Attributes
+ */
+
+/**
+ * Add 8 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
+{
+       return nla_put(msg, attrtype, sizeof(uint8_t), &value);
+}
+
+/**
+ * Return value of 8 bit integer attribute.
+ * @arg nla            8 bit integer attribute
+ *
+ * @return Payload as 8 bit integer.
+ */
+uint8_t nla_get_u8(struct nlattr *nla)
+{
+       return *(uint8_t *) nla_data(nla);
+}
+
+/**
+ * Add 16 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
+{
+       return nla_put(msg, attrtype, sizeof(uint16_t), &value);
+}
+
+/**
+ * Return payload of 16 bit integer attribute.
+ * @arg nla            16 bit integer attribute
+ *
+ * @return Payload as 16 bit integer.
+ */
+uint16_t nla_get_u16(struct nlattr *nla)
+{
+       return *(uint16_t *) nla_data(nla);
+}
+
+/**
+ * Add 32 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
+{
+       return nla_put(msg, attrtype, sizeof(uint32_t), &value);
+}
+
+/**
+ * Return payload of 32 bit integer attribute.
+ * @arg nla            32 bit integer attribute.
+ *
+ * @return Payload as 32 bit integer.
+ */
+uint32_t nla_get_u32(struct nlattr *nla)
+{
+       return *(uint32_t *) nla_data(nla);
+}
+
+/**
+ * Add 64 bit integer attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg value          Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
+{
+       return nla_put(msg, attrtype, sizeof(uint64_t), &value);
+}
+
+/**
+ * Return payload of u64 attribute
+ * @arg nla            u64 netlink attribute
+ *
+ * @return Payload as 64 bit integer.
+ */
+uint64_t nla_get_u64(struct nlattr *nla)
+{
+       uint64_t tmp;
+
+       nla_memcpy(&tmp, nla, sizeof(tmp));
+
+       return tmp;
+}
+
+/** @} */
+
+/**
+ * @name String Attribute
+ */
+
+/**
+ * Add string attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg str            NUL terminated string.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_string(struct nl_msg *msg, int attrtype, const char *str)
+{
+       return nla_put(msg, attrtype, strlen(str) + 1, str);
+}
+
+/**
+ * Return payload of string attribute.
+ * @arg nla            String attribute.
+ *
+ * @return Pointer to attribute payload.
+ */
+char *nla_get_string(struct nlattr *nla)
+{
+       return (char *) nla_data(nla);
+}
+
+char *nla_strdup(struct nlattr *nla)
+{
+       return strdup(nla_get_string(nla));
+}
+
+/** @} */
+
+/**
+ * @name Flag Attribute
+ */
+
+/**
+ * Add flag netlink attribute to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_flag(struct nl_msg *msg, int attrtype)
+{
+       return nla_put(msg, attrtype, 0, NULL);
+}
+
+/**
+ * Return true if flag attribute is set.
+ * @arg nla            Flag netlink attribute.
+ *
+ * @return True if flag is set, otherwise false.
+ */
+int nla_get_flag(struct nlattr *nla)
+{
+       return !!nla;
+}
+
+/** @} */
+
+/**
+ * @name Microseconds Attribute
+ */
+
+/**
+ * Add a msecs netlink attribute to a netlink message
+ * @arg n              netlink message
+ * @arg attrtype       attribute type
+ * @arg msecs          number of msecs
+ */
+int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs)
+{
+       return nla_put_u64(n, attrtype, msecs);
+}
+
+/**
+ * Return payload of msecs attribute
+ * @arg nla            msecs netlink attribute
+ *
+ * @return the number of milliseconds.
+ */
+unsigned long nla_get_msecs(struct nlattr *nla)
+{
+       return nla_get_u64(nla);
+}
+
+/** @} */
+
+/**
+ * @name Nested Attribute
+ */
+
+/**
+ * Add nested attributes to netlink message.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type.
+ * @arg nested         Message containing attributes to be nested.
+ *
+ * Takes the attributes found in the \a nested message and appends them
+ * to the message \a msg nested in a container of the type \a attrtype.
+ * The \a nested message may not have a family specific header.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
+{
+       NL_DBG(2, "msg %p: attr <> %d: adding msg %p as nested attribute\n",
+               msg, attrtype, nested);
+
+       return nla_put(msg, attrtype, nlmsg_datalen(nested->nm_nlh),
+                      nlmsg_data(nested->nm_nlh));
+}
+
+
+/**
+ * Start a new level of nested attributes.
+ * @arg msg            Netlink message.
+ * @arg attrtype       Attribute type of container.
+ *
+ * @return Pointer to container attribute.
+ */
+struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
+{
+       struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
+
+       if (nla_put(msg, attrtype, 0, NULL) < 0)
+               return NULL;
+
+       NL_DBG(2, "msg %p: attr <%p> %d: starting nesting\n",
+               msg, start, start->nla_type);
+
+       return start;
+}
+
+/**
+ * Finalize nesting of attributes.
+ * @arg msg            Netlink message.
+ * @arg start          Container attribute as returned from nla_nest_start().
+ *
+ * Corrects the container attribute header to include the appeneded attributes.
+ *
+ * @return 0
+ */
+int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
+{
+       size_t pad, len;
+
+       len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) start;
+
+       if (len == NLA_HDRLEN) {
+               /*
+                * Kernel can't handle empty nested attributes, trim the
+                * attribute header again
+                */
+               nla_nest_cancel(msg, start);
+
+               return 0;
+       }
+
+       start->nla_len = len;
+
+       pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len;
+       if (pad > 0) {
+               /*
+                * Data inside attribute does not end at a alignment boundry.
+                * Pad accordingly and accoun for the additional space in
+                * the message. nlmsg_reserve() may never fail in this situation,
+                * the allocate message buffer must be a multiple of NLMSG_ALIGNTO.
+                */
+               if (!nlmsg_reserve(msg, pad, 0))
+                       BUG();
+
+               NL_DBG(2, "msg %p: attr <%p> %d: added %zu bytes of padding\n",
+                       msg, start, start->nla_type, pad);
+       }
+
+       NL_DBG(2, "msg %p: attr <%p> %d: closing nesting, len=%u\n",
+               msg, start, start->nla_type, start->nla_len);
+
+       return 0;
+}
+
+/**
+ * Cancel the addition of a nested attribute
+ * @arg msg            Netlink message
+ * @arg attr           Nested netlink attribute
+ *
+ * Removes any partially added nested Netlink attribute from the message
+ * by resetting the message to the size before the call to nla_nest_start()
+ * and by overwriting any potentially touched message segments with 0.
+ */
+void nla_nest_cancel(struct nl_msg *msg, struct nlattr *attr)
+{
+       ssize_t len;
+
+       len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) attr;
+       if (len < 0)
+               BUG();
+       else if (len > 0) {
+               msg->nm_nlh->nlmsg_len -= len;
+               memset(nlmsg_tail(msg->nm_nlh), 0, len);
+       }
+}
+
+/**
+ * Create attribute index based on nested attribute
+ * @arg tb             Index array to be filled (maxtype+1 elements).
+ * @arg maxtype                Maximum attribute type expected and accepted.
+ * @arg nla            Nested Attribute.
+ * @arg policy         Attribute validation policy.
+ *
+ * Feeds the stream of attributes nested into the specified attribute
+ * to nla_parse().
+ *
+ * @see nla_parse
+ * @return 0 on success or a negative error code.
+ */
+int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
+                    struct nla_policy *policy)
+{
+       return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
+}
+
+/**
+ * Return true if attribute has NLA_F_NESTED flag set
+ * @arg attr           Netlink attribute
+ *
+ * @return True if attribute has NLA_F_NESTED flag set, oterhwise False.
+ */
+int nla_is_nested(struct nlattr *attr)
+{
+       return !!(attr->nla_type & NLA_F_NESTED);
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/cache.c b/lib/cache.c
new file mode 100644 (file)
index 0000000..e99e9d2
--- /dev/null
@@ -0,0 +1,1220 @@
+/*
+ * lib/cache.c         Caching Module
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cache_mngt
+ * @defgroup cache Cache
+ *
+ * @code
+ *   Cache Management             |    | Type Specific Cache Operations
+ *                                      
+ *                                |    | +----------------+ +------------+
+ *                                       | request update | | msg_parser |
+ *                                |    | +----------------+ +------------+
+ *                                     +- - - - -^- - - - - - - -^- -|- - - -
+ *    nl_cache_update:            |              |               |   |
+ *          1) --------- co_request_update ------+               |   |
+ *                                |                              |   |
+ *          2) destroy old cache     +----------- pp_cb ---------|---+
+ *                                |  |                           |
+ *          3) ---------- nl_recvmsgs ----------+   +- cb_valid -+
+ *             +--------------+   |  |          |   |
+ *             | nl_cache_add |<-----+   + - - -v- -|- - - - - - - - - - -
+ *             +--------------+   |      | +-------------+
+ *                                         | nl_recvmsgs |
+ *                                |      | +-----|-^-----+
+ *                                           +---v-|---+
+ *                                |      |   | nl_recv |
+ *                                           +---------+
+ *                                |      |                 Core Netlink
+ * @endcode
+ * 
+ * Related sections in the development guide:
+ * - @core_doc{core_cache, Caching System}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/cache.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/hashtable.h>
+#include <netlink/utils.h>
+
+/**
+ * @name Access Functions
+ * @{
+ */
+
+/**
+ * Return the number of items in the cache
+ * @arg cache          cache handle
+ */
+int nl_cache_nitems(struct nl_cache *cache)
+{
+       return cache->c_nitems;
+}
+
+/**
+ * Return the number of items matching a filter in the cache
+ * @arg cache          Cache object.
+ * @arg filter         Filter object.
+ */
+int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter)
+{
+       struct nl_object *obj;
+       int nitems = 0;
+
+       if (cache->c_ops == NULL)
+               BUG();
+
+       nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
+               if (filter && !nl_object_match_filter(obj, filter))
+                       continue;
+
+               nitems++;
+       }
+
+       return nitems;
+}
+
+/**
+ * Returns \b true if the cache is empty.
+ * @arg cache          Cache to check
+ * @return \a true if the cache is empty, otherwise \b false is returned.
+ */
+int nl_cache_is_empty(struct nl_cache *cache)
+{
+       return nl_list_empty(&cache->c_items);
+}
+
+/**
+ * Return the operations set of the cache
+ * @arg cache          cache handle
+ */
+struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache)
+{
+       return cache->c_ops;
+}
+
+/**
+ * Return the first element in the cache
+ * @arg cache          cache handle
+ */
+struct nl_object *nl_cache_get_first(struct nl_cache *cache)
+{
+       if (nl_list_empty(&cache->c_items))
+               return NULL;
+
+       return nl_list_entry(cache->c_items.next,
+                            struct nl_object, ce_list);
+}
+
+/**
+ * Return the last element in the cache
+ * @arg cache          cache handle
+ */
+struct nl_object *nl_cache_get_last(struct nl_cache *cache)
+{
+       if (nl_list_empty(&cache->c_items))
+               return NULL;
+
+       return nl_list_entry(cache->c_items.prev,
+                            struct nl_object, ce_list);
+}
+
+/**
+ * Return the next element in the cache
+ * @arg obj            current object
+ */
+struct nl_object *nl_cache_get_next(struct nl_object *obj)
+{
+       if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list))
+               return NULL;
+       else
+               return nl_list_entry(obj->ce_list.next,
+                                    struct nl_object, ce_list);
+}
+
+/**
+ * Return the previous element in the cache
+ * @arg obj            current object
+ */
+struct nl_object *nl_cache_get_prev(struct nl_object *obj)
+{
+       if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list))
+               return NULL;
+       else
+               return nl_list_entry(obj->ce_list.prev,
+                                    struct nl_object, ce_list);
+}
+
+/** @} */
+
+/**
+ * @name Cache Allocation/Deletion
+ * @{
+ */
+
+/**
+ * Allocate new cache
+ * @arg ops            Cache operations
+ *
+ * Allocate and initialize a new cache based on the cache operations
+ * provided.
+ *
+ * @return Allocated cache or NULL if allocation failed.
+ */
+struct nl_cache *nl_cache_alloc(struct nl_cache_ops *ops)
+{
+       struct nl_cache *cache;
+
+       cache = calloc(1, sizeof(*cache));
+       if (!cache)
+               return NULL;
+
+       nl_init_list_head(&cache->c_items);
+       cache->c_ops = ops;
+       cache->c_flags |= ops->co_flags;
+       cache->c_refcnt = 1;
+
+       /*
+        * If object type provides a hash keygen
+        * functions, allocate a hash table for the
+        * cache objects for faster lookups
+        */
+       if (ops->co_obj_ops->oo_keygen) {
+               int hashtable_size;
+
+               if (ops->co_hash_size)
+                       hashtable_size = ops->co_hash_size;
+               else
+                       hashtable_size = NL_MAX_HASH_ENTRIES;
+
+               cache->hashtable = nl_hash_table_alloc(hashtable_size);
+       }
+
+       NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
+
+       return cache;
+}
+
+/**
+ * Allocate new cache and fill it
+ * @arg ops            Cache operations
+ * @arg sock           Netlink socket
+ * @arg result         Result pointer
+ *
+ * Allocate new cache and fill it. Equivalent to calling:
+ * @code
+ * cache = nl_cache_alloc(ops);
+ * nl_cache_refill(sock, cache);
+ * @endcode
+ *
+ * @see nl_cache_alloc
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *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 new cache based on type name
+ * @arg kind           Name of cache type
+ * @arg result         Result pointer
+ *
+ * Lookup cache ops via nl_cache_ops_lookup() and allocate the cache
+ * by calling nl_cache_alloc(). Stores the allocated cache in the
+ * result pointer provided.
+ *
+ * @see nl_cache_alloc
+ *
+ * @return 0 on success or a negative error code.
+ */
+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_safe(kind);
+       if (!ops)
+               return -NLE_NOCACHE;
+
+       cache = nl_cache_alloc(ops);
+       nl_cache_ops_put(ops);
+       if (!cache)
+               return -NLE_NOMEM;
+
+       *result = cache;
+       return 0;
+}
+
+/**
+ * Allocate new cache containing a subset of an existing cache
+ * @arg orig           Original cache to base new cache on
+ * @arg filter         Filter defining the subset to be filled into the new cache
+ *
+ * Allocates a new cache matching the type of the cache specified by
+ * \p orig. Iterates over the \p orig cache applying the specified
+ * \p filter and copies all objects that match to the new cache.
+ *
+ * The copied objects are clones but do not contain a reference to each
+ * other. Later modifications to objects in the original cache will
+ * not affect objects in the new cache.
+ *
+ * @return A newly allocated cache or NULL.
+ */
+struct nl_cache *nl_cache_subset(struct nl_cache *orig,
+                                struct nl_object *filter)
+{
+       struct nl_cache *cache;
+       struct nl_object *obj;
+
+       if (!filter)
+               BUG();
+
+       cache = nl_cache_alloc(orig->c_ops);
+       if (!cache)
+               return NULL;
+
+       NL_DBG(2, "Filling subset of cache %p <%s> with filter %p into %p\n",
+              orig, nl_cache_name(orig), filter, cache);
+
+       nl_list_for_each_entry(obj, &orig->c_items, ce_list) {
+               if (!nl_object_match_filter(obj, filter))
+                       continue;
+
+               nl_cache_add(cache, obj);
+       }
+
+       return cache;
+}
+
+/**
+ * Allocate new cache and copy the contents of an existing cache
+ * @arg cache          Original cache to base new cache on
+ *
+ * Allocates a new cache matching the type of the cache specified by
+ * \p cache. Iterates over the \p cache cache and copies all objects
+ * to the new cache.
+ *
+ * The copied objects are clones but do not contain a reference to each
+ * other. Later modifications to objects in the original cache will
+ * not affect objects in the new cache.
+ *
+ * @return A newly allocated cache or NULL.
+ */
+struct nl_cache *nl_cache_clone(struct nl_cache *cache)
+{
+       struct nl_cache_ops *ops = nl_cache_get_ops(cache);
+       struct nl_cache *clone;
+       struct nl_object *obj;
+
+       clone = nl_cache_alloc(ops);
+       if (!clone)
+               return NULL;
+
+       NL_DBG(2, "Cloning %p into %p\n", cache, clone);
+
+       nl_list_for_each_entry(obj, &cache->c_items, ce_list)
+               nl_cache_add(clone, obj);
+
+       return clone;
+}
+
+/**
+ * Remove all objects of a cache.
+ * @arg cache          Cache to clear
+ *
+ * The objects are unliked/removed from the cache by calling
+ * nl_cache_remove() on each object in the cache. If any of the objects
+ * to not contain any further references to them, those objects will
+ * be freed.
+ *
+ * Unlike with nl_cache_free(), the cache is not freed just emptied.
+ */
+void nl_cache_clear(struct nl_cache *cache)
+{
+       struct nl_object *obj, *tmp;
+
+       NL_DBG(2, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
+
+       nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
+               nl_cache_remove(obj);
+}
+
+static void __nl_cache_free(struct nl_cache *cache)
+{
+       nl_cache_clear(cache);
+
+       if (cache->hashtable)
+               nl_hash_table_free(cache->hashtable);
+
+       NL_DBG(2, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
+       free(cache);
+}
+
+/**
+ * Increase reference counter of cache
+ * @arg cache          Cache
+ */
+void nl_cache_get(struct nl_cache *cache)
+{
+       cache->c_refcnt++;
+
+       NL_DBG(3, "Incremented cache %p <%s> reference count to %d\n",
+              cache, nl_cache_name(cache), cache->c_refcnt);
+}
+
+/**
+ * Free a cache.
+ * @arg cache          Cache to free.
+ *
+ * Calls nl_cache_clear() to remove all objects associated with the
+ * cache and frees the cache afterwards.
+ *
+ * @see nl_cache_clear()
+ */
+void nl_cache_free(struct nl_cache *cache)
+{
+       if (!cache)
+               return;
+
+       cache->c_refcnt--;
+
+       NL_DBG(3, "Decremented cache %p <%s> reference count, %d remaining\n",
+              cache, nl_cache_name(cache), cache->c_refcnt);
+
+       if (cache->c_refcnt <= 0)
+               __nl_cache_free(cache);
+}
+
+void nl_cache_put(struct nl_cache *cache)
+{
+       return nl_cache_free(cache);
+}
+
+/** @} */
+
+/**
+ * @name Cache Modifications
+ * @{
+ */
+
+static int __cache_add(struct nl_cache *cache, struct nl_object *obj)
+{
+       int ret;
+
+       obj->ce_cache = cache;
+
+       if (cache->hashtable) {
+               ret = nl_hash_table_add(cache->hashtable, obj);
+               if (ret < 0) {
+                       obj->ce_cache = NULL;
+                       return ret;
+               }
+       }
+
+       nl_list_add_tail(&obj->ce_list, &cache->c_items);
+       cache->c_nitems++;
+
+       NL_DBG(3, "Added object %p to cache %p <%s>, nitems %d\n",
+              obj, cache, nl_cache_name(cache), cache->c_nitems);
+
+       return 0;
+}
+
+/**
+ * Add object to cache.
+ * @arg cache          Cache
+ * @arg obj            Object to be added to the cache
+ *
+ * Adds the object \p obj to the specified \p cache. In case the object
+ * is already associated with another cache, the object is cloned before
+ * adding it to the cache. In this case, the sole reference to the object
+ * will be the one of the cache. Therefore clearing/freeing the cache
+ * will result in the object being freed again.
+ *
+ * If the object has not been associated with a cache yet, the reference
+ * counter of the object is incremented to account for the additional
+ * reference.
+ *
+ * The type of the object and cache must match, otherwise an error is
+ * returned (-NLE_OBJ_MISMATCH).
+ *
+ * @see nl_cache_move()
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
+{
+       struct nl_object *new;
+       int ret = 0;
+
+       if (cache->c_ops->co_obj_ops != obj->ce_ops)
+               return -NLE_OBJ_MISMATCH;
+
+       if (!nl_list_empty(&obj->ce_list)) {
+               NL_DBG(3, "Object %p already in cache, cloning new object\n", obj);
+
+               new = nl_object_clone(obj);
+               if (!new)
+                       return -NLE_NOMEM;
+       } else {
+               nl_object_get(obj);
+               new = obj;
+       }
+
+       ret = __cache_add(cache, new);
+       if (ret < 0)
+               nl_object_put(new);
+
+       return ret;
+}
+
+/**
+ * Move object from one cache to another
+ * @arg cache          Cache to move object to.
+ * @arg obj            Object subject to be moved
+ *
+ * Removes the the specified object \p obj from its associated cache
+ * and moves it to another cache.
+ *
+ * If the object is not associated with a cache, the function behaves
+ * just like nl_cache_add().
+ *
+ * The type of the object and cache must match, otherwise an error is
+ * returned (-NLE_OBJ_MISMATCH).
+ *
+ * @see nl_cache_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_move(struct nl_cache *cache, struct nl_object *obj)
+{
+       if (cache->c_ops->co_obj_ops != obj->ce_ops)
+               return -NLE_OBJ_MISMATCH;
+
+       NL_DBG(3, "Moving object %p from cache %p to cache %p\n",
+              obj, obj->ce_cache, cache);
+       
+       /* Acquire reference, if already in a cache this will be
+        * reverted during removal */
+       nl_object_get(obj);
+
+       if (!nl_list_empty(&obj->ce_list))
+               nl_cache_remove(obj);
+
+       return __cache_add(cache, obj);
+}
+
+/**
+ * Remove object from cache.
+ * @arg obj            Object to remove from cache
+ *
+ * Removes the object \c obj from the cache it is associated with. The
+ * reference counter of the object will be decremented. If the reference
+ * to the object was the only one remaining, the object will be freed.
+ *
+ * If no cache is associated with the object, this function is a NOP.
+ */
+void nl_cache_remove(struct nl_object *obj)
+{
+       int ret;
+       struct nl_cache *cache = obj->ce_cache;
+
+       if (cache == NULL)
+               return;
+
+       if (cache->hashtable) {
+               ret = nl_hash_table_del(cache->hashtable, obj);
+               if (ret < 0)
+                       NL_DBG(2, "Failed to delete %p from cache %p <%s>.\n",
+                              obj, cache, nl_cache_name(cache));
+       }
+
+       nl_list_del(&obj->ce_list);
+       obj->ce_cache = NULL;
+       nl_object_put(obj);
+       cache->c_nitems--;
+
+       NL_DBG(2, "Deleted object %p from cache %p <%s>.\n",
+              obj, cache, nl_cache_name(cache));
+}
+
+/** @} */
+
+/**
+ * @name Synchronization
+ * @{
+ */
+
+/**
+ * Set synchronization arg1 of cache
+ * @arg cache          Cache
+ * @arg arg            argument
+ *
+ * Synchronization arguments are used to specify filters when
+ * requesting dumps from the kernel.
+ */
+void nl_cache_set_arg1(struct nl_cache *cache, int arg)
+{
+        cache->c_iarg1 = arg;
+}
+
+/**
+ * Set synchronization arg2 of cache
+ * @arg cache          Cache
+ * @arg arg            argument
+ *
+ * Synchronization arguments are used to specify filters when
+ * requesting dumps from the kernel.
+ */
+void nl_cache_set_arg2(struct nl_cache *cache, int arg)
+{
+        cache->c_iarg2 = arg;
+}
+
+/**
+ * Set cache flags
+ * @arg cache          Cache
+ * @arg flags          Flags
+ */
+void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags)
+{
+       cache->c_flags |= flags;
+}
+
+/**
+ * Invoke the request-update operation
+ * @arg sk             Netlink socket.
+ * @arg cache          Cache
+ *
+ * This function causes the \e request-update function of the cache
+ * operations to be invoked. This usually causes a dump request to
+ * be sent over the netlink socket which triggers the kernel to dump
+ * all objects of a specific type to be dumped onto the netlink
+ * socket for pickup.
+ *
+ * The behaviour of this function depends on the implemenation of
+ * the \e request_update function of each individual type of cache.
+ *
+ * This function will not have any effects on the cache (unless the
+ * request_update implementation of the cache operations does so).
+ *
+ * Use nl_cache_pickup() to pick-up (read) the objects from the socket
+ * and fill them into the cache.
+ *
+ * @see nl_cache_pickup(), nl_cache_resync()
+ *
+ * @return 0 on success or a negative error code.
+ */
+static int nl_cache_request_full_dump(struct nl_sock *sk,
+                                     struct nl_cache *cache)
+{
+       if (cache->c_ops->co_request_update == NULL)
+               return -NLE_OPNOTSUPP;
+
+       NL_DBG(2, "Requesting update from kernel for cache %p <%s>\n",
+                 cache, nl_cache_name(cache));
+
+       return cache->c_ops->co_request_update(cache, sk);
+}
+
+/** @cond SKIP */
+struct update_xdata {
+       struct nl_cache_ops *ops;
+       struct nl_parser_param *params;
+};
+
+static int update_msg_parser(struct nl_msg *msg, void *arg)
+{
+       struct update_xdata *x = arg;
+       int ret = 0;
+
+       ret = nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
+       if (ret == -NLE_EXIST)
+               return NL_SKIP;
+       else
+               return ret;
+}
+/** @endcond */
+
+/**
+ * Pick-up a netlink request-update with your own parser
+ * @arg sk             Netlink socket
+ * @arg cache          Cache
+ * @arg param          Parser parameters
+ */
+static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
+                         struct nl_parser_param *param)
+{
+       int err;
+       struct nl_cb *cb;
+       struct update_xdata x = {
+               .ops = cache->c_ops,
+               .params = param,
+       };
+
+       NL_DBG(2, "Picking up answer for cache %p <%s>\n",
+              cache, nl_cache_name(cache));
+
+       cb = nl_cb_clone(sk->s_cb);
+       if (cb == NULL)
+               return -NLE_NOMEM;
+
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
+
+       err = nl_recvmsgs(sk, cb);
+       if (err < 0)
+               NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned %d: %s\n",
+                      cache, nl_cache_name(cache), err, nl_geterror(err));
+
+       nl_cb_put(cb);
+
+       return err;
+}
+
+static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
+{
+       struct nl_cache *cache = (struct nl_cache *)p->pp_arg;
+       struct nl_object *old;
+
+       old = nl_cache_search(cache, c);
+       if (old) {
+               if (nl_object_update(old, c) == 0) {
+                       nl_object_put(old);
+                       return 0;
+               }
+
+               nl_cache_remove(old);
+               nl_object_put(old);
+       }
+
+       return nl_cache_add(cache, c);
+}
+
+/**
+ * Pickup a netlink dump response and put it into a cache.
+ * @arg sk             Netlink socket.
+ * @arg cache          Cache to put items into.
+ *
+ * Waits for netlink messages to arrive, parses them and puts them into
+ * the specified cache. If an old object with same key attributes is
+ * present in the cache, it is replaced with the new object.
+ * If the old object type supports an update operation, an update is
+ * attempted before a replace.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
+{
+       struct nl_parser_param p = {
+               .pp_cb = pickup_cb,
+               .pp_arg = cache,
+       };
+
+       return __cache_pickup(sk, cache, &p);
+}
+
+static int cache_include(struct nl_cache *cache, struct nl_object *obj,
+                        struct nl_msgtype *type, change_func_t cb, void *data)
+{
+       struct nl_object *old;
+
+       switch (type->mt_act) {
+       case NL_ACT_NEW:
+       case NL_ACT_DEL:
+               old = nl_cache_search(cache, obj);
+               if (old) {
+                       /*
+                        * Some objects types might support merging the new
+                        * object with the old existing cache object.
+                        * Handle them first.
+                        */
+                       if (nl_object_update(old, obj) == 0) {
+                               if (cb)
+                                       cb(cache, old, NL_ACT_CHANGE, data);
+                               nl_object_put(old);
+                               return 0;
+                       }
+
+                       nl_cache_remove(old);
+                       if (type->mt_act == NL_ACT_DEL) {
+                               if (cb)
+                                       cb(cache, old, NL_ACT_DEL, data);
+                               nl_object_put(old);
+                       }
+               }
+
+               if (type->mt_act == NL_ACT_NEW) {
+                       nl_cache_move(cache, obj);
+                       if (old == NULL && cb)
+                               cb(cache, obj, NL_ACT_NEW, data);
+                       else if (old) {
+                               if (nl_object_diff(old, obj) && cb)
+                                       cb(cache, obj, NL_ACT_CHANGE, data);
+
+                               nl_object_put(old);
+                       }
+               }
+               break;
+       default:
+               NL_DBG(2, "Unknown action associated to object %p\n", obj);
+               return 0;
+       }
+
+       return 0;
+}
+
+int nl_cache_include(struct nl_cache *cache, struct nl_object *obj,
+                    change_func_t change_cb, void *data)
+{
+       struct nl_cache_ops *ops = cache->c_ops;
+       int i;
+
+       if (ops->co_obj_ops != obj->ce_ops)
+               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, data);
+
+       NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n",
+              obj, cache, nl_cache_name(cache));
+
+       return -NLE_MSGTYPE_NOSUPPORT;
+}
+
+static int resync_cb(struct nl_object *c, struct nl_parser_param *p)
+{
+       struct nl_cache_assoc *ca = p->pp_arg;
+
+       return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data);
+}
+
+int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
+                   change_func_t change_cb, void *data)
+{
+       struct nl_object *obj, *next;
+       struct nl_af_group *grp;
+       struct nl_cache_assoc ca = {
+               .ca_cache = cache,
+               .ca_change = change_cb,
+               .ca_change_data = data,
+       };
+       struct nl_parser_param p = {
+               .pp_cb = resync_cb,
+               .pp_arg = &ca,
+       };
+       int err;
+
+       NL_DBG(1, "Resyncing cache %p <%s>...\n", cache, nl_cache_name(cache));
+
+       /* Mark all objects so we can see if some of them are obsolete */
+       nl_cache_mark_all(cache);
+
+       grp = cache->c_ops->co_groups;
+       do {
+               if (grp && grp->ag_group &&
+                       (cache->c_flags & NL_CACHE_AF_ITER))
+                       nl_cache_set_arg1(cache, grp->ag_family);
+
+restart:
+               err = nl_cache_request_full_dump(sk, cache);
+               if (err < 0)
+                       goto errout;
+
+               err = __cache_pickup(sk, cache, &p);
+               if (err == -NLE_DUMP_INTR)
+                       goto restart;
+               else if (err < 0)
+                       goto errout;
+
+               if (grp)
+                       grp++;
+       } while (grp && grp->ag_group &&
+               (cache->c_flags & NL_CACHE_AF_ITER));
+
+       nl_list_for_each_entry_safe(obj, next, &cache->c_items, ce_list) {
+               if (nl_object_is_marked(obj)) {
+                       nl_object_get(obj);
+                       nl_cache_remove(obj);
+                       if (change_cb)
+                               change_cb(cache, obj, NL_ACT_DEL, data);
+                       nl_object_put(obj);
+               }
+       }
+
+       NL_DBG(1, "Finished resyncing %p <%s>\n", cache, nl_cache_name(cache));
+
+       err = 0;
+errout:
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Parsing
+ * @{
+ */
+
+/** @cond SKIP */
+int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                  struct nlmsghdr *nlh, struct nl_parser_param *params)
+{
+       int i, err;
+
+       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 != -NLE_OPNOTSUPP)
+                               goto errout;
+               }
+       }
+
+
+       err = -NLE_MSGTYPE_NOSUPPORT;
+errout:
+       return err;
+}
+/** @endcond */
+
+/**
+ * Parse a netlink message and add it to the cache.
+ * @arg cache          cache to add element to
+ * @arg msg            netlink message
+ *
+ * Parses a netlink message by calling the cache specific message parser
+ * and adds the new element to the cache. If an old object with same key
+ * attributes is present in the cache, it is replaced with the new object.
+ * If the old object type supports an update operation, an update is
+ * attempted before a replace.
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
+{
+       struct nl_parser_param p = {
+               .pp_cb = pickup_cb,
+               .pp_arg = cache,
+       };
+
+       return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
+}
+
+/**
+ * (Re)fill a cache with the contents in the kernel.
+ * @arg sk             Netlink socket.
+ * @arg cache          cache to update
+ *
+ * Clears the specified cache and fills it with the current state in
+ * the kernel.
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
+{
+       struct nl_af_group *grp;
+       int err;
+
+       nl_cache_clear(cache);
+       grp = cache->c_ops->co_groups;
+       do {
+               if (grp && grp->ag_group &&
+                       (cache->c_flags & NL_CACHE_AF_ITER))
+                       nl_cache_set_arg1(cache, grp->ag_family);
+
+restart:
+               err = nl_cache_request_full_dump(sk, cache);
+               if (err < 0)
+                       return err;
+
+               NL_DBG(2, "Updating cache %p <%s> for family %u, request sent, waiting for reply\n",
+                      cache, nl_cache_name(cache), grp ? grp->ag_family : AF_UNSPEC);
+
+               err = nl_cache_pickup(sk, cache);
+               if (err == -NLE_DUMP_INTR) {
+                       NL_DBG(2, "Dump interrupted, restarting!\n");
+                       goto restart;
+               } else if (err < 0)
+                       break;
+
+               if (grp)
+                       grp++;
+       } while (grp && grp->ag_group &&
+                       (cache->c_flags & NL_CACHE_AF_ITER));
+
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Utillities
+ * @{
+ */
+static struct nl_object *__cache_fast_lookup(struct nl_cache *cache,
+                                            struct nl_object *needle)
+{
+       struct nl_object *obj;
+
+       obj = nl_hash_table_lookup(cache->hashtable, needle);
+       if (obj) {
+           nl_object_get(obj);
+           return obj;
+       }
+
+       return NULL;
+}
+
+/**
+ * Search object in cache
+ * @arg cache          Cache
+ * @arg needle         Object to look for.
+ *
+ * Searches the cache for an object which matches the object \p needle.
+ * The function nl_object_identical() is used to determine if the
+ * objects match. If a matching object is found, the reference counter
+ * is incremented and the object is returned.
+ * 
+ * Therefore, if an object is returned, the reference to the object
+ * must be returned by calling nl_object_put() after usage.
+ *
+ * @return Reference to object or NULL if not found.
+ */
+struct nl_object *nl_cache_search(struct nl_cache *cache,
+                                 struct nl_object *needle)
+{
+       struct nl_object *obj;
+
+       if (cache->hashtable)
+               return __cache_fast_lookup(cache, needle);
+
+       nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
+               if (nl_object_identical(obj, needle)) {
+                       nl_object_get(obj);
+                       return obj;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Find object in cache
+ * @arg cache          Cache
+ * @arg filter         object acting as a filter
+ *
+ * Searches the cache for an object which matches the object filter.
+ * If the filter attributes matches the object type id attributes,
+ * and the cache supports hash lookups, a faster hashtable lookup
+ * is used to return the object. Else, function nl_object_match_filter() is
+ * used to determine if the objects match. If a matching object is
+ * found, the reference counter is incremented and the object is returned.
+ *
+ * Therefore, if an object is returned, the reference to the object
+ * must be returned by calling nl_object_put() after usage.
+ *
+ * @return Reference to object or NULL if not found.
+ */
+struct nl_object *nl_cache_find(struct nl_cache *cache,
+                               struct nl_object *filter)
+{
+       struct nl_object *obj;
+
+       if (cache->c_ops == NULL)
+               BUG();
+
+       if ((nl_object_get_id_attrs(filter) == filter->ce_mask)
+               && cache->hashtable)
+               return __cache_fast_lookup(cache, filter);
+
+       nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
+               if (nl_object_match_filter(obj, filter)) {
+                       nl_object_get(obj);
+                       return obj;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Mark all objects of a cache
+ * @arg cache          Cache
+ *
+ * Marks all objects of a cache by calling nl_object_mark() on each
+ * object associated with the cache.
+ */
+void nl_cache_mark_all(struct nl_cache *cache)
+{
+       struct nl_object *obj;
+
+       NL_DBG(2, "Marking all objects in cache %p <%s>\n",
+              cache, nl_cache_name(cache));
+
+       nl_list_for_each_entry(obj, &cache->c_items, ce_list)
+               nl_object_mark(obj);
+}
+
+/** @} */
+
+/**
+ * @name Dumping
+ * @{
+ */
+
+/**
+ * Dump all elements of a cache.
+ * @arg cache          cache to dump
+ * @arg params         dumping parameters
+ *
+ * Dumps all elements of the \a cache to the file descriptor \a fd.
+ */
+void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
+{
+       nl_cache_dump_filter(cache, params, NULL);
+}
+
+/**
+ * Dump all elements of a cache (filtered).
+ * @arg cache          cache to dump
+ * @arg params         dumping parameters (optional)
+ * @arg filter         filter object
+ *
+ * Dumps all elements of the \a cache to the file descriptor \a fd
+ * given they match the given filter \a filter.
+ */
+void nl_cache_dump_filter(struct nl_cache *cache,
+                         struct nl_dump_params *params,
+                         struct nl_object *filter)
+{
+       int type = params ? params->dp_type : NL_DUMP_DETAILS;
+       struct nl_object_ops *ops;
+       struct nl_object *obj;
+
+       NL_DBG(2, "Dumping cache %p <%s> with filter %p\n",
+              cache, nl_cache_name(cache), filter);
+
+       if (type > NL_DUMP_MAX || type < 0)
+               BUG();
+
+       if (cache->c_ops == NULL)
+               BUG();
+
+       ops = cache->c_ops->co_obj_ops;
+       if (!ops->oo_dump[type])
+               return;
+
+       if (params->dp_buf)
+               memset(params->dp_buf, 0, params->dp_buflen);
+
+       nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
+               if (filter && !nl_object_match_filter(obj, filter))
+                       continue;
+
+               NL_DBG(4, "Dumping object %p...\n", obj);
+               dump_from_ops(obj, params);
+       }
+}
+
+/** @} */
+
+/**
+ * @name Iterators
+ * @{
+ */
+
+/**
+ * Call a callback on each element of the cache.
+ * @arg cache          cache to iterate on
+ * @arg cb             callback function
+ * @arg arg            argument passed to callback function
+ *
+ * Calls a callback function \a cb on each element of the \a cache.
+ * The argument \a arg is passed on the callback function.
+ */
+void nl_cache_foreach(struct nl_cache *cache,
+                     void (*cb)(struct nl_object *, void *), void *arg)
+{
+       nl_cache_foreach_filter(cache, NULL, cb, arg);
+}
+
+/**
+ * Call a callback on each element of the cache (filtered).
+ * @arg cache          cache to iterate on
+ * @arg filter         filter object
+ * @arg cb             callback function
+ * @arg arg            argument passed to callback function
+ *
+ * Calls a callback function \a cb on each element of the \a cache
+ * that matches the \a filter. The argument \a arg is passed on
+ * to the callback function.
+ */
+void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter,
+                            void (*cb)(struct nl_object *, void *), void *arg)
+{
+       struct nl_object *obj, *tmp;
+
+       if (cache->c_ops == NULL)
+               BUG();
+
+       nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) {
+               if (filter) {
+                       int diff = nl_object_match_filter(obj, filter);
+
+                       NL_DBG(3, "%p<->%p object difference: %x\n",
+                               obj, filter, diff);
+
+                       if (!diff)
+                               continue;
+               }
+
+               /* Caller may hold obj for a long time */
+               nl_object_get(obj);
+
+               cb(obj, arg);
+
+               nl_object_put(obj);
+       }
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/cache_mngr.c b/lib/cache_mngr.c
new file mode 100644 (file)
index 0000000..f8a65e3
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * lib/cache_mngr.c    Cache Manager
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cache_mngt
+ * @defgroup cache_mngr Manager
+ * @brief Manager keeping caches up to date automatically.
+ *
+ * The cache manager keeps caches up to date automatically by listening to
+ * netlink notifications and integrating the received information into the
+ * existing cache.
+ *
+ * @note This functionality is still considered experimental.
+ *
+ * Related sections in the development guide:
+ * - @core_doc{_cache_manager,Cache Manager}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/cache.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define NASSOC_INIT            16
+#define NASSOC_EXPAND          8
+/** @endcond */
+
+static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
+{
+       struct nl_cache_assoc *ca = p->pp_arg;
+       struct nl_cache_ops *ops = ca->ca_cache->c_ops;
+
+       NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache);
+#ifdef NL_DEBUG
+       if (nl_debug >= 4)
+               nl_object_dump(obj, &nl_debug_dp);
+#endif
+
+       if (ops->co_event_filter)
+               if (ops->co_event_filter(ca->ca_cache, obj) != NL_OK)
+                       return 0;
+
+       if (ops->co_include_event)
+               return ops->co_include_event(ca->ca_cache, obj, ca->ca_change,
+                                            ca->ca_change_data);
+       else
+               return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
+}
+
+static int event_input(struct nl_msg *msg, void *arg)
+{
+       struct nl_cache_mngr *mngr = arg;
+       int protocol = nlmsg_get_proto(msg);
+       int type = nlmsg_hdr(msg)->nlmsg_type;
+       struct nl_cache_ops *ops;
+       int i, n;
+       struct nl_parser_param p = {
+               .pp_cb = include_cb,
+       };
+
+       NL_DBG(2, "Cache manager %p, handling new message %p as event\n",
+              mngr, msg);
+#ifdef NL_DEBUG
+       if (nl_debug >= 4)
+               nl_msg_dump(msg, stderr);
+#endif
+
+       if (mngr->cm_protocol != protocol)
+               BUG();
+
+       for (i = 0; i < mngr->cm_nassocs; i++) {
+               if (mngr->cm_assocs[i].ca_cache) {
+                       ops = mngr->cm_assocs[i].ca_cache->c_ops;
+                       for (n = 0; ops->co_msgtypes[n].mt_id >= 0; n++)
+                               if (ops->co_msgtypes[n].mt_id == type)
+                                       goto found;
+               }
+       }
+
+       return NL_SKIP;
+
+found:
+       NL_DBG(2, "Associated message %p to cache %p\n",
+              msg, mngr->cm_assocs[i].ca_cache);
+       p.pp_arg = &mngr->cm_assocs[i];
+
+       return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
+}
+
+/**
+ * Allocate new cache manager
+ * @arg sk             Netlink socket or NULL to auto allocate
+ * @arg protocol       Netlink protocol this manager is used for
+ * @arg flags          Flags (\c NL_AUTO_PROVIDE)
+ * @arg result         Result pointer
+ *
+ * Allocates a new cache manager for the specified netlink protocol.
+ *
+ * 1. If sk is not specified (\c NULL) a netlink socket matching the
+ *    specified protocol will be automatically allocated.
+ *
+ * 2. The socket will be put in non-blocking mode and sequence checking
+ *    will be disabled regardless of whether the socket was provided by
+ *    the caller or automatically allocated.
+ *
+ * 3. The socket will be connected.
+ *
+ * If the flag \c NL_AUTO_PROVIDE is specified, any cache added to the
+ * manager will automatically be made available to other users using
+ * nl_cache_mngt_provide().
+ *
+ * @note If the socket is provided by the caller, it is NOT recommended
+ *       to use the socket for anything else besides receiving netlink
+ *       notifications.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_mngr_alloc(struct nl_sock *sk, int protocol, int flags,
+                       struct nl_cache_mngr **result)
+{
+       struct nl_cache_mngr *mngr;
+       int err = -NLE_NOMEM;
+
+       /* Catch abuse of flags */
+       if (flags & NL_ALLOCATED_SOCK)
+               BUG();
+
+       mngr = calloc(1, sizeof(*mngr));
+       if (!mngr)
+               return -NLE_NOMEM;
+
+       if (!sk) {
+               if (!(sk = nl_socket_alloc()))
+                       goto errout;
+
+               flags |= NL_ALLOCATED_SOCK;
+       }
+
+       mngr->cm_sock = sk;
+       mngr->cm_nassocs = NASSOC_INIT;
+       mngr->cm_protocol = protocol;
+       mngr->cm_flags = flags;
+       mngr->cm_assocs = calloc(mngr->cm_nassocs,
+                                sizeof(struct nl_cache_assoc));
+       if (!mngr->cm_assocs)
+               goto errout;
+
+       /* Required to receive async event notifications */
+       nl_socket_disable_seq_check(mngr->cm_sock);
+
+       if ((err = nl_connect(mngr->cm_sock, protocol) < 0))
+               goto errout;
+
+       if ((err = nl_socket_set_nonblocking(mngr->cm_sock) < 0))
+               goto errout;
+
+       /* Create and allocate socket for sync cache fills */
+       mngr->cm_sync_sock = nl_socket_alloc();
+       if (!mngr->cm_sync_sock)
+               goto errout;
+       if ((err = nl_connect(mngr->cm_sync_sock, protocol)) < 0)
+               goto errout_free_sync_sock;
+
+       NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
+              mngr, protocol, mngr->cm_nassocs);
+
+       *result = mngr;
+       return 0;
+
+errout_free_sync_sock:
+       nl_socket_free(mngr->cm_sync_sock);
+errout:
+       nl_cache_mngr_free(mngr);
+       return err;
+}
+
+/**
+ * Add cache to cache manager
+ * @arg mngr           Cache manager.
+ * @arg cache          Cache to be added to cache manager
+ * @arg cb             Function to be called upon changes.
+ * @arg data           Argument passed on to change callback
+ *
+ * Adds cache to the manager. The operation will trigger a full
+ * dump request from the kernel to initially fill the contents
+ * of the cache. The manager will subscribe to the notification group
+ * of the cache and keep track of any further changes.
+ *
+ * The user is responsible for calling nl_cache_mngr_poll() or monitor
+ * the socket and call nl_cache_mngr_data_ready() to allow the library
+ * to process netlink notification events.
+ *
+ * @see nl_cache_mngr_poll()
+ * @see nl_cache_mngr_data_ready()
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
+ *                            cache type
+ * @return -NLE_OPNOTSUPP Cache type does not support updates
+ * @return -NLE_EXIST Cache of this type already being managed
+ */
+int nl_cache_mngr_add_cache(struct nl_cache_mngr *mngr, struct nl_cache *cache,
+                     change_func_t cb, void *data)
+{
+       struct nl_cache_ops *ops;
+       struct nl_af_group *grp;
+       int err, i;
+
+       ops = cache->c_ops;
+       if (!ops)
+               return -NLE_INVAL;
+
+       if (ops->co_protocol != mngr->cm_protocol)
+               return -NLE_PROTO_MISMATCH;
+
+       if (ops->co_groups == NULL)
+               return -NLE_OPNOTSUPP;
+
+       for (i = 0; i < mngr->cm_nassocs; i++)
+               if (mngr->cm_assocs[i].ca_cache &&
+                   mngr->cm_assocs[i].ca_cache->c_ops == ops)
+                       return -NLE_EXIST;
+
+retry:
+       for (i = 0; i < mngr->cm_nassocs; i++)
+               if (!mngr->cm_assocs[i].ca_cache)
+                       break;
+
+       if (i >= mngr->cm_nassocs) {
+               mngr->cm_nassocs += NASSOC_EXPAND;
+               mngr->cm_assocs = realloc(mngr->cm_assocs,
+                                         mngr->cm_nassocs *
+                                         sizeof(struct nl_cache_assoc));
+               if (mngr->cm_assocs == NULL)
+                       return -NLE_NOMEM;
+
+               memset(mngr->cm_assocs + (mngr->cm_nassocs - NASSOC_EXPAND), 0,
+                      NASSOC_EXPAND * sizeof(struct nl_cache_assoc));
+
+               NL_DBG(1, "Increased capacity of cache manager %p " \
+                         "to %d\n", mngr, mngr->cm_nassocs);
+               goto retry;
+       }
+
+       for (grp = ops->co_groups; grp->ag_group; grp++) {
+               err = nl_socket_add_membership(mngr->cm_sock, grp->ag_group);
+               if (err < 0)
+                       return err;
+       }
+
+       err = nl_cache_refill(mngr->cm_sync_sock, cache);
+       if (err < 0)
+               goto errout_drop_membership;
+
+       mngr->cm_assocs[i].ca_cache = cache;
+       mngr->cm_assocs[i].ca_change = cb;
+       mngr->cm_assocs[i].ca_change_data = data;
+
+       if (mngr->cm_flags & NL_AUTO_PROVIDE)
+               nl_cache_mngt_provide(cache);
+
+       NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
+              cache, nl_cache_name(cache), mngr);
+
+       return 0;
+
+errout_drop_membership:
+       for (grp = ops->co_groups; grp->ag_group; grp++)
+               nl_socket_drop_membership(mngr->cm_sock, grp->ag_group);
+
+       return err;
+}
+
+/**
+ * Add cache to cache manager
+ * @arg mngr           Cache manager.
+ * @arg name           Name of cache to keep track of
+ * @arg cb             Function to be called upon changes.
+ * @arg data           Argument passed on to change callback
+ * @arg result         Pointer to store added cache (optional)
+ *
+ * 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
+ * initially fill the contents of the cache. The manager will subscribe
+ * to the notification group of the cache and keep track of any further
+ * changes.
+ *
+ * The user is responsible for calling nl_cache_mngr_poll() or monitor
+ * the socket and call nl_cache_mngr_data_ready() to allow the library
+ * to process netlink notification events.
+ *
+ * @see nl_cache_mngr_poll()
+ * @see nl_cache_mngr_data_ready()
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_NOCACHE Unknown cache type
+ * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
+ *                            cache type
+ * @return -NLE_OPNOTSUPP Cache type does not support updates
+ * @return -NLE_EXIST Cache of this type already being managed
+ */
+int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
+                     change_func_t cb, void *data, struct nl_cache **result)
+{
+       struct nl_cache_ops *ops;
+       struct nl_cache *cache;
+       int err;
+
+       ops = nl_cache_ops_lookup_safe(name);
+       if (!ops)
+               return -NLE_NOCACHE;
+
+       cache = nl_cache_alloc(ops);
+       nl_cache_ops_put(ops);
+       if (!cache)
+               return -NLE_NOMEM;
+
+       err = nl_cache_mngr_add_cache(mngr, cache, cb, data);
+       if (err < 0)
+               goto errout_free_cache;
+
+       *result = cache;
+       return 0;
+
+errout_free_cache:
+       nl_cache_free(cache);
+
+       return err;
+}
+
+/**
+ * Get socket file descriptor
+ * @arg mngr           Cache Manager
+ *
+ * Get the file descriptor of the socket associated with the manager.
+ *
+ * @note Do not use the socket for anything besides receiving
+ *       notifications.
+ */
+int nl_cache_mngr_get_fd(struct nl_cache_mngr *mngr)
+{
+       return nl_socket_get_fd(mngr->cm_sock);
+}
+
+/**
+ * Check for event notifications
+ * @arg mngr           Cache Manager
+ * @arg timeout                Upper limit poll() will block, in milliseconds.
+ *
+ * Causes poll() to be called to check for new event notifications
+ * being available. Calls nl_cache_mngr_data_ready() to process
+ * available data.
+ *
+ * This functionally is ideally called regularly during an idle
+ * period.
+ *
+ * A timeout can be specified in milliseconds to limit the time the
+ * function will wait for updates.
+ *
+ * @see nl_cache_mngr_data_ready()
+ *
+ * @return The number of messages processed or a negative error code.
+ */
+int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout)
+{
+       int ret;
+       struct pollfd fds = {
+               .fd = nl_socket_get_fd(mngr->cm_sock),
+               .events = POLLIN,
+       };
+
+       NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
+       ret = poll(&fds, 1, timeout);
+       NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
+       if (ret < 0)
+               return -nl_syserr2nlerr(errno);
+
+       /* No events, return */
+       if (ret == 0)
+               return 0;
+
+       return nl_cache_mngr_data_ready(mngr);
+}
+
+/**
+ * Receive available event notifications
+ * @arg mngr           Cache manager
+ *
+ * This function can be called if the socket associated to the manager
+ * contains updates to be received. This function should only be used
+ * if nl_cache_mngr_poll() is not used.
+ *
+ * The function will process messages until there is no more data to
+ * be read from the socket.
+ *
+ * @see nl_cache_mngr_poll()
+ *
+ * @return The number of messages processed or a negative error code.
+ */
+int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr)
+{
+       int err, nread = 0;
+       struct nl_cb *cb;
+
+       NL_DBG(2, "Cache manager %p, reading new data from fd %d\n",
+              mngr, nl_socket_get_fd(mngr->cm_sock));
+
+       cb = nl_cb_clone(mngr->cm_sock->s_cb);
+       if (cb == NULL)
+               return -NLE_NOMEM;
+
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, event_input, mngr);
+
+       while ((err = nl_recvmsgs_report(mngr->cm_sock, cb)) > 0) {
+               NL_DBG(2, "Cache manager %p, recvmsgs read %d messages\n",
+                      mngr, err);
+               nread += err;
+       }
+
+       nl_cb_put(cb);
+       if (err < 0)
+               return err;
+
+       return nread;
+}
+
+/**
+ * Print information about cache manager
+ * @arg mngr           Cache manager
+ * @arg p              Dumping parameters
+ *
+ * Prints information about the cache manager including all managed caches.
+ *
+ * @note This is a debugging function.
+ */
+void nl_cache_mngr_info(struct nl_cache_mngr *mngr, struct nl_dump_params *p)
+{
+       char buf[128];
+       int i;
+
+       nl_dump_line(p, "cache-manager <%p>\n", mngr);
+       nl_dump_line(p, "  .protocol = %s\n",
+                    nl_nlfamily2str(mngr->cm_protocol, buf, sizeof(buf)));
+       nl_dump_line(p, "  .flags    = %#x\n", mngr->cm_flags);
+       nl_dump_line(p, "  .nassocs  = %u\n", mngr->cm_nassocs);
+       nl_dump_line(p, "  .sock     = <%p>\n", mngr->cm_sock);
+
+       for (i = 0; i < mngr->cm_nassocs; i++) {
+               struct nl_cache_assoc *assoc = &mngr->cm_assocs[i];
+
+               if (assoc->ca_cache) {
+                       nl_dump_line(p, "  .cache[%d] = <%p> {\n", i, assoc->ca_cache);
+                       nl_dump_line(p, "    .name = %s\n", assoc->ca_cache->c_ops->co_name);
+                       nl_dump_line(p, "    .change_func = <%p>\n", assoc->ca_change);
+                       nl_dump_line(p, "    .change_data = <%p>\n", assoc->ca_change_data);
+                       nl_dump_line(p, "    .nitems = %u\n", nl_cache_nitems(assoc->ca_cache));
+                       nl_dump_line(p, "    .objects = {\n");
+
+                       p->dp_prefix += 6;
+                       nl_cache_dump(assoc->ca_cache, p);
+                       p->dp_prefix -= 6;
+
+                       nl_dump_line(p, "    }\n");
+                       nl_dump_line(p, "  }\n");
+               }
+       }
+}
+
+/**
+ * Free cache manager and all caches.
+ * @arg mngr           Cache manager.
+ *
+ * Release all resources held by a cache manager.
+ */
+void nl_cache_mngr_free(struct nl_cache_mngr *mngr)
+{
+       int i;
+
+       if (!mngr)
+               return;
+
+       if (mngr->cm_sock)
+               nl_close(mngr->cm_sock);
+
+       if (mngr->cm_sync_sock) {
+               nl_close(mngr->cm_sync_sock);
+               nl_socket_free(mngr->cm_sync_sock);
+       }
+
+       if (mngr->cm_flags & NL_ALLOCATED_SOCK)
+               nl_socket_free(mngr->cm_sock);
+
+       for (i = 0; i < mngr->cm_nassocs; i++) {
+               if (mngr->cm_assocs[i].ca_cache) {
+                       nl_cache_mngt_unprovide(mngr->cm_assocs[i].ca_cache);
+                       nl_cache_free(mngr->cm_assocs[i].ca_cache);
+               }
+       }
+
+       free(mngr->cm_assocs);
+       free(mngr);
+
+       NL_DBG(1, "Cache manager %p freed\n", mngr);
+}
+
+/** @} */
diff --git a/lib/cache_mngt.c b/lib/cache_mngt.c
new file mode 100644 (file)
index 0000000..4d3d6ff
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * lib/cache_mngt.c    Cache Management
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup cache_mngt Caching System
+ *
+ * Related sections in the development guide:
+ * - @core_doc{core_cache, Caching System}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/cache.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+
+static struct nl_cache_ops *cache_ops;
+static NL_RW_LOCK(cache_ops_lock);
+
+/**
+ * @name Cache Operations Sets
+ * @{
+ */
+
+struct nl_cache_ops *__nl_cache_ops_lookup(const char *name)
+{
+       struct nl_cache_ops *ops;
+
+       for (ops = cache_ops; ops; ops = ops->co_next)
+               if (!strcmp(ops->co_name, name))
+                       return ops;
+
+       return NULL;
+}
+
+/**
+ * Increment reference counter
+ * @arg ops            Cache operations
+ */
+void nl_cache_ops_get(struct nl_cache_ops *ops)
+{
+       ops->co_refcnt++;
+}
+
+/**
+ * Decrement reference counter
+ * @arg ops            Cache operations
+ */
+void nl_cache_ops_put(struct nl_cache_ops *ops)
+{
+       ops->co_refcnt--;
+}
+
+/**
+ * Lookup cache operations by name
+ * @arg name           name of the cache type
+ *
+ * @attention This function is not safe, it does not increment the reference
+ *            counter. Please use nl_cache_ops_lookup_safe().
+ *
+ * @return The cache operations or NULL if not found.
+ */
+struct nl_cache_ops *nl_cache_ops_lookup(const char *name)
+{
+       struct nl_cache_ops *ops;
+
+       nl_read_lock(&cache_ops_lock);
+       ops = __nl_cache_ops_lookup(name);
+       nl_read_unlock(&cache_ops_lock);
+
+       return ops;
+}
+
+/**
+ * Lookup cache operations by name
+ * @arg name           name of the cache type
+ *
+ * @note The reference counter of the returned cache operation is incremented
+ *       and must be decremented after use with nl_cache_ops_put().
+ *
+ * @return The cache operations or NULL if not found.
+ */
+struct nl_cache_ops *nl_cache_ops_lookup_safe(const char *name)
+{
+       struct nl_cache_ops *ops;
+
+       nl_write_lock(&cache_ops_lock);
+       if ((ops = __nl_cache_ops_lookup(name)))
+               nl_cache_ops_get(ops);
+       nl_write_unlock(&cache_ops_lock);
+
+       return ops;
+}
+
+static struct nl_cache_ops *__cache_ops_associate(int protocol, int msgtype)
+{
+       int i;
+       struct nl_cache_ops *ops;
+
+       for (ops = cache_ops; ops; ops = ops->co_next) {
+               if (ops->co_protocol != protocol)
+                       continue;
+
+               for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
+                       if (ops->co_msgtypes[i].mt_id == msgtype)
+                               return ops;
+       }
+
+       return NULL;
+}
+
+/**
+ * Associate protocol and message type to cache operations
+ * @arg protocol               netlink protocol
+ * @arg msgtype                        netlink message type
+ *
+ * @attention This function is not safe, it does not increment the reference
+ *            counter. Please use nl_cache_ops_associate_safe().
+ *
+ * @see nl_cache_ops_associate_safe()
+ *
+ * @return The cache operations or NULL if no match found.
+ */
+struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype)
+{
+       struct nl_cache_ops *ops;
+
+       nl_read_lock(&cache_ops_lock);
+       ops = __cache_ops_associate(protocol, msgtype);
+       nl_read_unlock(&cache_ops_lock);
+
+       return ops;
+}
+
+/**
+ * Associate protocol and message type to cache operations
+ * @arg protocol               netlink protocol
+ * @arg msgtype                        netlink message type
+ *
+ * Searches the registered cache operations for a matching protocol
+ * and message type.
+ *
+ * @note The reference counter of the returned cache operation is incremented
+ *       and must be decremented after use with nl_cache_ops_put().
+ *
+ * @return The cache operations or NULL if no no match was found.
+ */
+struct nl_cache_ops *nl_cache_ops_associate_safe(int protocol, int msgtype)
+{
+       struct nl_cache_ops *ops;
+
+       nl_write_lock(&cache_ops_lock);
+       if ((ops = __cache_ops_associate(protocol, msgtype)))
+               nl_cache_ops_get(ops);
+       nl_write_unlock(&cache_ops_lock);
+
+       return ops;
+}
+
+/**
+ * Lookup message type cache association
+ * @arg ops                    cache operations
+ * @arg msgtype                        netlink message type
+ *
+ * Searches for a matching message type association ing the specified
+ * cache operations.
+ *
+ * @attention The guranteed lifetime of the returned message type is bound
+ *            to the lifetime of the underlying cache operations.
+ *
+ * @return A message type association or NULL.
+ */
+struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype)
+{
+       int i;
+
+       for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
+               if (ops->co_msgtypes[i].mt_id == msgtype)
+                       return &ops->co_msgtypes[i];
+
+       return NULL;
+}
+
+/* Must hold cache_ops_lock */
+static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops)
+{
+       struct nl_cache_ops *ops;
+
+       for (ops = cache_ops; ops; ops = ops->co_next)
+               if (ops->co_obj_ops == obj_ops)
+                       return ops;
+
+       return NULL;
+
+}
+
+/**
+ * Call a function for each registered cache operation
+ * @arg cb             Callback function to be called
+ * @arg arg            User specific argument.
+ */
+void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg)
+{
+       struct nl_cache_ops *ops;
+
+       nl_read_lock(&cache_ops_lock);
+       for (ops = cache_ops; ops; ops = ops->co_next)
+               cb(ops, arg);
+       nl_read_unlock(&cache_ops_lock);
+}
+
+/**
+ * Set default flags for caches of this type
+ * @arg ops            Cache ops
+ * @arg flags          Flags to set
+ *
+ * The cache operation flags will be derived to all caches allocates
+ * based on this set of cache operations.
+ */
+void nl_cache_ops_set_flags(struct nl_cache_ops *ops, unsigned int flags)
+{
+       nl_write_lock(&cache_ops_lock);
+       ops->co_flags |= flags;
+       nl_write_unlock(&cache_ops_lock);
+}
+
+/**
+ * Register a set of cache operations
+ * @arg ops            cache operations
+ *
+ * Called by users of caches to announce the avaibility of
+ * a certain cache type.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_mngt_register(struct nl_cache_ops *ops)
+{
+       if (!ops->co_name || !ops->co_obj_ops)
+               return -NLE_INVAL;
+
+       nl_write_lock(&cache_ops_lock);
+       if (__nl_cache_ops_lookup(ops->co_name)) {
+               nl_write_unlock(&cache_ops_lock);
+               return -NLE_EXIST;
+       }
+
+       ops->co_refcnt = 0;
+       ops->co_next = cache_ops;
+       cache_ops = ops;
+       nl_write_unlock(&cache_ops_lock);
+
+       NL_DBG(1, "Registered cache operations %s\n", ops->co_name);
+
+       return 0;
+}
+
+/**
+ * Unregister a set of cache operations
+ * @arg ops            cache operations
+ *
+ * Called by users of caches to announce a set of
+ * cache operations is no longer available. The
+ * specified cache operations must have been registered
+ * previously using nl_cache_mngt_register()
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
+{
+       struct nl_cache_ops *t, **tp;
+       int err = 0;
+
+       nl_write_lock(&cache_ops_lock);
+
+       if (ops->co_refcnt > 0) {
+               err = -NLE_BUSY;
+               goto errout;
+       }
+
+       for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next)
+               if (t == ops)
+                       break;
+
+       if (!t) {
+               err = -NLE_NOCACHE;
+               goto errout;
+       }
+
+       NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name);
+
+       *tp = t->co_next;
+errout:
+       nl_write_unlock(&cache_ops_lock);
+
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Global Cache Provisioning/Requiring
+ * @{
+ */
+
+/**
+ * Provide a cache for global use
+ * @arg cache          cache to provide
+ *
+ * Offers the specified cache to be used by other modules.
+ * Only one cache per type may be shared at a time,
+ * a previsouly provided caches will be overwritten.
+ */
+void nl_cache_mngt_provide(struct nl_cache *cache)
+{
+       struct nl_cache_ops *ops;
+
+       nl_write_lock(&cache_ops_lock);
+
+       ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
+       if (!ops)
+               BUG();
+       else {
+               nl_cache_get(cache);
+
+               /*
+                * Hold a reference to the cache operations to ensure the
+                * ops don't go away while we use it to store the cache pointer.
+                */
+               if (!ops->co_major_cache)
+                       nl_cache_ops_get(ops);
+
+               ops->co_major_cache = cache;
+       }
+
+       nl_write_unlock(&cache_ops_lock);
+}
+
+/**
+ * Unprovide a cache for global use
+ * @arg cache          cache to unprovide
+ *
+ * Cancels the offer to use a cache globally. The
+ * cache will no longer be returned via lookups but
+ * may still be in use.
+ */
+void nl_cache_mngt_unprovide(struct nl_cache *cache)
+{
+       struct nl_cache_ops *ops;
+
+       nl_write_lock(&cache_ops_lock);
+
+       ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops);
+       if (!ops)
+               BUG();
+       else if (ops->co_major_cache == cache) {
+               nl_cache_free(ops->co_major_cache);
+               nl_cache_ops_put(ops);
+               ops->co_major_cache = NULL;
+       }
+
+       nl_write_unlock(&cache_ops_lock);
+}
+
+struct nl_cache *__nl_cache_mngt_require(const char *name)
+{
+       struct nl_cache_ops *ops;
+       struct nl_cache *cache = NULL;
+
+       ops = nl_cache_ops_lookup_safe(name);
+       if (ops) {
+               cache = ops->co_major_cache;
+               nl_cache_ops_put(ops);
+       }
+       
+       return cache;
+}
+
+/**
+ * Return cache previously provided via nl_cache_mngt_provide()
+ * @arg name           Name of cache to lookup
+ *
+ * @attention This function is not safe, it does not increment the reference
+ *            counter. Please use nl_cache_mngt_require_safe().
+ *
+ * @see nl_cache_mngt_require_safe()
+ *
+ * @return Pointer to cache or NULL if none registered
+ */
+struct nl_cache *nl_cache_mngt_require(const char *name)
+{
+       struct nl_cache *cache;
+
+       if (!(cache = __nl_cache_mngt_require(name)))
+               NL_DBG(1, "Application BUG: Your application must "
+                      "call nl_cache_mngt_provide() and\nprovide a valid "
+                      "%s cache to be used for internal lookups.\nSee the "
+                      " API documentation for more details.\n", name);
+       
+       return cache;
+}
+
+/**
+ * Return cache previously provided via nl_cache_mngt_provide()
+ * @arg name           Name of cache to lookup
+ *
+ * @note The reference counter of the returned cache is incremented
+ *       and must be decremented after use with nl_cache_put().
+ *
+ * @return Pointer to cache or NULL if none registered
+ */
+struct nl_cache *nl_cache_mngt_require_safe(const char *name)
+{
+       struct nl_cache *cache;
+
+       if ((cache = nl_cache_mngt_require(name)))
+               nl_cache_get(cache);
+       
+       return cache;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/cli/cls/basic.c b/lib/cli/cls/basic.c
new file mode 100644 (file)
index 0000000..1939988
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * lib/cli/cls/basic.c         basic classifier module for CLI lib
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/route/cls/basic.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-cls-add [...] basic [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" -h, --help                Show this help text.\n"
+" -t, --target=ID           Target class to send matching packets to\n"
+" -e, --ematch=EXPR         Ematch expression\n"
+"\n"
+"EXAMPLE"
+"    # Create a \"catch-all\" classifier, attached to \"q_root\", classyfing\n"
+"    # all not yet classified packets to class \"c_default\"\n"
+"    nl-cls-add --dev=eth0 --parent=q_root basic --target=c_default\n");
+}
+
+static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       struct rtnl_cls *cls = (struct rtnl_cls *) tc;
+       struct rtnl_ematch_tree *tree;
+       uint32_t target;
+       int err;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_TARGET = 257,
+                       ARG_DEFAULT = 258,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "target", 1, 0, 't' },
+                       { "ematch", 1, 0, 'e' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "ht:e:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage();
+                       exit(0);
+
+               case 't':
+                       if ((err = rtnl_tc_str2handle(optarg, &target)) < 0)
+                               nl_cli_fatal(err, "Unable to parse target \"%s\":",
+                                       optarg, nl_geterror(err));
+
+                       rtnl_basic_set_target(cls, target);
+                       break;
+
+               case 'e':
+                       tree = nl_cli_cls_parse_ematch(cls, optarg);
+                       rtnl_basic_set_ematch(cls, tree);
+                       break;
+               }
+       }
+}
+
+static struct nl_cli_tc_module basic_module =
+{
+       .tm_name                = "basic",
+       .tm_type                = RTNL_TC_TYPE_CLS,
+       .tm_parse_argv          = parse_argv,
+};
+
+static void __init basic_init(void)
+{
+       nl_cli_tc_register(&basic_module);
+}
+
+static void __exit basic_exit(void)
+{
+       nl_cli_tc_unregister(&basic_module);
+}
diff --git a/lib/cli/cls/cgroup.c b/lib/cli/cls/cgroup.c
new file mode 100644 (file)
index 0000000..fae6208
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * lib/cli/cls/cgroup.c        cgroup classifier module for CLI lib
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/route/cls/cgroup.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-cls-add [...] cgroup [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" -h, --help                Show this help text.\n"
+" -e, --ematch=EXPR         Ematch expression\n"
+"\n"
+"EXAMPLE"
+"    nl-cls-add --dev=eth0 --parent=q_root cgroup\n");
+}
+
+static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       struct rtnl_cls *cls = (struct rtnl_cls *) tc;
+       struct rtnl_ematch_tree *tree;
+
+       for (;;) {
+               int c, optidx = 0;
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "ematch", 1, 0, 'e' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "he:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage();
+                       exit(0);
+
+               case 'e':
+                       tree = nl_cli_cls_parse_ematch(cls, optarg);
+                       rtnl_cgroup_set_ematch(cls, tree);
+                       break;
+               }
+       }
+}
+
+static struct nl_cli_tc_module cgroup_module =
+{
+       .tm_name                = "cgroup",
+       .tm_type                = RTNL_TC_TYPE_CLS,
+       .tm_parse_argv          = parse_argv,
+};
+
+static void __init cgroup_init(void)
+{
+       nl_cli_tc_register(&cgroup_module);
+}
+
+static void __exit cgroup_exit(void)
+{
+       nl_cli_tc_unregister(&cgroup_module);
+}
diff --git a/lib/cli/qdisc/bfifo.c b/lib/cli/qdisc/bfifo.c
new file mode 100644 (file)
index 0000000..1ee4777
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * src/lib/bfifo.c             bfifo module for CLI lib
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/fifo.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-qdisc-add [...] bfifo [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --limit=LIMIT         Maximum queue length in number of bytes.\n"
+"\n"
+"EXAMPLE"
+"    # Attach bfifo with a 4KB bytes limit to eth1\n"
+"    nl-qdisc-add --dev=eth1 --parent=root bfifo --limit=4096\n");
+}
+
+static void bfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+       int limit;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_LIMIT = 257,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "limit", 1, 0, ARG_LIMIT },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "h", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage();
+                       return;
+
+               case ARG_LIMIT:
+                       limit = nl_size2int(optarg);
+                       if (limit < 0) {
+                               nl_cli_fatal(limit, "Unable to parse bfifo limit "
+                                       "\"%s\": Invalid format.", optarg);
+                       }
+
+                       rtnl_qdisc_fifo_set_limit(qdisc, limit);
+                       break;
+               }
+       }
+}
+
+static struct nl_cli_tc_module bfifo_module =
+{
+       .tm_name                = "bfifo",
+       .tm_type                = RTNL_TC_TYPE_QDISC,
+       .tm_parse_argv          = bfifo_parse_argv,
+};
+
+static void __init bfifo_init(void)
+{
+       nl_cli_tc_register(&bfifo_module);
+}
+
+static void __exit bfifo_exit(void)
+{
+       nl_cli_tc_unregister(&bfifo_module);
+}
diff --git a/lib/cli/qdisc/blackhole.c b/lib/cli/qdisc/blackhole.c
new file mode 100644 (file)
index 0000000..af9dc6d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * src/lib/blackhole.c    Blackhole module for CLI lib
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-qdisc-add [...] blackhole [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"\n"
+"EXAMPLE"
+"    # Drop all outgoing packets on eth1\n"
+"    nl-qdisc-add --dev=eth1 --parent=root blackhole\n");
+}
+
+static void blackhole_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       for (;;) {
+               int c, optidx = 0;
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "h", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage();
+                       return;
+               }
+       }
+}
+
+static struct nl_cli_tc_module blackhole_module =
+{
+       .tm_name                = "blackhole",
+       .tm_type                = RTNL_TC_TYPE_QDISC,
+       .tm_parse_argv          = blackhole_parse_argv,
+};
+
+static void __init blackhole_init(void)
+{
+       nl_cli_tc_register(&blackhole_module);
+}
+
+static void __exit blackhole_exit(void)
+{
+       nl_cli_tc_unregister(&blackhole_module);
+}
diff --git a/lib/cli/qdisc/htb.c b/lib/cli/qdisc/htb.c
new file mode 100644 (file)
index 0000000..1751595
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * src/lib/htb.c       HTB module for CLI lib
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/htb.h>
+
+static void print_qdisc_usage(void)
+{
+       printf(
+"Usage: nl-qdisc-add [...] htb [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --r2q=DIV             Rate to quantum divisor (default: 10)\n"
+"     --default=ID          Default class for unclassified traffic.\n"
+"\n"
+"EXAMPLE"
+"    # Create htb root qdisc 1: and direct unclassified traffic to class 1:10\n"
+"    nl-qdisc-add --dev=eth1 --parent=root --handle=1: htb --default=10\n");
+}
+
+static void htb_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_R2Q = 257,
+                       ARG_DEFAULT = 258,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "r2q", 1, 0, ARG_R2Q },
+                       { "default", 1, 0, ARG_DEFAULT },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "hv", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_qdisc_usage();
+                       return;
+
+               case ARG_R2Q:
+                       rtnl_htb_set_rate2quantum(qdisc, nl_cli_parse_u32(optarg));
+                       break;
+
+               case ARG_DEFAULT:
+                       rtnl_htb_set_defcls(qdisc, nl_cli_parse_u32(optarg));
+                       break;
+               }
+       }
+}
+
+static void print_class_usage(void)
+{
+       printf(
+"Usage: nl-class-add [...] htb [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --rate=RATE           Rate limit.\n"
+"     --ceil=RATE           Rate limit while borrowing (default: equal to --rate).\n"
+"     --prio=PRIO           Priority, lower is served first (default: 0).\n"
+"     --quantum=SIZE        Amount of bytes to serve at once (default: rate/r2q).\n"
+"     --burst=SIZE          Max charge size of rate burst buffer (default: auto).\n"
+"     --cburst=SIZE         Max charge size of ceil rate burst buffer (default: auto)\n"
+"\n"
+"EXAMPLE"
+"    # Attach class 1:1 to htb qdisc 1: and rate limit it to 20mbit\n"
+"    nl-class-add --dev=eth1 --parent=1: --classid=1:1 htb --rate=20mbit\n");
+}
+
+static void htb_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       struct rtnl_class *class = (struct rtnl_class *) tc;
+       long rate;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_RATE = 257,
+                       ARG_QUANTUM = 258,
+                       ARG_CEIL,
+                       ARG_PRIO,
+                       ARG_BURST,
+                       ARG_CBURST,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "rate", 1, 0, ARG_RATE },
+                       { "quantum", 1, 0, ARG_QUANTUM },
+                       { "ceil", 1, 0, ARG_CEIL },
+                       { "prio", 1, 0, ARG_PRIO },
+                       { "burst", 1, 0, ARG_BURST },
+                       { "cburst", 1, 0, ARG_CBURST },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "h", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_class_usage();
+                       return;
+
+               case ARG_RATE:
+                       rate = nl_size2int(optarg);
+                       if (rate < 0) {
+                               nl_cli_fatal(rate, "Unable to parse htb rate "
+                                       "\"%s\": Invalid format.", optarg);
+                       }
+
+                       rtnl_htb_set_rate(class, rate);
+                       break;
+
+               case ARG_CEIL:
+                       rate = nl_size2int(optarg);
+                       if (rate < 0) {
+                               nl_cli_fatal(rate, "Unable to parse htb ceil rate "
+                                       "\"%s\": Invalid format.", optarg);
+                       }
+
+                       rtnl_htb_set_ceil(class, rate);
+                       break;
+
+               case ARG_PRIO:
+                       rtnl_htb_set_prio(class, nl_cli_parse_u32(optarg));
+                       break;
+
+               case ARG_QUANTUM:
+                       rate = nl_size2int(optarg);
+                       if (rate < 0) {
+                               nl_cli_fatal(rate, "Unable to parse quantum "
+                                       "\"%s\": Invalid format.", optarg);
+                       }
+
+                       rtnl_htb_set_quantum(class, rate);
+                       break;
+
+               case ARG_BURST:
+                       rate = nl_size2int(optarg);
+                       if (rate < 0) {
+                               nl_cli_fatal(rate, "Unable to parse burst "
+                                       "\"%s\": Invalid format.", optarg);
+                       }
+
+                       rtnl_htb_set_rbuffer(class, rate);
+                       break;
+
+               case ARG_CBURST:
+                       rate = nl_size2int(optarg);
+                       if (rate < 0) {
+                               nl_cli_fatal(rate, "Unable to parse cburst "
+                                       "\"%s\": Invalid format.", optarg);
+                       }
+
+                       rtnl_htb_set_cbuffer(class, rate);
+                       break;
+               }
+       }
+}
+
+static struct nl_cli_tc_module htb_qdisc_module =
+{
+       .tm_name                = "htb",
+       .tm_type                = RTNL_TC_TYPE_QDISC,
+       .tm_parse_argv          = htb_parse_qdisc_argv,
+};
+
+static struct nl_cli_tc_module htb_class_module =
+{
+       .tm_name                = "htb",
+       .tm_type                = RTNL_TC_TYPE_CLASS,
+       .tm_parse_argv          = htb_parse_class_argv,
+};
+
+static void __init htb_init(void)
+{
+       nl_cli_tc_register(&htb_qdisc_module);
+       nl_cli_tc_register(&htb_class_module);
+}
+
+static void __exit htb_exit(void)
+{
+       nl_cli_tc_unregister(&htb_class_module);
+       nl_cli_tc_unregister(&htb_qdisc_module);
+}
diff --git a/lib/cli/qdisc/pfifo.c b/lib/cli/qdisc/pfifo.c
new file mode 100644 (file)
index 0000000..02c4d22
--- /dev/null
@@ -0,0 +1,77 @@
+
+/*
+ * src/lib/pfifo.c             pfifo module for CLI lib
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/fifo.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-qdisc-add [...] pfifo [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --limit=LIMIT         Maximum queue length in number of packets.\n"
+"\n"
+"EXAMPLE"
+"    # Attach pfifo with a 32 packet limit to eth1\n"
+"    nl-qdisc-add --dev=eth1 --parent=root pfifo --limit=32\n");
+}
+
+static void pfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_LIMIT = 257,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "limit", 1, 0, ARG_LIMIT },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "h", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage();
+                       return;
+
+               case ARG_LIMIT:
+                       rtnl_qdisc_fifo_set_limit(qdisc, nl_cli_parse_u32(optarg));
+                       break;
+               }
+       }
+}
+
+static struct nl_cli_tc_module pfifo_module =
+{
+       .tm_name                = "pfifo",
+       .tm_type                = RTNL_TC_TYPE_QDISC,
+       .tm_parse_argv          = pfifo_parse_argv,
+};
+
+static void __init pfifo_init(void)
+{
+       nl_cli_tc_register(&pfifo_module);
+}
+
+static void __exit pfifo_exit(void)
+{
+       nl_cli_tc_unregister(&pfifo_module);
+}
diff --git a/lib/cli/qdisc/plug.c b/lib/cli/qdisc/plug.c
new file mode 100644 (file)
index 0000000..2b8d5d6
--- /dev/null
@@ -0,0 +1,113 @@
+
+/*
+ * src/lib/cli/qdisc/plug.c            plug module for CLI lib
+ *
+ *     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) 2012 Shriram Rajagopalan <rshriram@cs.ubc.ca>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/plug.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-qdisc-add [...] plug [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+"     --help                Show this help text.\n"
+"     --limit               Maximum queue length in bytes.\n"
+"     --buffer              create a new buffer(plug) and queue incoming traffic into it.\n"
+"     --release-one         release traffic from previous buffer.\n"
+"     --release-indefinite  stop buffering and release all (buffered and new) packets.\n"
+"\n"
+"EXAMPLE"
+"    # Attach plug qdisc with 32KB queue size to ifb0\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root plug --limit=32768\n"
+"    # Plug network traffic arriving at ifb0\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer\n"
+"    # Unplug traffic arriving at ifb0 indefinitely\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root --update plug --release-indefinite\n\n"
+"    # If operating in output buffering mode:\n"
+"    # at time t=t0, create a new output buffer b0 to hold network output\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer\n\n"
+"    # at time t=t1, take a checkpoint c0, create a new output buffer b1\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer\n"
+"    # at time t=t1+r, after c0 is committed, release b0\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root --update plug --release-one\n\n"
+"    # at time t=t2, take a checkpoint c1, create a new output buffer b2\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root --update plug --buffer\n"
+"    # at time t=t2+r, after c1 is committed, release b1\n"
+"    nl-qdisc-add --dev=ifb0 --parent=root --update plug --release-one\n");
+}
+
+static void plug_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+       struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_LIMIT              = 257,
+                       ARG_BUFFER             = 258,
+                       ARG_RELEASE_ONE        = 259,
+                       ARG_RELEASE_INDEFINITE = 260,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "limit", 1, 0, ARG_LIMIT },
+                       { "buffer", 0, 0, ARG_BUFFER },
+                       { "release-one", 0, 0, ARG_RELEASE_ONE },
+                       { "release-indefinite", 0, 0, ARG_RELEASE_INDEFINITE },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "h", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage();
+                       return;
+
+               case ARG_LIMIT:
+                       rtnl_qdisc_plug_set_limit(qdisc, nl_cli_parse_u32(optarg));
+                       break;
+
+               case ARG_BUFFER:
+                       rtnl_qdisc_plug_buffer(qdisc);
+                       break;
+
+               case ARG_RELEASE_ONE:
+                       rtnl_qdisc_plug_release_one(qdisc);
+                       break;
+
+               case ARG_RELEASE_INDEFINITE:
+                       rtnl_qdisc_plug_release_indefinite(qdisc);
+                       break;
+               }
+       }
+}
+
+static struct nl_cli_tc_module plug_module =
+{
+       .tm_name                = "plug",
+       .tm_type                = RTNL_TC_TYPE_QDISC,
+       .tm_parse_argv          = plug_parse_argv,
+};
+
+static void __init plug_init(void)
+{
+       nl_cli_tc_register(&plug_module);
+}
+
+static void __exit plug_exit(void)
+{
+       nl_cli_tc_unregister(&plug_module);
+}
diff --git a/lib/data.c b/lib/data.c
new file mode 100644 (file)
index 0000000..1a3a3fb
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * lib/data.c          Abstract Data
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core_types
+ * @defgroup data Abstract Data
+ *
+ * Abstract data type representing a binary data blob.
+ *
+ * Related sections in the development guide:
+ * - @core_doc{_abstract_data, Abstract Data}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/data.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <linux/socket.h>
+
+/**
+ * @name General
+ * @{
+ */
+
+/**
+ * Allocate a new abstract data object.
+ * @arg buf            Data buffer containing the actual data.
+ * @arg size           Size of data buffer.
+ *
+ * Allocates a new abstract data and copies the specified data
+ * buffer into the new handle.
+ * 
+ * @return Newly allocated data handle or NULL
+ */
+struct nl_data *nl_data_alloc(void *buf, size_t size)
+{
+       struct nl_data *data;
+
+       data = calloc(1, sizeof(*data));
+       if (!data)
+               goto errout;
+
+       data->d_data = calloc(1, size);
+       if (!data->d_data) {
+               free(data);
+               goto errout;
+       }
+
+       data->d_size = size;
+
+       if (buf)
+               memcpy(data->d_data, buf, size);
+
+       return data;
+errout:
+       return NULL;
+}
+
+/**
+ * Allocate abstract data object based on netlink attribute.
+ * @arg nla            Netlink attribute of unspecific type.
+ *
+ * Allocates a new abstract data and copies the payload of the
+ * attribute to the abstract data object.
+ * 
+ * @see nla_data_alloc
+ * @return Newly allocated data handle or NULL
+ */
+struct nl_data *nl_data_alloc_attr(struct nlattr *nla)
+{
+       return nl_data_alloc(nla_data(nla), nla_len(nla));
+}
+
+/**
+ * Clone an abstract data object.
+ * @arg src            Abstract data object
+ *
+ * @return Cloned object or NULL
+ */
+struct nl_data *nl_data_clone(struct nl_data *src)
+{
+       return nl_data_alloc(src->d_data, src->d_size);
+}
+
+/**
+ * Append data to an abstract data object.
+ * @arg data           Abstract data object.
+ * @arg buf            Data buffer containing the data to be appended.
+ * @arg size           Size of data to be apppended.
+ *
+ * Reallocates an abstract data and copies the specified data
+ * buffer into the new handle.
+ * 
+ * @return 0 on success or a negative error code
+ */
+int nl_data_append(struct nl_data *data, void *buf, size_t size)
+{
+       if (size > 0) {
+               data->d_data = realloc(data->d_data, data->d_size + size);
+               if (!data->d_data)
+                       return -NLE_NOMEM;
+
+               if (buf)
+                       memcpy(data->d_data + data->d_size, buf, size);
+               else
+                       memset(data->d_data + data->d_size, 0, size);
+
+               data->d_size += size;
+       }
+
+       return 0;
+}
+
+/**
+ * Free an abstract data object.
+ * @arg data           Abstract data object.
+ */
+void nl_data_free(struct nl_data *data)
+{
+       if (data)
+               free(data->d_data);
+
+       free(data);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Get data buffer of abstract data object.
+ * @arg data           Abstract data object.
+ * @return Data buffer or NULL if empty.
+ */
+void *nl_data_get(struct nl_data *data)
+{
+       return data->d_size > 0 ? data->d_data : NULL;
+}
+
+/**
+ * Get size of data buffer of abstract data object.
+ * @arg data           Abstract data object.
+ * @return Size of data buffer.
+ */
+size_t nl_data_get_size(struct nl_data *data)
+{
+       return data->d_size;
+}
+
+/** @} */
+
+/**
+ * @name Misc
+ * @{
+ */
+
+/**
+ * Compare two abstract data objects.
+ * @arg a              Abstract data object.
+ * @arg b              Another abstract data object.
+ * @return An integer less than, equal to, or greater than zero if
+ *         a is found, respectively, to be less than, to match, or
+ *         be greater than b.
+ */
+int nl_data_cmp(struct nl_data *a, struct nl_data *b)
+{
+       void *a_ = nl_data_get(a);
+       void *b_ = nl_data_get(b);
+
+       if (a_ && b_)
+               return memcmp(a_, b_, nl_data_get_size(a));
+       else
+               return -1;
+}
+
+/** @} */
+/** @} */
diff --git a/lib/defs.h.in b/lib/defs.h.in
new file mode 100644 (file)
index 0000000..62785cb
--- /dev/null
@@ -0,0 +1,86 @@
+/* lib/defs.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 to disable pthreads */
+#undef DISABLE_PTHREADS
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 to enable debugging */
+#undef NL_DEBUG
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
diff --git a/lib/error.c b/lib/error.c
new file mode 100644 (file)
index 0000000..f30b9a5
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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-private/netlink.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",
+[NLE_PKTLOC_FILE]      = "Unable to open packet location file",
+[NLE_PARSE_ERR]                = "Unable to parse object",
+[NLE_NODEV]            = "No such device",
+[NLE_IMMUTABLE]                = "Immutable attribute",
+[NLE_DUMP_INTR]                = "Dump inconsistency detected, interrupted",
+};
+
+/**
+ * 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 EEXIST:            return NLE_EXIST;
+       case EADDRNOTAVAIL:     return NLE_NOADDR;
+       case ESRCH:             /* fall through */
+       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;
+       case EBUSY:             return NLE_BUSY;
+       case ERANGE:            return NLE_RANGE;
+       case ENODEV:            return NLE_NODEV;
+       default:                return NLE_FAILURE;
+       }
+}
+
+/** @} */
+
diff --git a/lib/fib_lookup/lookup.c b/lib/fib_lookup/lookup.c
new file mode 100644 (file)
index 0000000..3d07317
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * lib/fib_lookup/lookup.c     FIB Lookup
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup fib_lookup FIB Lookup
+ * @brief
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/fib_lookup/request.h>
+#include <netlink/fib_lookup/lookup.h>
+
+/** @cond SKIP */
+static struct nl_cache_ops fib_lookup_ops;
+static struct nl_object_ops result_obj_ops;
+
+/* not exported so far */
+struct fib_result_nl {
+       uint32_t        fl_addr;   /* To be looked up*/ 
+       uint32_t        fl_fwmark; 
+       unsigned char   fl_tos;
+       unsigned char   fl_scope;
+       unsigned char   tb_id_in;
+
+       unsigned char   tb_id;      /* Results */
+       unsigned char   prefixlen;
+       unsigned char   nh_sel;
+       unsigned char   type;
+       unsigned char   scope;
+       int             err;      
+};
+/** @endcond */
+
+static void result_free_data(struct nl_object *obj)
+{
+       struct flnl_result *res = nl_object_priv(obj);
+
+       if (res && res->fr_req)
+               nl_object_put(OBJ_CAST(res->fr_req));
+}
+
+static int result_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct flnl_result *dst = nl_object_priv(_dst);
+       struct flnl_result *src = nl_object_priv(_src);
+
+       if (src->fr_req)
+               if (!(dst->fr_req = (struct flnl_request *)
+                               nl_object_clone(OBJ_CAST(src->fr_req))))
+                       return -NLE_NOMEM;
+       
+       return 0;
+}
+
+static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                            struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+       struct flnl_result *res;
+       struct fib_result_nl *fr;
+       struct nl_addr *addr;
+       int err = -NLE_INVAL;
+
+       res = flnl_result_alloc();
+       if (!res)
+               goto errout;
+
+       res->ce_msgtype = n->nlmsg_type;
+
+       res->fr_req = flnl_request_alloc();
+       if (!res->fr_req)
+               goto errout;
+
+       fr = nlmsg_data(n);
+       addr = nl_addr_build(AF_INET, &fr->fl_addr, 4);
+       if (!addr)
+               goto errout;
+       err = flnl_request_set_addr(res->fr_req, addr);
+       nl_addr_put(addr);
+       if (err < 0)
+               goto errout;
+
+       flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark);
+       flnl_request_set_tos(res->fr_req, fr->fl_tos);
+       flnl_request_set_scope(res->fr_req, fr->fl_scope);
+       flnl_request_set_table(res->fr_req, fr->tb_id_in);
+
+       res->fr_table_id = fr->tb_id;
+       res->fr_prefixlen = fr->prefixlen;
+       res->fr_nh_sel = fr->nh_sel;
+       res->fr_type = fr->type;
+       res->fr_scope = fr->scope;
+       res->fr_error = fr->err;
+
+       err = pp->pp_cb((struct nl_object *) res, pp);
+       if (err < 0)
+               goto errout;
+
+       /* REAL HACK, fib_lookup doesn't support ACK nor does it
+        * send a DONE message, enforce end of message stream
+        * after just the first message */
+       err = NL_STOP;
+
+errout:
+       flnl_result_put(res);
+       return err;
+}
+
+static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct flnl_result *res = (struct flnl_result *) obj;
+       char buf[256];
+
+       nl_dump_line(p, "table %s prefixlen %u next-hop-selector %u\n",
+               rtnl_route_table2str(res->fr_table_id, buf, sizeof(buf)),
+               res->fr_prefixlen, res->fr_nh_sel);
+       nl_dump_line(p, "type %s ",
+                    nl_rtntype2str(res->fr_type, buf, sizeof(buf)));
+       nl_dump(p, "scope %s error %s (%d)\n",
+               rtnl_scope2str(res->fr_scope, buf, sizeof(buf)),
+               strerror_r(-res->fr_error, buf, sizeof(buf)), res->fr_error);
+}
+
+static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+       result_dump_line(obj, p);
+}
+
+static int result_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       return 0;
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct flnl_result *flnl_result_alloc(void)
+{
+       return (struct flnl_result *) nl_object_alloc(&result_obj_ops);
+}
+
+void flnl_result_put(struct flnl_result *res)
+{
+       nl_object_put((struct nl_object *) res);
+}
+
+/** @} */
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Allocate lookup result cache.
+ *
+ * Allocates a new lookup result cache and initializes it properly.
+ *
+ * @note Free the memory after usage using nl_cache_destroy_and_free().
+ * @return Newly allocated cache or NULL if an error occured.
+ */
+struct nl_cache *flnl_result_alloc_cache(void)
+{
+       return nl_cache_alloc(&fib_lookup_ops);
+}
+
+/** @} */
+
+/**
+ * @name Lookup
+ * @{
+ */
+
+/**
+ * Builds a netlink request message to do a lookup
+ * @arg req            Requested match.
+ * @arg flags          additional netlink message flags
+ * @arg result         Result pointer
+ *
+ * Builds a new netlink message requesting a change of link 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.
+ * \a old must point to a link currently configured in the kernel
+ * and \a tmpl must contain the attributes to be changed set via
+ * \c rtnl_link_set_* functions.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int flnl_lookup_build_request(struct flnl_request *req, int flags,
+                             struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct nl_addr *addr;
+       uint64_t fwmark;
+       int tos, scope, table;
+       struct fib_result_nl fr = {0};
+
+       fwmark = flnl_request_get_fwmark(req);
+       tos = flnl_request_get_tos(req);
+       scope = flnl_request_get_scope(req);
+       table = flnl_request_get_table(req);
+
+       fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0;
+       fr.fl_tos = tos >= 0 ? tos : 0;
+       fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE;
+       fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC;
+
+       addr = flnl_request_get_addr(req);
+       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)
+               return -NLE_NOMEM;
+
+       if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0)
+               goto errout;
+
+       *result = msg;
+       return 0;
+
+errout:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * Perform FIB Lookup
+ * @arg sk             Netlink socket.
+ * @arg req            Lookup request object.
+ * @arg cache          Cache for result.
+ *
+ * Builds a netlink message to request a FIB lookup, waits for the
+ * reply and adds the result to the specified cache.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int flnl_lookup(struct nl_sock *sk, struct flnl_request *req,
+               struct nl_cache *cache)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = flnl_lookup_build_request(req, 0, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return nl_cache_pickup(sk, cache);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+int flnl_result_get_table_id(struct flnl_result *res)
+{
+       return res->fr_table_id;
+}
+
+int flnl_result_get_prefixlen(struct flnl_result *res)
+{
+       return res->fr_prefixlen;
+}
+
+int flnl_result_get_nexthop_sel(struct flnl_result *res)
+{
+       return res->fr_nh_sel;
+}
+
+int flnl_result_get_type(struct flnl_result *res)
+{
+       return res->fr_type;
+}
+
+int flnl_result_get_scope(struct flnl_result *res)
+{
+       return res->fr_scope;
+}
+
+int flnl_result_get_error(struct flnl_result *res)
+{
+       return res->fr_error;
+}
+
+/** @} */
+
+static struct nl_object_ops result_obj_ops = {
+       .oo_name                = "fib_lookup/result",
+       .oo_size                = sizeof(struct flnl_result),
+       .oo_free_data           = result_free_data,
+       .oo_clone               = result_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = result_dump_line,
+           [NL_DUMP_DETAILS]   = result_dump_details,
+       },
+       .oo_compare             = result_compare,
+};
+
+static struct nl_cache_ops fib_lookup_ops = {
+       .co_name                = "fib_lookup/fib_lookup",
+       .co_hdrsize             = sizeof(struct fib_result_nl),
+       .co_msgtypes            = {
+                                       { 0, NL_ACT_UNSPEC, "any" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_FIB_LOOKUP,
+       .co_msg_parser          = result_msg_parser,
+       .co_obj_ops             = &result_obj_ops,
+};
+
+static void __init fib_lookup_init(void)
+{
+       nl_cache_mngt_register(&fib_lookup_ops);
+}
+
+static void __exit fib_lookup_exit(void)
+{
+       nl_cache_mngt_unregister(&fib_lookup_ops);
+}
+
+/** @} */
diff --git a/lib/fib_lookup/request.c b/lib/fib_lookup/request.c
new file mode 100644 (file)
index 0000000..1b021b6
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * lib/fib_lookup/request.c    FIB Lookup Request
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup fib_lookup
+ * @defgroup flreq Request
+ * @brief
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/fib_lookup/request.h>
+
+static struct nl_object_ops request_obj_ops;
+
+/** @cond SKIP */
+#define REQUEST_ATTR_ADDR      0x01
+#define REQUEST_ATTR_FWMARK    0x02
+#define REQUEST_ATTR_TOS       0x04
+#define REQUEST_ATTR_SCOPE     0x08
+#define REQUEST_ATTR_TABLE     0x10
+/** @endcond */
+
+static void request_free_data(struct nl_object *obj)
+{
+       struct flnl_request *req = REQUEST_CAST(obj);
+
+       if (req)
+               nl_addr_put(req->lr_addr);
+}
+
+static int request_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct flnl_request *dst = nl_object_priv(_dst);
+       struct flnl_request *src = nl_object_priv(_src);
+
+       if (src->lr_addr)
+               if (!(dst->lr_addr = nl_addr_clone(src->lr_addr)))
+                       return -NLE_NOMEM;
+
+       return 0;
+}
+
+static int request_compare(struct nl_object *_a, struct nl_object *_b,
+                          uint32_t attrs, int flags)
+{
+       struct flnl_request *a = (struct flnl_request *) _a;
+       struct flnl_request *b = (struct flnl_request *) _b;
+       int diff = 0;
+
+#define REQ_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, REQUEST_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= REQ_DIFF(FWMARK,        a->lr_fwmark != b->lr_fwmark);
+       diff |= REQ_DIFF(TOS,           a->lr_tos != b->lr_tos);
+       diff |= REQ_DIFF(SCOPE,         a->lr_scope != b->lr_scope);
+       diff |= REQ_DIFF(TABLE,         a->lr_table != b->lr_table);
+       diff |= REQ_DIFF(ADDR,          nl_addr_cmp(a->lr_addr, b->lr_addr));
+
+#undef REQ_DIFF
+
+       return diff;
+}
+
+
+/**
+ * @name Lookup Request Creation/Deletion
+ * @{
+ */
+
+struct flnl_request *flnl_request_alloc(void)
+{
+       return REQUEST_CAST(nl_object_alloc(&request_obj_ops));
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void flnl_request_set_fwmark(struct flnl_request *req, uint64_t fwmark)
+{
+       req->lr_fwmark = fwmark;
+       req->ce_mask |= REQUEST_ATTR_FWMARK;
+}
+
+uint64_t flnl_request_get_fwmark(struct flnl_request *req)
+{
+       if (req->ce_mask & REQUEST_ATTR_FWMARK)
+               return req->lr_fwmark;
+       else
+               return UINT_LEAST64_MAX;
+}
+
+void flnl_request_set_tos(struct flnl_request *req, int tos)
+{
+       req->lr_tos = tos;
+       req->ce_mask |= REQUEST_ATTR_TOS;
+}
+
+int flnl_request_get_tos(struct flnl_request *req)
+{
+       if (req->ce_mask & REQUEST_ATTR_TOS)
+               return req->lr_tos;
+       else
+               return -1;
+}
+
+void flnl_request_set_scope(struct flnl_request *req, int scope)
+{
+       req->lr_scope = scope;
+       req->ce_mask |= REQUEST_ATTR_SCOPE;
+}
+
+int flnl_request_get_scope(struct flnl_request *req)
+{
+       if (req->ce_mask & REQUEST_ATTR_SCOPE)
+               return req->lr_scope;
+       else
+               return -1;
+}
+
+void flnl_request_set_table(struct flnl_request *req, int table)
+{
+       req->lr_table = table;
+       req->ce_mask |= REQUEST_ATTR_TABLE;
+}
+
+int flnl_request_get_table(struct flnl_request *req)
+{
+       if (req->ce_mask & REQUEST_ATTR_TABLE)
+               return req->lr_table;
+       else
+               return -1;
+}
+
+int flnl_request_set_addr(struct flnl_request *req, struct nl_addr *addr)
+{
+       if (addr->a_family != AF_INET)
+               return -NLE_AF_NOSUPPORT;
+
+       if (req->lr_addr)
+               nl_addr_put(req->lr_addr);
+
+       nl_addr_get(addr);
+       req->lr_addr = addr;
+
+       req->ce_mask |= REQUEST_ATTR_ADDR;
+
+       return 0;
+}
+
+struct nl_addr *flnl_request_get_addr(struct flnl_request *req)
+{
+       if (req->ce_mask & REQUEST_ATTR_ADDR)
+               return req->lr_addr;
+       else
+               return NULL;
+}
+
+/** @} */
+
+static struct nl_object_ops request_obj_ops = {
+       .oo_name                = "fib_lookup/request",
+       .oo_size                = sizeof(struct flnl_request),
+       .oo_free_data           = request_free_data,
+       .oo_clone               = request_clone,
+       .oo_compare             = request_compare,
+       .oo_id_attrs            = ~0,
+};
+
+/** @} */
diff --git a/lib/genl/ctrl.c b/lib/genl/ctrl.c
new file mode 100644 (file)
index 0000000..ce07f1d
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+ * lib/genl/ctrl.c             Generic Netlink Controller
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup genl
+ * @defgroup genl_ctrl Controller (Resolver)
+ *
+ * Resolves Generic Netlink family names to numeric identifiers.
+ *
+ * The controller is a component in the kernel that resolves Generic Netlink
+ * family names to their numeric identifiers. This module provides functions
+ * to query the controller to access the resolving functionality.
+ * @{
+ */
+
+#include <netlink-private/genl.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define CTRL_VERSION           0x0001
+
+static struct nl_cache_ops genl_ctrl_ops;
+
+static int ctrl_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+       return genl_send_simple(h, GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
+                               CTRL_VERSION, NLM_F_DUMP);
+}
+
+static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
+       [CTRL_ATTR_FAMILY_ID]   = { .type = NLA_U16 },
+       [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING,
+                                   .maxlen = GENL_NAMSIZ },
+       [CTRL_ATTR_VERSION]     = { .type = NLA_U32 },
+       [CTRL_ATTR_HDRSIZE]     = { .type = NLA_U32 },
+       [CTRL_ATTR_MAXATTR]     = { .type = NLA_U32 },
+       [CTRL_ATTR_OPS]         = { .type = NLA_NESTED },
+       [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy family_op_policy[CTRL_ATTR_OP_MAX+1] = {
+       [CTRL_ATTR_OP_ID]       = { .type = NLA_U32 },
+       [CTRL_ATTR_OP_FLAGS]    = { .type = NLA_U32 },
+};
+
+static struct nla_policy family_grp_policy[CTRL_ATTR_MCAST_GRP_MAX+1] = {
+       [CTRL_ATTR_MCAST_GRP_NAME] = { .type = NLA_STRING },
+       [CTRL_ATTR_MCAST_GRP_ID]   = { .type = NLA_U32 },
+};
+
+static int parse_mcast_grps(struct genl_family *family, struct nlattr *grp_attr)
+{
+       struct nlattr *nla;
+       int remaining, err;
+
+       if (!grp_attr)
+               BUG();
+
+       nla_for_each_nested(nla, grp_attr, remaining) {
+               struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1];
+               int id;
+               const char * name;
+
+               err = nla_parse_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, nla,
+                                      family_grp_policy);
+               if (err < 0)
+                       goto errout;
+
+               if (tb[CTRL_ATTR_MCAST_GRP_ID] == NULL) {
+                       err = -NLE_MISSING_ATTR;
+                       goto errout;
+               }
+               id = nla_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
+
+               if (tb[CTRL_ATTR_MCAST_GRP_NAME] == NULL) {
+                       err = -NLE_MISSING_ATTR;
+                       goto errout;
+               }
+               name = nla_get_string(tb[CTRL_ATTR_MCAST_GRP_NAME]);
+
+               err = genl_family_add_grp(family, id, name);
+               if (err < 0)
+                       goto errout;
+       }
+
+       err = 0;
+
+errout:
+       return err;
+}
+
+static int ctrl_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
+                          struct genl_info *info, void *arg)
+{
+       struct genl_family *family;
+       struct nl_parser_param *pp = arg;
+       int err;
+
+       family = genl_family_alloc();
+       if (family == NULL) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       if (info->attrs[CTRL_ATTR_FAMILY_NAME] == NULL) {
+               err = -NLE_MISSING_ATTR;
+               goto errout;
+       }
+
+       if (info->attrs[CTRL_ATTR_FAMILY_ID] == NULL) {
+               err = -NLE_MISSING_ATTR;
+               goto errout;
+       }
+
+       family->ce_msgtype = info->nlh->nlmsg_type;
+       genl_family_set_id(family,
+                          nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]));
+       genl_family_set_name(family,
+                    nla_get_string(info->attrs[CTRL_ATTR_FAMILY_NAME]));
+
+       if (info->attrs[CTRL_ATTR_VERSION]) {
+               uint32_t version = nla_get_u32(info->attrs[CTRL_ATTR_VERSION]);
+               genl_family_set_version(family, version);
+       }
+
+       if (info->attrs[CTRL_ATTR_HDRSIZE]) {
+               uint32_t hdrsize = nla_get_u32(info->attrs[CTRL_ATTR_HDRSIZE]);
+               genl_family_set_hdrsize(family, hdrsize);
+       }
+
+       if (info->attrs[CTRL_ATTR_MAXATTR]) {
+               uint32_t maxattr = nla_get_u32(info->attrs[CTRL_ATTR_MAXATTR]);
+               genl_family_set_maxattr(family, maxattr);
+       }
+
+       if (info->attrs[CTRL_ATTR_OPS]) {
+               struct nlattr *nla, *nla_ops;
+               int remaining;
+
+               nla_ops = info->attrs[CTRL_ATTR_OPS];
+               nla_for_each_nested(nla, nla_ops, remaining) {
+                       struct nlattr *tb[CTRL_ATTR_OP_MAX+1];
+                       int flags = 0, id;
+
+                       err = nla_parse_nested(tb, CTRL_ATTR_OP_MAX, nla,
+                                              family_op_policy);
+                       if (err < 0)
+                               goto errout;
+
+                       if (tb[CTRL_ATTR_OP_ID] == NULL) {
+                               err = -NLE_MISSING_ATTR;
+                               goto errout;
+                       }
+                       
+                       id = nla_get_u32(tb[CTRL_ATTR_OP_ID]);
+
+                       if (tb[CTRL_ATTR_OP_FLAGS])
+                               flags = nla_get_u32(tb[CTRL_ATTR_OP_FLAGS]);
+
+                       err = genl_family_add_op(family, id, flags);
+                       if (err < 0)
+                               goto errout;
+
+               }
+       }
+       
+       if (info->attrs[CTRL_ATTR_MCAST_GROUPS]) {
+               err = parse_mcast_grps(family, info->attrs[CTRL_ATTR_MCAST_GROUPS]);
+               if (err < 0)
+                       goto errout;
+       }
+
+       err = pp->pp_cb((struct nl_object *) family, pp);
+errout:
+       genl_family_put(family);
+       return err;
+}
+
+/**
+ * process responses from from the query sent by genl_ctrl_probe_by_name 
+ * @arg nl_msg         Returned message.
+ * @arg name           genl_family structure to fill out.
+ *
+ * Process returned messages, filling out the missing informatino in the
+ * genl_family structure
+ *
+ * @return Indicator to keep processing frames or not
+ *
+ */
+static int probe_response(struct nl_msg *msg, void *arg)
+{
+       struct nlattr *tb[CTRL_ATTR_MAX+1];
+       struct nlmsghdr *nlh = nlmsg_hdr(msg);
+       struct genl_family *ret = (struct genl_family *)arg;
+
+       if (genlmsg_parse(nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy))
+               return NL_SKIP;
+
+       if (tb[CTRL_ATTR_FAMILY_ID])
+               genl_family_set_id(ret, nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]));
+
+       if (tb[CTRL_ATTR_MCAST_GROUPS])
+               if (parse_mcast_grps(ret, tb[CTRL_ATTR_MCAST_GROUPS]) < 0)
+                       return NL_SKIP;
+
+       return NL_STOP;
+}
+
+/**
+ * Look up generic netlink family by family name querying the kernel directly
+ * @arg sk             Socket.
+ * @arg name           Family name.
+ *
+ * Directly query's the kernel for a given family name.  The caller will own a
+ * reference on the returned object which needsd to be given back after usage
+ * using genl_family_put.
+ *
+ * Note: This API call differs from genl_ctrl_search_by_name in that it querys
+ * the kernel directly, alowing for module autoload to take place to resolve the
+ * family request. Using an nl_cache prevents that operation
+ *
+ * @return Generic netlink family object or NULL if no match was found.
+ */
+static struct genl_family *genl_ctrl_probe_by_name(struct nl_sock *sk,
+                                                  const char *name)
+{
+       struct nl_msg *msg;
+       struct genl_family *ret;
+       struct nl_cb *cb, *orig;
+       int rc;
+
+       ret = genl_family_alloc();
+       if (!ret)
+               goto out;
+
+       genl_family_set_name(ret, name);
+
+       msg = nlmsg_alloc();
+       if (!msg)
+               goto out_fam_free;
+
+       if (!(orig = nl_socket_get_cb(sk)))
+               goto out_msg_free;
+
+       cb = nl_cb_clone(orig);
+       nl_cb_put(orig);
+       if (!cb)
+               goto out_msg_free;
+
+       if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
+                       0, 0, CTRL_CMD_GETFAMILY, 1)) {
+               BUG();
+               goto out_cb_free;
+       }
+
+       if (nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
+               goto out_cb_free;
+
+       rc = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response,
+                      (void *) ret);
+       if (rc < 0)
+               goto out_cb_free;
+
+       rc = nl_send_auto_complete(sk, msg);
+       if (rc < 0)
+               goto out_cb_free;
+
+       rc = nl_recvmsgs(sk, cb);
+       if (rc < 0)
+               goto out_cb_free;
+
+       /* If search was successful, request may be ACKed after data */
+       rc = wait_for_ack(sk);
+       if (rc < 0)
+               goto out_cb_free;
+
+       if (genl_family_get_id(ret) != 0) {
+               nlmsg_free(msg);
+               nl_cb_put(cb);
+               return ret;
+       }
+
+out_cb_free:
+       nl_cb_put(cb);
+out_msg_free:
+       nlmsg_free(msg);
+out_fam_free:
+       genl_family_put(ret);
+       ret = NULL;
+out:
+       return ret;
+}
+
+
+/** @endcond */
+
+/**
+ * @name Controller Cache
+ *
+ * The controller cache allows to keep a local copy of the list of all
+ * kernel side registered Generic Netlink families to quickly resolve
+ * multiple Generic Netlink family names without requiring to communicate
+ * with the kernel for each resolving iteration. 
+ *
+ * @{
+ */
+
+/**
+ * Allocate a new controller cache
+ * @arg sk             Generic Netlink socket
+ * @arg result         Pointer to store resulting cache
+ *
+ * Allocates a new cache mirroring the state of the controller and stores it
+ * in \c *result. The allocated cache will contain a list of all currently
+ * registered kernel side Generic Netlink families. The cache is meant to be
+ * used to resolve family names locally.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_ctrl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+       return nl_cache_alloc_and_fill(&genl_ctrl_ops, sk, result);
+}
+
+/**
+ * Search controller cache for a numeric address match
+ * @arg cache          Controller cache
+ * @arg id             Numeric family identifier.
+ *
+ * Searches a previously allocated controller cache and looks for an entry
+ * that matches the specified numeric family identifier \c id.  If a match
+ * is found successfully, the reference count of the matching object is
+ * increased by one before the objet is returned.
+ *
+ * @see genl_ctrl_alloc_cache()
+ * @see genl_ctrl_search_by_name()
+ * @see genl_family_put()
+ *
+ * @return Generic Netlink family object or NULL if no match was found.
+ */
+struct genl_family *genl_ctrl_search(struct nl_cache *cache, int id)
+{
+       struct genl_family *fam;
+
+       if (cache->c_ops != &genl_ctrl_ops)
+               BUG();
+
+       nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
+               if (fam->gf_id == id) {
+                       nl_object_get((struct nl_object *) fam);
+                       return fam;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Search controller cache for a family name match
+ * @arg cache          Controller cache
+ * @arg name           Name of Generic Netlink family
+ *
+ * Searches a previously allocated controller cache and looks for an entry
+ * that matches the specified family \c name. If a match is found successfully,
+ * the reference count of the matching object is increased by one before the
+ * objet is returned.
+ *
+ * @see genl_ctrl_alloc_cache()
+ * @see genl_ctrl_search()
+ * @see genl_family_put()
+ *
+ * @return Generic Netlink family object or NULL if no match was found.
+ */
+struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache,
+                                            const char *name)
+{
+       struct genl_family *fam;
+
+       if (cache->c_ops != &genl_ctrl_ops)
+               BUG();
+
+       nl_list_for_each_entry(fam, &cache->c_items, ce_list) {
+               if (!strcmp(name, fam->gf_name)) {
+                       nl_object_get((struct nl_object *) fam);
+                       return fam;
+               }
+       }
+
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Direct Resolvers
+ *
+ * These functions communicate directly with the kernel and do not require
+ * a cache to be kept up to date.
+ *
+ * @{
+ */
+
+/**
+ * Resolve Generic Netlink family name to numeric identifier
+ * @arg sk             Generic Netlink socket.
+ * @arg name           Name of Generic Netlink family
+ *
+ * Resolves the Generic Netlink family name to the corresponding numeric
+ * family identifier. This function queries the kernel directly, use
+ * genl_ctrl_search_by_name() if you need to resolve multiple names.
+ *
+ * @see genl_ctrl_search_by_name()
+ *
+ * @return The numeric family identifier or a negative error code.
+ */
+int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
+{
+       struct genl_family *family;
+       int err;
+
+       family = genl_ctrl_probe_by_name(sk, name);
+       if (family == NULL) {
+               err = -NLE_OBJ_NOTFOUND;
+               goto errout;
+       }
+
+       err = genl_family_get_id(family);
+       genl_family_put(family);
+errout:
+       return err;
+}
+
+static int genl_ctrl_grp_by_name(const struct genl_family *family,
+                                const char *grp_name)
+{
+       struct genl_family_grp *grp;
+
+       nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
+               if (!strcmp(grp->name, grp_name)) {
+                       return grp->id;
+               }
+       }
+
+       return -NLE_OBJ_NOTFOUND;
+}
+
+/**
+ * Resolve Generic Netlink family group name
+ * @arg sk             Generic Netlink socket
+ * @arg family_name    Name of Generic Netlink family
+ * @arg grp_name       Name of group to resolve
+ *
+ * Looks up the family object and resolves the group name to the numeric
+ * group identifier.
+ *
+ * @return Numeric group identifier or a negative error code.
+ */
+int genl_ctrl_resolve_grp(struct nl_sock *sk, const char *family_name,
+                         const char *grp_name)
+{
+
+       struct genl_family *family;
+       int err;
+
+       family = genl_ctrl_probe_by_name(sk, family_name);
+       if (family == NULL) {
+               err = -NLE_OBJ_NOTFOUND;
+               goto errout;
+       }
+
+       err = genl_ctrl_grp_by_name(family, grp_name);
+       genl_family_put(family);
+errout:
+       return err;
+}
+
+/** @} */
+
+/** @cond SKIP */
+static struct genl_cmd genl_cmds[] = {
+       {
+               .c_id           = CTRL_CMD_NEWFAMILY,
+               .c_name         = "NEWFAMILY" ,
+               .c_maxattr      = CTRL_ATTR_MAX,
+               .c_attr_policy  = ctrl_policy,
+               .c_msg_parser   = ctrl_msg_parser,
+       },
+       {
+               .c_id           = CTRL_CMD_DELFAMILY,
+               .c_name         = "DELFAMILY" ,
+       },
+       {
+               .c_id           = CTRL_CMD_GETFAMILY,
+               .c_name         = "GETFAMILY" ,
+       },
+       {
+               .c_id           = CTRL_CMD_NEWOPS,
+               .c_name         = "NEWOPS" ,
+       },
+       {
+               .c_id           = CTRL_CMD_DELOPS,
+               .c_name         = "DELOPS" ,
+       },
+};
+
+static struct genl_ops genl_ops = {
+       .o_cmds                 = genl_cmds,
+       .o_ncmds                = ARRAY_SIZE(genl_cmds),
+};
+
+extern struct nl_object_ops genl_family_ops;
+
+static struct nl_cache_ops genl_ctrl_ops = {
+       .co_name                = "genl/family",
+       .co_hdrsize             = GENL_HDRSIZE(0),
+       .co_msgtypes            = GENL_FAMILY(GENL_ID_CTRL, "nlctrl"),
+       .co_genl                = &genl_ops,
+       .co_protocol            = NETLINK_GENERIC,
+       .co_request_update      = ctrl_request_update,
+       .co_obj_ops             = &genl_family_ops,
+};
+
+static void __init ctrl_init(void)
+{
+       genl_register(&genl_ctrl_ops);
+}
+
+static void __exit ctrl_exit(void)
+{
+       genl_unregister(&genl_ctrl_ops);
+}
+/** @endcond */
+
+/** @} */
diff --git a/lib/genl/family.c b/lib/genl/family.c
new file mode 100644 (file)
index 0000000..897c809
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * lib/genl/family.c           Generic Netlink Family
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup genl_ctrl
+ * @defgroup genl_family Generic Netlink Family Object
+ *
+ * Object representing a kernel side registered Generic Netlink family
+ *
+ * @{
+ */
+
+#include <netlink-private/genl.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define FAMILY_ATTR_ID         0x01
+#define FAMILY_ATTR_NAME       0x02
+#define FAMILY_ATTR_VERSION    0x04
+#define FAMILY_ATTR_HDRSIZE    0x08
+#define FAMILY_ATTR_MAXATTR    0x10
+#define FAMILY_ATTR_OPS                0x20
+
+struct nl_object_ops genl_family_ops;
+
+static void family_constructor(struct nl_object *c)
+{
+       struct genl_family *family = (struct genl_family *) c;
+
+       nl_init_list_head(&family->gf_ops);
+       nl_init_list_head(&family->gf_mc_grps);
+}
+
+static void family_free_data(struct nl_object *c)
+{
+       struct genl_family *family = (struct genl_family *) c;
+       struct genl_family_op *ops, *tmp;
+       struct genl_family_grp *grp, *t_grp;
+
+       if (family == NULL)
+               return;
+
+       nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) {
+               nl_list_del(&ops->o_list);
+               free(ops);
+       }
+
+       nl_list_for_each_entry_safe(grp, t_grp, &family->gf_mc_grps, list) {
+               nl_list_del(&grp->list);
+               free(grp);
+       }
+
+}
+
+static int family_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct genl_family *dst = nl_object_priv(_dst);
+       struct genl_family *src = nl_object_priv(_src);
+       struct genl_family_op *ops;
+       struct genl_family_grp *grp;
+       int err;
+
+       nl_list_for_each_entry(ops, &src->gf_ops, o_list) {
+               err = genl_family_add_op(dst, ops->o_id, ops->o_flags);
+               if (err < 0)
+                       return err;
+       }
+
+       nl_list_for_each_entry(grp, &src->gf_mc_grps, list) {
+               err = genl_family_add_grp(dst, grp->id, grp->name);
+               if (err < 0)
+                       return err;
+       }
+
+       
+       return 0;
+}
+
+static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct genl_family *family = (struct genl_family *) obj;
+
+       nl_dump(p, "0x%04x %s version %u\n",
+               family->gf_id, family->gf_name, family->gf_version);
+}
+
+static const struct trans_tbl ops_flags[] = {
+       __ADD(GENL_ADMIN_PERM, admin_perm)
+       __ADD(GENL_CMD_CAP_DO, has_doit)
+       __ADD(GENL_CMD_CAP_DUMP, has_dump)
+       __ADD(GENL_CMD_CAP_HASPOL, has_policy)
+};
+
+static char *ops_flags2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, ops_flags, ARRAY_SIZE(ops_flags));
+}
+
+static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct genl_family_grp *grp;
+       struct genl_family *family = (struct genl_family *) obj;
+
+       family_dump_line(obj, p);
+       nl_dump_line(p, "    hdrsize %u maxattr %u\n",
+                    family->gf_hdrsize, family->gf_maxattr);
+
+       if (family->ce_mask & FAMILY_ATTR_OPS) {
+               struct genl_family_op *op;
+               char buf[64];
+
+               nl_list_for_each_entry(op, &family->gf_ops, o_list) {
+                       ops_flags2str(op->o_flags, buf, sizeof(buf));
+
+                       genl_op2name(family->gf_id, op->o_id, buf, sizeof(buf));
+
+                       nl_dump_line(p, "      op %s (0x%02x)", buf, op->o_id);
+
+                       if (op->o_flags)
+                               nl_dump(p, " <%s>",
+                                       ops_flags2str(op->o_flags, buf,
+                                                     sizeof(buf)));
+
+                       nl_dump(p, "\n");
+               }
+       }
+
+       nl_list_for_each_entry(grp, &family->gf_mc_grps, list) {
+               nl_dump_line(p, "      grp %s (0x%02x)\n", grp->name, grp->id);
+       }
+
+}
+
+static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+       family_dump_details(obj, p);
+}
+
+static int family_compare(struct nl_object *_a, struct nl_object *_b,
+                         uint32_t attrs, int flags)
+{
+       struct genl_family *a = (struct genl_family *) _a;
+       struct genl_family *b = (struct genl_family *) _b;
+       int diff = 0;
+
+#define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= FAM_DIFF(ID,            a->gf_id != b->gf_id);
+       diff |= FAM_DIFF(VERSION,       a->gf_version != b->gf_version);
+       diff |= FAM_DIFF(HDRSIZE,       a->gf_hdrsize != b->gf_hdrsize);
+       diff |= FAM_DIFF(MAXATTR,       a->gf_maxattr != b->gf_maxattr);
+       diff |= FAM_DIFF(NAME,          strcmp(a->gf_name, b->gf_name));
+
+#undef FAM_DIFF
+
+       return diff;
+}
+/** @endcond */
+
+/**
+ * @name Object Allocation
+ * @{
+ */
+
+/**
+ * Allocate new Generic Netlink family object
+ * 
+ * @return Newly allocated Generic Netlink family object or NULL.
+ */
+struct genl_family *genl_family_alloc(void)
+{
+       return (struct genl_family *) nl_object_alloc(&genl_family_ops);
+}
+
+/**
+ * Release reference on Generic Netlink family object
+ * @arg family         Generic Netlink family object
+ *
+ * Reduces the reference counter of a Generic Netlink family object by one.
+ * The object is freed after the last user has returned its reference.
+ *
+ * @see nl_object_put()
+ */
+void genl_family_put(struct genl_family *family)
+{
+       nl_object_put((struct nl_object *) family);
+}
+
+/** @} */
+
+/**
+ * @name Numeric Identifier
+ * @{
+ */
+
+/**
+ * Return numeric identifier
+ * @arg family         Generic Netlink family object
+ *
+ * @return Numeric identifier or 0 if not available.
+ */
+unsigned int genl_family_get_id(struct genl_family *family)
+{
+       if (family->ce_mask & FAMILY_ATTR_ID)
+               return family->gf_id;
+       else
+               return GENL_ID_GENERATE;
+}
+
+/**
+ * Set the numeric identifier
+ * @arg family         Generic Netlink family object
+ * @arg id             New numeric identifier
+ */
+void genl_family_set_id(struct genl_family *family, unsigned int id)
+{
+       family->gf_id = id;
+       family->ce_mask |= FAMILY_ATTR_ID;
+}
+
+/** @} */
+
+/**
+ * @name Human Readable Name
+ * @{
+ */
+
+/**
+ * Return human readable name
+ * @arg family         Generic Netlink family object
+ *
+ * @return Name of family or NULL if not available
+ */
+char *genl_family_get_name(struct genl_family *family)
+{
+       if (family->ce_mask & FAMILY_ATTR_NAME)
+               return family->gf_name;
+       else
+               return NULL;
+}
+
+/**
+ * Set human readable name
+ * @arg family         Generic Netlink family object
+ * @arg name           New human readable name
+ */
+void genl_family_set_name(struct genl_family *family, const char *name)
+{
+       strncpy(family->gf_name, name, GENL_NAMSIZ-1);
+       family->ce_mask |= FAMILY_ATTR_NAME;
+}
+
+/**
+ * @name Interface Version
+ * @{
+ */
+
+/**
+ * Return interface version
+ * @arg family         Generic Netlink family object
+ *
+ * @return Interface version or 0 if not available.
+ */
+uint8_t genl_family_get_version(struct genl_family *family)
+{
+       if (family->ce_mask & FAMILY_ATTR_VERSION)
+               return family->gf_version;
+       else
+               return 0;
+}
+
+/**
+ * Set interface version
+ * @arg family         Generic Netlink family object
+ * @arg version                New interface version
+ */
+void genl_family_set_version(struct genl_family *family, uint8_t version)
+{
+       family->gf_version = version;
+       family->ce_mask |= FAMILY_ATTR_VERSION;
+}
+
+/** @} */
+
+/**
+ * @name Header Size
+ * @{
+ */
+
+/**
+ * Return user header size expected by kernel component
+ * @arg family         Generic Netlink family object
+ *
+ * @return Expected header length or 0 if not available.
+ */
+uint32_t genl_family_get_hdrsize(struct genl_family *family)
+{
+       if (family->ce_mask & FAMILY_ATTR_HDRSIZE)
+               return family->gf_hdrsize;
+       else
+               return 0;
+}
+
+void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize)
+{
+       family->gf_hdrsize = hdrsize;
+       family->ce_mask |= FAMILY_ATTR_HDRSIZE;
+}
+
+/** @} */
+
+/**
+ * @name Maximum Expected Attribute
+ * @{
+ */
+
+uint32_t genl_family_get_maxattr(struct genl_family *family)
+{
+       if (family->ce_mask & FAMILY_ATTR_MAXATTR)
+               return family->gf_maxattr;
+       else
+               return family->gf_maxattr;
+}
+
+void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
+{
+       family->gf_maxattr = maxattr;
+       family->ce_mask |= FAMILY_ATTR_MAXATTR;
+}
+
+/** @} */
+
+/**
+ * @name Operations
+ * @{
+ */
+
+int genl_family_add_op(struct genl_family *family, int id, int flags)
+{
+       struct genl_family_op *op;
+
+       op = calloc(1, sizeof(*op));
+       if (op == NULL)
+               return -NLE_NOMEM;
+
+       op->o_id = id;
+       op->o_flags = flags;
+
+       nl_list_add_tail(&op->o_list, &family->gf_ops);
+       family->ce_mask |= FAMILY_ATTR_OPS;
+
+       return 0;
+}
+
+int genl_family_add_grp(struct genl_family *family, uint32_t id,
+                       const char *name)
+{
+       struct genl_family_grp *grp;  
+
+       grp = calloc(1, sizeof(*grp));
+       if (grp == NULL)
+               return -NLE_NOMEM;
+
+       grp->id = id;
+       strncpy(grp->name, name, GENL_NAMSIZ - 1);
+
+       nl_list_add_tail(&grp->list, &family->gf_mc_grps);
+
+       return 0;
+}
+
+/** @} */
+
+/** @cond SKIP */
+struct nl_object_ops genl_family_ops = {
+       .oo_name                = "genl/family",
+       .oo_size                = sizeof(struct genl_family),
+       .oo_constructor         = family_constructor,
+       .oo_free_data           = family_free_data,
+       .oo_clone               = family_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = family_dump_line,
+           [NL_DUMP_DETAILS]   = family_dump_details,
+           [NL_DUMP_STATS]     = family_dump_stats,
+       },
+       .oo_compare             = family_compare,
+       .oo_id_attrs            = FAMILY_ATTR_ID,
+};
+/** @endcond */
+
+/** @} */
diff --git a/lib/genl/genl.c b/lib/genl/genl.c
new file mode 100644 (file)
index 0000000..0c9b11e
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * lib/genl/genl.c             Generic Netlink
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @defgroup genl Generic Netlink Library (libnl-genl)
+ *
+ * @{
+ */
+
+#include <netlink-private/genl.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/utils.h>
+
+/**
+ * @name Generic Netlink Socket
+ * @{
+ */
+
+/**
+ * Connect a Generic Netlink socket
+ * @arg sk             Unconnected Netlink socket
+ *
+ * This function expects a struct nl_socket object previously allocated via
+ * nl_socket_alloc(). It calls nl_connect() to create the local socket file
+ * descriptor and binds the socket to the \c NETLINK_GENERIC Netlink protocol.
+ *
+ * Using this function is equivalent to:
+ * @code
+ * nl_connect(sk, NETLINK_GENERIC);
+ * @endcode
+ *
+ * @see nl_connect()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_connect(struct nl_sock *sk)
+{
+       return nl_connect(sk, NETLINK_GENERIC);
+}
+
+/** @} */
+
+/**
+ * @name Sending Data
+ * @{
+ */
+
+/**
+ * Send a Generic Netlink message consisting only of a header
+ * @arg sk             Generic Netlink socket
+ * @arg family         Numeric family identifier
+ * @arg cmd            Numeric command identifier
+ * @arg version                Interface version
+ * @arg flags          Additional Netlink message flags (optional)
+ *
+ * This function is a shortcut for sending a Generic Netlink message without
+ * any message payload. The message will only consist of the Netlink and
+ * Generic Netlink headers. The header is constructed based on the specified
+ * parameters and passed on to nl_send_simple() to send it on the specified
+ * socket.
+ *
+ * @par Example:
+ * @code
+ * #include <netlink/genl/genl.h>
+ * #include <linux/genetlink.h>
+ *
+ * err = genl_send_simple(sk, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, CTRL_VERSION,
+ *                        NLM_F_DUMP);
+ * @endcode
+ *
+ * @see nl_send_simple()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_send_simple(struct nl_sock *sk, int family, int cmd,
+                    int version, int flags)
+{
+       struct genlmsghdr hdr = {
+               .cmd = cmd,
+               .version = version,
+       };
+
+       return nl_send_simple(sk, family, flags, &hdr, sizeof(hdr));
+}
+
+/** @} */
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+/**
+ * Validate Generic Netlink message headers
+ * @arg nlh            Pointer to Netlink message header
+ * @arg hdrlen         Length of user header
+ *
+ * Verifies the integrity of the Netlink and Generic Netlink headers by
+ * enforcing the following requirements:
+ *  - Valid Netlink message header (nlmsg_valid_hdr())
+ *  - Presence of a complete Generic Netlink header
+ *  - At least \c hdrlen bytes of payload included after the generic
+ *    netlink header.
+ *
+ * @return A positive integer (true) if the headers are valid or
+ *         0 (false) if not.
+ */
+int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
+{
+       struct genlmsghdr *ghdr;
+
+       if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
+               return 0;
+
+       ghdr = nlmsg_data(nlh);
+       if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
+               return 0;
+
+       return 1;
+}
+
+/**
+ * Validate Generic Netlink message including attributes
+ * @arg nlh            Pointer to Netlink message header
+ * @arg hdrlen         Length of user header
+ * @arg maxtype                Maximum attribtue id expected
+ * @arg policy         Attribute validation policy
+ *
+ * Verifies the validity of the Netlink and Generic Netlink headers using
+ * genlmsg_valid_hdr() and calls nla_validate() on the message payload to
+ * verify the integrity of eventual attributes.
+ *
+ * @note You may call genlmsg_parse() directly to perform validation and
+ *       parsing in a single step. 
+ *
+ * @see genlmsg_valid_hdr()
+ * @see nla_validate()
+ * @see genlmsg_parse()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
+                    struct nla_policy *policy)
+{
+       struct genlmsghdr *ghdr;
+
+       if (!genlmsg_valid_hdr(nlh, hdrlen))
+               return -NLE_MSG_TOOSHORT;
+
+       ghdr = nlmsg_data(nlh);
+       return nla_validate(genlmsg_attrdata(ghdr, hdrlen),
+                           genlmsg_attrlen(ghdr, hdrlen), maxtype, policy);
+}
+
+/**
+ * Parse Generic Netlink message including attributes
+ * @arg nlh            Pointer to Netlink message header
+ * @arg hdrlen         Length of user header
+ * @arg tb             Array to store parsed attributes
+ * @arg maxtype                Maximum attribute id expected
+ * @arg policy         Attribute validation policy
+ *
+ * Verifies the validity of the Netlink and Generic Netlink headers using
+ * genlmsg_valid_hdr() and calls nla_parse() on the message payload to
+ * parse eventual attributes.
+ *
+ * @par Example:
+ * @code
+ * struct nlattr *attrs[MY_TYPE_MAX+1];
+ *
+ * if ((err = genlsmg_parse(nlmsg_nlh(msg), sizeof(struct my_hdr), attrs,
+ *                          MY_TYPE_MAX, attr_policy)) < 0)
+ *     // ERROR
+ * @endcode
+ *
+ * @see genlmsg_valid_hdr()
+ * @see genlmsg_validate()
+ * @see nla_parse()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+                 int maxtype, struct nla_policy *policy)
+{
+       struct genlmsghdr *ghdr;
+
+       if (!genlmsg_valid_hdr(nlh, hdrlen))
+               return -NLE_MSG_TOOSHORT;
+
+       ghdr = nlmsg_data(nlh);
+       return nla_parse(tb, maxtype, genlmsg_attrdata(ghdr, hdrlen),
+                        genlmsg_attrlen(ghdr, hdrlen), policy);
+}
+
+/**
+ * Return pointer to Generic Netlink header
+ * @arg nlh            Netlink message header
+ *
+ * @return Pointer to Generic Netlink message header
+ */
+struct genlmsghdr *genlmsg_hdr(struct nlmsghdr *nlh)
+{
+       return nlmsg_data(nlh);
+}
+
+/**
+ * Return length of message payload including user header
+ * @arg gnlh           Generic Netlink message header
+ *
+ * @see genlmsg_data()
+ *
+ * @return Length of user payload including an eventual user header in
+ *         number of bytes.
+ */
+int genlmsg_len(const struct genlmsghdr *gnlh)
+{
+       const struct nlmsghdr *nlh;
+
+       nlh = (const struct nlmsghdr *)((const unsigned char *) gnlh - NLMSG_HDRLEN);
+       return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
+
+/**
+ * Return pointer to user header
+ * @arg gnlh           Generic Netlink message header
+ *
+ * Calculates the pointer to the user header based on the pointer to
+ * the Generic Netlink message header.
+ *
+ * @return Pointer to the user header
+ */
+void *genlmsg_user_hdr(const struct genlmsghdr *gnlh)
+{
+       return genlmsg_data(gnlh);
+}
+
+/**
+ * Return pointer to user data
+ * @arg gnlh           Generic netlink message header
+ * @arg hdrlen         Length of user header
+ *
+ * Calculates the pointer to the user data based on the pointer to
+ * the Generic Netlink message header.
+ *
+ * @see genlmsg_user_datalen()
+ *
+ * @return Pointer to the user data
+ */
+void *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen)
+{
+       return genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen);
+}
+
+/**
+ * Return length of user data
+ * @arg gnlh           Generic Netlink message header
+ * @arg hdrlen         Length of user header
+ *
+ * @see genlmsg_user_data()
+ *
+ * @return Length of user data in bytes
+ */
+int genlmsg_user_datalen(const struct genlmsghdr *gnlh, const int hdrlen)
+{
+       return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/**
+ * Return pointer to message attributes
+ * @arg gnlh           Generic Netlink message header
+ * @arg hdrlen         Length of user header
+ *
+ * @see genlmsg_attrlen()
+ *
+ * @return Pointer to the start of the message's attributes section.
+ */
+struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
+{
+       return genlmsg_user_data(gnlh, hdrlen);
+}
+
+/**
+ * Return length of message attributes
+ * @arg gnlh           Generic Netlink message header
+ * @arg hdrlen         Length of user header
+ *
+ * @see genlmsg_attrdata()
+ *
+ * @return Length of the message section containing attributes in number
+ *         of bytes.
+ */
+int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
+{
+       return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/** @} */
+
+/**
+ * @name Message Construction
+ * @{
+ */
+
+/**
+ * Add Generic Netlink headers to Netlink message
+ * @arg msg            Netlink message object
+ * @arg port           Netlink port or NL_AUTO_PORT
+ * @arg seq            Sequence number of message or NL_AUTO_SEQ
+ * @arg family         Numeric family identifier
+ * @arg hdrlen         Length of user header
+ * @arg flags          Additional Netlink message flags (optional)
+ * @arg cmd            Numeric command identifier
+ * @arg version                Interface version
+ *
+ * Calls nlmsg_put() on the specified message object to reserve space for
+ * the Netlink header, the Generic Netlink header, and a user header of
+ * specified length. Fills out the header fields with the specified
+ * parameters.
+ *
+ * @par Example:
+ * @code
+ * struct nl_msg *msg;
+ * struct my_hdr *user_hdr;
+ *
+ * if (!(msg = nlmsg_alloc()))
+ *     // ERROR
+ *
+ * user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family_id,
+ *                        sizeof(struct my_hdr), 0, MY_CMD_FOO, 0);
+ * if (!user_hdr)
+ *     // ERROR
+ * @endcode
+ *
+ * @see nlmsg_put()
+ *
+ * Returns Pointer to user header or NULL if an error occurred.
+ */
+void *genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
+                 int hdrlen, int flags, uint8_t cmd, uint8_t version)
+{
+       struct nlmsghdr *nlh;
+       struct genlmsghdr hdr = {
+               .cmd = cmd,
+               .version = version,
+       };
+
+       nlh = nlmsg_put(msg, port, seq, family, GENL_HDRLEN + hdrlen, flags);
+       if (nlh == NULL)
+               return NULL;
+
+       memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
+       NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
+              msg, cmd, version);
+
+       return nlmsg_data(nlh) + GENL_HDRLEN;
+}
+
+/** @} */
+
+/**
+ * @name Deprecated
+ * @{
+ */
+
+/**
+ * Return pointer to message payload
+ * @arg gnlh           Generic Netlink message header
+ *
+ * @deprecated This function has been deprecated due to inability to specify
+ *             the length of the user header. Use genlmsg_user_hdr()
+ *             respectively genlmsg_user_data().
+ *
+ * @return Pointer to payload section
+ */
+void *genlmsg_data(const struct genlmsghdr *gnlh)
+{
+       return ((unsigned char *) gnlh + GENL_HDRLEN);
+}
+
+/** @} */
+/** @} */
diff --git a/lib/genl/mngt.c b/lib/genl/mngt.c
new file mode 100644 (file)
index 0000000..3648663
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * lib/genl/mngt.c             Generic Netlink Management
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup genl
+ * @defgroup genl_mngt Family and Command Registration
+ *
+ * Registering Generic Netlink Families and Commands
+ *
+ * @{
+ */
+
+#include <netlink-private/genl.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/mngt.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+
+static NL_LIST_HEAD(genl_ops_list);
+
+static struct genl_cmd *lookup_cmd(struct genl_ops *ops, int cmd_id)
+{
+       struct genl_cmd *cmd;
+       int i;
+
+       for (i = 0; i < ops->o_ncmds; i++) {
+               cmd = &ops->o_cmds[i];
+               if (cmd->c_id == cmd_id)
+                       return cmd;
+       }
+
+       return NULL;
+}
+
+static int cmd_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
+                         struct genl_ops *ops, struct nl_cache_ops *cache_ops, void *arg)
+{
+       int err;
+       struct genlmsghdr *ghdr;
+       struct genl_cmd *cmd;
+
+       ghdr = genlmsg_hdr(nlh);
+
+       if (!(cmd = lookup_cmd(ops, ghdr->cmd))) {
+               err = -NLE_MSGTYPE_NOSUPPORT;
+               goto errout;
+       }
+
+       if (cmd->c_msg_parser == NULL)
+               err = -NLE_OPNOTSUPP;
+       else {
+               struct nlattr *tb[cmd->c_maxattr + 1];
+               struct genl_info info = {
+                       .who = who,
+                       .nlh = nlh,
+                       .genlhdr = ghdr,
+                       .userhdr = genlmsg_user_hdr(ghdr),
+                       .attrs = tb,
+               };
+
+               err = nlmsg_parse(nlh, GENL_HDRSIZE(ops->o_hdrsize), tb, cmd->c_maxattr,
+                                 cmd->c_attr_policy);
+               if (err < 0)
+                       goto errout;
+
+               err = cmd->c_msg_parser(cache_ops, cmd, &info, arg);
+       }
+errout:
+       return err;
+
+}
+
+static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                          struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       if (ops->co_genl == NULL)
+               BUG();
+
+       return cmd_msg_parser(who, nlh, ops->co_genl, ops, pp);
+}
+
+static struct genl_ops *lookup_family(int family)
+{
+       struct genl_ops *ops;
+
+       nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
+               if (ops->o_id == family)
+                       return ops;
+       }
+
+       return NULL;
+}
+
+static struct genl_ops *lookup_family_by_name(const char *name)
+{
+       struct genl_ops *ops;
+
+       nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
+               if (!strcmp(ops->o_name, name))
+                       return ops;
+       }
+
+       return NULL;
+}
+
+char *genl_op2name(int family, int op, char *buf, size_t len)
+{
+       struct genl_ops *ops;
+       int i;
+
+       if ((ops = lookup_family(family))) {
+               for (i = 0; i < ops->o_ncmds; i++) {
+                       struct genl_cmd *cmd;
+                       cmd = &ops->o_cmds[i];
+
+                       if (cmd->c_id == op) {
+                               strncpy(buf, cmd->c_name, len - 1);
+                               return buf;
+                       }
+               }
+       }
+
+       strncpy(buf, "unknown", len - 1);
+       return NULL;
+}
+
+/** @endcond */
+
+/**
+ * @name Registration
+ * @{
+ */
+
+/**
+ * Register Generic Netlink family and associated commands
+ * @arg ops            Generic Netlink family definition
+ *
+ * Registers the specified Generic Netlink family definition together with
+ * all associated commands. After registration, received Generic Netlink
+ * messages can be passed to genl_handle_msg() which will validate the
+ * messages, look for a matching command and call the respective callback
+ * function automatically.
+ *
+ * @note Consider using genl_register() if the family is used to implement a
+ *       cacheable type.
+ *
+ * @see genl_unregister_family();
+ * @see genl_register();
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_register_family(struct genl_ops *ops)
+{
+       if (!ops->o_name)
+               return -NLE_INVAL;
+
+       if (ops->o_cmds && ops->o_ncmds <= 0)
+               return -NLE_INVAL;
+
+       if (ops->o_id && lookup_family(ops->o_id))
+               return -NLE_EXIST;
+
+       if (lookup_family_by_name(ops->o_name))
+               return -NLE_EXIST;
+
+       nl_list_add_tail(&ops->o_list, &genl_ops_list);
+
+       return 0;
+}
+
+/**
+ * Unregister Generic Netlink family
+ * @arg ops            Generic Netlink family definition
+ *
+ * Unregisters a family and all associated commands that were previously
+ * registered using genl_register_family().
+ *
+ * @see genl_register_family()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_unregister_family(struct genl_ops *ops)
+{
+       nl_list_del(&ops->o_list);
+
+       return 0;
+}
+
+/**
+ * Run a received message through the demultiplexer
+ * @arg msg            Generic Netlink message
+ * @arg arg            Argument passed on to the message handler callback
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_handle_msg(struct nl_msg *msg, void *arg)
+{
+       struct nlmsghdr *nlh = nlmsg_hdr(msg);
+       struct genl_ops *ops;
+
+       if (!genlmsg_valid_hdr(nlh, 0))
+               return -NLE_INVAL;
+
+       if (!(ops = lookup_family(nlh->nlmsg_type)))
+               return -NLE_MSGTYPE_NOSUPPORT;
+
+       return cmd_msg_parser(nlmsg_get_src(msg), nlh, ops, NULL, arg);
+}
+
+/** @} */
+
+/**
+ * @name Registration of Cache Operations
+ * @{
+ */
+
+/**
+ * Register Generic Netlink family backed cache
+ * @arg ops            Cache operations definition
+ *
+ * Same as genl_register_family() but additionally registers the specified
+ * cache operations using nl_cache_mngt_register() and associates it with
+ * the Generic Netlink family.
+ *
+ * @see genl_register_family()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_register(struct nl_cache_ops *ops)
+{
+       int err;
+
+       if (ops->co_protocol != NETLINK_GENERIC) {
+               err = -NLE_PROTO_MISMATCH;
+               goto errout;
+       }
+
+       if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
+               err = -NLE_INVAL;
+               goto errout;
+       }
+
+       if (ops->co_genl == NULL) {
+               err = -NLE_INVAL;
+               goto errout;
+       }
+
+       ops->co_genl->o_cache_ops = ops;
+       ops->co_genl->o_hdrsize = ops->co_hdrsize - GENL_HDRLEN;
+       ops->co_genl->o_name = ops->co_msgtypes[0].mt_name;
+       ops->co_genl->o_id = ops->co_msgtypes[0].mt_id;
+       ops->co_msg_parser = genl_msg_parser;
+
+       if ((err = genl_register_family(ops->co_genl)) < 0)
+               goto errout;
+
+       err = nl_cache_mngt_register(ops);
+errout:
+       return err;
+}
+
+/**
+ * Unregister cache based Generic Netlink family
+ * @arg ops            Cache operations definition
+ */
+void genl_unregister(struct nl_cache_ops *ops)
+{
+       if (!ops)
+               return;
+
+       nl_cache_mngt_unregister(ops);
+
+       genl_unregister_family(ops->co_genl);
+}
+
+/** @} */
+
+/** @cond SKIP */
+static int __genl_ops_resolve(struct nl_cache *ctrl, struct genl_ops *ops)
+{
+       struct genl_family *family;
+
+       family = genl_ctrl_search_by_name(ctrl, ops->o_name);
+       if (family != NULL) {
+               ops->o_id = genl_family_get_id(family);
+
+               if (ops->o_cache_ops)
+                       ops->o_cache_ops->co_msgtypes[0].mt_id = ops->o_id;
+
+               genl_family_put(family);
+
+               return 0;
+       }
+
+       return -NLE_OBJ_NOTFOUND;
+}
+
+int genl_resolve_id(struct genl_ops *ops)
+{
+       struct nl_sock *sk;
+       int err = 0;
+
+       /* Check if resolved already */
+       if (ops->o_id != GENL_ID_GENERATE)
+               return 0;
+
+       if (!ops->o_name)
+               return -NLE_INVAL;
+
+       if (!(sk = nl_socket_alloc()))
+               return -NLE_NOMEM;
+
+       if ((err = genl_connect(sk)) < 0)
+               goto errout_free;
+
+       err = genl_ops_resolve(sk, ops);
+
+errout_free:
+       nl_socket_free(sk);
+
+       return err;
+}
+/** @endcond */
+
+/**
+ * @name Resolving the name of registered families
+ * @{
+ */
+
+/**
+ * Resolve a single Generic Netlink family
+ * @arg sk             Generic Netlink socket
+ * @arg ops            Generic Netlink family definition
+ *
+ * Resolves the family name to its numeric identifier.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_ops_resolve(struct nl_sock *sk, struct genl_ops *ops)
+{
+       struct nl_cache *ctrl;
+       int err;
+
+       if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0)
+               goto errout;
+
+       err = __genl_ops_resolve(ctrl, ops);
+
+       nl_cache_free(ctrl);
+errout:
+       return err;
+}
+
+/**
+ * Resolve all registered Generic Netlink families
+ * @arg sk             Generic Netlink socket
+ *
+ * Walks through all local Generic Netlink families that have been registered
+ * using genl_register() and resolves the name of each family to the
+ * corresponding numeric identifier.
+ *
+ * @see genl_register()
+ * @see genl_ops_resolve()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int genl_mngt_resolve(struct nl_sock *sk)
+{
+       struct nl_cache *ctrl;
+       struct genl_ops *ops;
+       int err = 0;
+
+       if ((err = genl_ctrl_alloc_cache(sk, &ctrl)) < 0)
+               goto errout;
+
+       nl_list_for_each_entry(ops, &genl_ops_list, o_list) {
+               err = __genl_ops_resolve(ctrl, ops);
+       }
+
+       nl_cache_free(ctrl);
+errout:
+       return err;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/handlers.c b/lib/handlers.c
new file mode 100644 (file)
index 0000000..e52c850
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * lib/handlers.c      default netlink message handlers
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup cb Callbacks/Customization
+ *
+ * Related sections in the development guide:
+ * - @core_doc{core_cb, Callback Configuration}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/handlers.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/msg.h>
+#include <netlink/handlers.h>
+
+static void print_header_content(FILE *ofd, struct nlmsghdr *n)
+{
+       char flags[128];
+       char type[32];
+       
+       fprintf(ofd, "type=%s length=%u flags=<%s> sequence-nr=%u pid=%u",
+               nl_nlmsgtype2str(n->nlmsg_type, type, sizeof(type)),
+               n->nlmsg_len, nl_nlmsg_flags2str(n->nlmsg_flags, flags,
+               sizeof(flags)), n->nlmsg_seq, n->nlmsg_pid);
+}
+
+static int nl_valid_handler_verbose(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stdout;
+
+       fprintf(ofd, "-- Warning: unhandled valid message: ");
+       print_header_content(ofd, nlmsg_hdr(msg));
+       fprintf(ofd, "\n");
+
+       return NL_OK;
+}
+
+static int nl_invalid_handler_verbose(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Error: Invalid message: ");
+       print_header_content(ofd, nlmsg_hdr(msg));
+       fprintf(ofd, "\n");
+
+       return NL_STOP;
+}
+
+static int nl_overrun_handler_verbose(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Error: Netlink Overrun: ");
+       print_header_content(ofd, nlmsg_hdr(msg));
+       fprintf(ofd, "\n");
+       
+       return NL_STOP;
+}
+
+static int nl_error_handler_verbose(struct sockaddr_nl *who,
+                                   struct nlmsgerr *e, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+       char buf[256];
+
+       fprintf(ofd, "-- Error received: %s\n-- Original message: ",
+               strerror_r(-e->error, buf, sizeof(buf)));
+       print_header_content(ofd, &e->msg);
+       fprintf(ofd, "\n");
+
+       return -nl_syserr2nlerr(e->error);
+}
+
+static int nl_valid_handler_debug(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Debug: Unhandled Valid message: ");
+       print_header_content(ofd, nlmsg_hdr(msg));
+       fprintf(ofd, "\n");
+
+       return NL_OK;
+}
+
+static int nl_finish_handler_debug(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Debug: End of multipart message block: ");
+       print_header_content(ofd, nlmsg_hdr(msg));
+       fprintf(ofd, "\n");
+       
+       return NL_STOP;
+}
+
+static int nl_msg_in_handler_debug(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Debug: Received Message:\n");
+       nl_msg_dump(msg, ofd);
+       
+       return NL_OK;
+}
+
+static int nl_msg_out_handler_debug(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Debug: Sent Message:\n");
+       nl_msg_dump(msg, ofd);
+
+       return NL_OK;
+}
+
+static int nl_skipped_handler_debug(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Debug: Skipped message: ");
+       print_header_content(ofd, nlmsg_hdr(msg));
+       fprintf(ofd, "\n");
+
+       return NL_SKIP;
+}
+
+static int nl_ack_handler_debug(struct nl_msg *msg, void *arg)
+{
+       FILE *ofd = arg ? arg : stderr;
+
+       fprintf(ofd, "-- Debug: ACK: ");
+       print_header_content(ofd, nlmsg_hdr(msg));
+       fprintf(ofd, "\n");
+
+       return NL_STOP;
+}
+
+static nl_recvmsg_msg_cb_t cb_def[NL_CB_TYPE_MAX+1][NL_CB_KIND_MAX+1] = {
+       [NL_CB_VALID] = {
+               [NL_CB_VERBOSE] = nl_valid_handler_verbose,
+               [NL_CB_DEBUG]   = nl_valid_handler_debug,
+       },
+       [NL_CB_FINISH] = {
+               [NL_CB_DEBUG]   = nl_finish_handler_debug,
+       },
+       [NL_CB_INVALID] = {
+               [NL_CB_VERBOSE] = nl_invalid_handler_verbose,
+               [NL_CB_DEBUG]   = nl_invalid_handler_verbose,
+       },
+       [NL_CB_MSG_IN] = {
+               [NL_CB_DEBUG]   = nl_msg_in_handler_debug,
+       },
+       [NL_CB_MSG_OUT] = {
+               [NL_CB_DEBUG]   = nl_msg_out_handler_debug,
+       },
+       [NL_CB_OVERRUN] = {
+               [NL_CB_VERBOSE] = nl_overrun_handler_verbose,
+               [NL_CB_DEBUG]   = nl_overrun_handler_verbose,
+       },
+       [NL_CB_SKIPPED] = {
+               [NL_CB_DEBUG]   = nl_skipped_handler_debug,
+       },
+       [NL_CB_ACK] = {
+               [NL_CB_DEBUG]   = nl_ack_handler_debug,
+       },
+};
+
+static nl_recvmsg_err_cb_t cb_err_def[NL_CB_KIND_MAX+1] = {
+       [NL_CB_VERBOSE] = nl_error_handler_verbose,
+       [NL_CB_DEBUG]   = nl_error_handler_verbose,
+};
+
+/**
+ * @name Callback Handle Management
+ * @{
+ */
+
+/**
+ * Allocate a new callback handle
+ * @arg kind           callback kind to be used for initialization
+ * @return Newly allocated callback handle or NULL
+ */
+struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
+{
+       int i;
+       struct nl_cb *cb;
+
+       if (kind < 0 || kind > NL_CB_KIND_MAX)
+               return NULL;
+
+       cb = calloc(1, sizeof(*cb));
+       if (!cb)
+               return NULL;
+
+       cb->cb_refcnt = 1;
+
+       for (i = 0; i <= NL_CB_TYPE_MAX; i++)
+               nl_cb_set(cb, i, kind, NULL, NULL);
+
+       nl_cb_err(cb, kind, NULL, NULL);
+
+       return cb;
+}
+
+/**
+ * Clone an existing callback handle
+ * @arg orig           original callback handle
+ * @return Newly allocated callback handle being a duplicate of
+ *         orig or NULL
+ */
+struct nl_cb *nl_cb_clone(struct nl_cb *orig)
+{
+       struct nl_cb *cb;
+       
+       cb = nl_cb_alloc(NL_CB_DEFAULT);
+       if (!cb)
+               return NULL;
+
+       memcpy(cb, orig, sizeof(*orig));
+       cb->cb_refcnt = 1;
+
+       return cb;
+}
+
+struct nl_cb *nl_cb_get(struct nl_cb *cb)
+{
+       cb->cb_refcnt++;
+
+       return cb;
+}
+
+void nl_cb_put(struct nl_cb *cb)
+{
+       if (!cb)
+               return;
+
+       cb->cb_refcnt--;
+
+       if (cb->cb_refcnt < 0)
+               BUG();
+
+       if (cb->cb_refcnt <= 0)
+               free(cb);
+}
+
+/** @} */
+
+/**
+ * @name Callback Setup
+ * @{
+ */
+
+/**
+ * Set up a callback 
+ * @arg cb             callback set
+ * @arg type           callback to modify
+ * @arg kind           kind of implementation
+ * @arg func           callback function (NL_CB_CUSTOM)
+ * @arg arg            argument passed to callback
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
+             nl_recvmsg_msg_cb_t func, void *arg)
+{
+       if (type < 0 || type > NL_CB_TYPE_MAX)
+               return -NLE_RANGE;
+
+       if (kind < 0 || kind > NL_CB_KIND_MAX)
+               return -NLE_RANGE;
+
+       if (kind == NL_CB_CUSTOM) {
+               cb->cb_set[type] = func;
+               cb->cb_args[type] = arg;
+       } else {
+               cb->cb_set[type] = cb_def[type][kind];
+               cb->cb_args[type] = arg;
+       }
+
+       return 0;
+}
+
+/**
+ * Set up a all callbacks
+ * @arg cb             callback set
+ * @arg kind           kind of callback
+ * @arg func           callback function
+ * @arg arg            argument to be passwd to callback function
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
+                 nl_recvmsg_msg_cb_t func, void *arg)
+{
+       int i, err;
+
+       for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
+               err = nl_cb_set(cb, i, kind, func, arg);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/**
+ * Set up an error callback
+ * @arg cb             callback set
+ * @arg kind           kind of callback
+ * @arg func           callback function
+ * @arg arg            argument to be passed to callback function
+ */
+int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
+             nl_recvmsg_err_cb_t func, void *arg)
+{
+       if (kind < 0 || kind > NL_CB_KIND_MAX)
+               return -NLE_RANGE;
+
+       if (kind == NL_CB_CUSTOM) {
+               cb->cb_err = func;
+               cb->cb_err_arg = arg;
+       } else {
+               cb->cb_err = cb_err_def[kind];
+               cb->cb_err_arg = arg;
+       }
+
+       return 0;
+}
+
+/** @} */
+
+/**
+ * @name Overwriting
+ * @{
+ */
+
+/**
+ * Overwrite internal calls to nl_recvmsgs()
+ * @arg cb             callback set
+ * @arg func           replacement callback for nl_recvmsgs()
+ */
+void nl_cb_overwrite_recvmsgs(struct nl_cb *cb,
+                             int (*func)(struct nl_sock *, struct nl_cb *))
+{
+       cb->cb_recvmsgs_ow = func;
+}
+
+/**
+ * Overwrite internal calls to nl_recv()
+ * @arg cb             callback set
+ * @arg func           replacement callback for nl_recv()
+ */
+void nl_cb_overwrite_recv(struct nl_cb *cb,
+                         int (*func)(struct nl_sock *, struct sockaddr_nl *,
+                                     unsigned char **, struct ucred **))
+{
+       cb->cb_recv_ow = func;
+}
+
+/**
+ * Overwrite internal calls to nl_send()
+ * @arg cb             callback set
+ * @arg func           replacement callback for nl_send()
+ */
+void nl_cb_overwrite_send(struct nl_cb *cb,
+                         int (*func)(struct nl_sock *, struct nl_msg *))
+{
+       cb->cb_send_ow = func;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644 (file)
index 0000000..47c938b
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * This code was taken from http://ccodearchive.net/info/hash.html
+ * The original file was modified to remove unwanted code
+ * and some changes to fit the current build environment
+ */
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions.  Routines to test the hash are included
+if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+the public domain.  It has no warranty.
+
+You probably want to use hashlittle().  hashlittle() and hashbig()
+hash byte arrays.  hashlittle() is is faster than hashbig() on
+little-endian machines.  Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+  a = i1;  b = i2;  c = i3;
+  mix(a,b,c);
+  a += i4; b += i5; c += i6;
+  mix(a,b,c);
+  a += i7;
+  final(a,b,c);
+then use c as the hash value.  If you have a variable length array of
+4-byte integers to hash, use hash_word().  If you have a byte array (like
+a character string), use hashlittle().  If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big?  I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers.  This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+#include <netlink/hash.h>
+
+#if HAVE_LITTLE_ENDIAN
+#define HASH_LITTLE_ENDIAN 1
+#define HASH_BIG_ENDIAN 0
+#elif HAVE_BIG_ENDIAN
+#define HASH_LITTLE_ENDIAN 0
+#define HASH_BIG_ENDIAN 1
+#else
+#error Unknown endian
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or
+  all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+    4  6  8 16 19  4
+    9 15  3 18 27 15
+   14  9  3  7 17  3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta.  I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche.  There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a.  The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism.  Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism.  I did what I could.  Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different.  This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or
+  all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+  4  8 15 26 3 22 24
+ 10  8 15 26 3 22 24
+ 11  8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
+}
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+  k       : the key (the unaligned variable-length array of bytes)
+  length  : the length of the key, counting by bytes
+  val2    : IN: can be any 4-byte value OUT: second 32 bit hash.
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Two keys differing by one or two bits will have
+totally different hash values.  Note that the return value is better
+mixed than val2, so use that first.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.  It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+static uint32_t hashlittle( const void *key, size_t length, uint32_t *val2 )
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + *val2;
+
+  u.ptr = key;
+  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+    const uint8_t  *k8;
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /*
+     * "k[2]&0xffffff" actually reads beyond the end of the string, but
+     * then masks off the part it's not allowed to read.  Because the
+     * string is aligned, the masked-off tail is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     *
+     * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR.
+     */
+#if 0
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff; break;
+    case 2 : a+=k[0]&0xffff; break;
+    case 1 : a+=k[0]&0xff; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    }
+
+#else /* make valgrind happy */
+
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
+    case 9 : c+=k8[8];                   /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
+    case 5 : b+=k8[4];                   /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
+    case 1 : a+=k8[0]; break;
+    case 0 : return c;
+    }
+
+#endif /* !valgrind */
+
+  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+    const uint8_t  *k8;
+
+    /*--------------- all but last block: aligned reads and different mixing */
+    while (length > 12)
+    {
+      a += k[0] + (((uint32_t)k[1])<<16);
+      b += k[2] + (((uint32_t)k[3])<<16);
+      c += k[4] + (((uint32_t)k[5])<<16);
+      mix(a,b,c);
+      length -= 12;
+      k += 6;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
+    case 10: c+=k[4];
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 9 : c+=k8[8];                      /* fall through */
+    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
+    case 6 : b+=k[2];
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 5 : b+=k8[4];                      /* fall through */
+    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
+    case 2 : a+=k[0];
+             break;
+    case 1 : a+=k8[0];
+             break;
+    case 0 : return c;                     /* zero length requires no mixing */
+    }
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      a += ((uint32_t)k[1])<<8;
+      a += ((uint32_t)k[2])<<16;
+      a += ((uint32_t)k[3])<<24;
+      b += k[4];
+      b += ((uint32_t)k[5])<<8;
+      b += ((uint32_t)k[6])<<16;
+      b += ((uint32_t)k[7])<<24;
+      c += k[8];
+      c += ((uint32_t)k[9])<<8;
+      c += ((uint32_t)k[10])<<16;
+      c += ((uint32_t)k[11])<<24;
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=((uint32_t)k[11])<<24;
+    case 11: c+=((uint32_t)k[10])<<16;
+    case 10: c+=((uint32_t)k[9])<<8;
+    case 9 : c+=k[8];
+    case 8 : b+=((uint32_t)k[7])<<24;
+    case 7 : b+=((uint32_t)k[6])<<16;
+    case 6 : b+=((uint32_t)k[5])<<8;
+    case 5 : b+=k[4];
+    case 4 : a+=((uint32_t)k[3])<<24;
+    case 3 : a+=((uint32_t)k[2])<<16;
+    case 2 : a+=((uint32_t)k[1])<<8;
+    case 1 : a+=k[0];
+             break;
+    case 0 : return c;
+    }
+  }
+
+  final(a,b,c);
+  *val2 = b;
+  return c;
+}
+
+/*
+ * hashbig():
+ * This is the same as hash_word() on big-endian machines.  It is different
+ * from hashlittle() on all machines.  hashbig() takes advantage of
+ * big-endian byte ordering.
+ */
+static uint32_t hashbig( const void *key, size_t length, uint32_t *val2)
+{
+  uint32_t a,b,c;
+  union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + *val2;
+
+  u.ptr = key;
+  if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+    const uint8_t  *k8;
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /*
+     * "k[2]<<8" actually reads beyond the end of the string, but
+     * then shifts out the part it's not allowed to read.  Because the
+     * string is aligned, the illegal read is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     *
+     * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR.
+     */
+#if 0
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff00; break;
+    case 2 : a+=k[0]&0xffff0000; break;
+    case 1 : a+=k[0]&0xff000000; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    }
+
+#else  /* make valgrind happy */
+
+    k8 = (const uint8_t *)k;
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<8;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<16;  /* fall through */
+    case 9 : c+=((uint32_t)k8[8])<<24;  /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<8;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<16;  /* fall through */
+    case 5 : b+=((uint32_t)k8[4])<<24;  /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<8;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<16;  /* fall through */
+    case 1 : a+=((uint32_t)k8[0])<<24; break;
+    case 0 : return c;
+    }
+
+#endif /* !VALGRIND */
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += ((uint32_t)k[0])<<24;
+      a += ((uint32_t)k[1])<<16;
+      a += ((uint32_t)k[2])<<8;
+      a += ((uint32_t)k[3]);
+      b += ((uint32_t)k[4])<<24;
+      b += ((uint32_t)k[5])<<16;
+      b += ((uint32_t)k[6])<<8;
+      b += ((uint32_t)k[7]);
+      c += ((uint32_t)k[8])<<24;
+      c += ((uint32_t)k[9])<<16;
+      c += ((uint32_t)k[10])<<8;
+      c += ((uint32_t)k[11]);
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=k[11];
+    case 11: c+=((uint32_t)k[10])<<8;
+    case 10: c+=((uint32_t)k[9])<<16;
+    case 9 : c+=((uint32_t)k[8])<<24;
+    case 8 : b+=k[7];
+    case 7 : b+=((uint32_t)k[6])<<8;
+    case 6 : b+=((uint32_t)k[5])<<16;
+    case 5 : b+=((uint32_t)k[4])<<24;
+    case 4 : a+=k[3];
+    case 3 : a+=((uint32_t)k[2])<<8;
+    case 2 : a+=((uint32_t)k[1])<<16;
+    case 1 : a+=((uint32_t)k[0])<<24;
+             break;
+    case 0 : return c;
+    }
+  }
+
+  final(a,b,c);
+  *val2 = b;
+  return c;
+}
+
+uint32_t nl_hash_any(const void *key, size_t length, uint32_t base)
+{
+       if (HASH_BIG_ENDIAN)
+               return hashbig(key, length, &base);
+       else
+               return hashlittle(key, length, &base);
+}
diff --git a/lib/hashtable.c b/lib/hashtable.c
new file mode 100644 (file)
index 0000000..8b15925
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * netlink/hashtable.c      Netlink hashtable Utilities
+ *
+ *      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) 2012 Cumulus Networks, Inc
+ */
+#include <string.h>
+#include <netlink-private/netlink.h>
+#include <netlink/object.h>
+#include <netlink/hash.h>
+#include <netlink/hashtable.h>
+
+/**
+ * @ingroup core_types
+ * @defgroup hashtable Hashtable
+ * @{
+ */
+
+/**
+ * Allocate hashtable
+ * @arg size           Size of hashtable in number of elements
+ *
+ * @return Allocated hashtable or NULL.
+ */
+nl_hash_table_t *nl_hash_table_alloc(int size)
+{
+       nl_hash_table_t *ht;
+
+       ht = calloc(1, sizeof (*ht));
+       if (!ht)
+               goto errout;
+
+       ht->nodes = calloc(size, sizeof (*ht->nodes));
+       if (!ht->nodes) {
+               free(ht);
+               goto errout;
+       }
+
+       ht->size = size;
+
+       return ht;
+errout:
+       return NULL;
+}
+
+/**
+ * Free hashtable including all nodes
+ * @arg ht             Hashtable
+ *
+ * @note Reference counter of all objects in the hashtable will be decremented.
+ */
+void nl_hash_table_free(nl_hash_table_t *ht)
+{
+       int i;
+
+       for(i = 0; i < ht->size; i++) {
+           nl_hash_node_t *node = ht->nodes[i];
+           nl_hash_node_t *saved_node;
+
+           while (node) {
+                  saved_node = node;
+                  node = node->next;
+                  nl_object_put(saved_node->obj);
+                  free(saved_node);
+           }
+       }
+
+       free(ht->nodes);
+       free(ht);
+}
+
+/**
+ * Lookup identical object in hashtable
+ * @arg ht             Hashtable
+ * @arg        obj             Object to lookup
+ *
+ * Generates hashkey for `obj` and traverses the corresponding chain calling
+ * `nl_object_identical()` on each trying to find a match.
+ *
+ * @return Pointer to object if match was found or NULL.
+ */
+struct nl_object* nl_hash_table_lookup(nl_hash_table_t *ht,
+                                      struct nl_object *obj)
+{
+       nl_hash_node_t *node;
+       uint32_t key_hash;
+
+       nl_object_keygen(obj, &key_hash, ht->size);
+       node = ht->nodes[key_hash];
+
+       while (node) {
+              if (nl_object_identical(node->obj, obj))
+                  return node->obj;
+              node = node->next;
+       }
+
+       return NULL;
+}
+
+/**
+ * Add object to hashtable
+ * @arg ht             Hashtable
+ * @arg obj            Object to add
+ *
+ * Adds `obj` to the hashtable. Object type must support hashing, otherwise all
+ * objects will be added to the chain `0`.
+ *
+ * @note The reference counter of the object is incremented.
+ *
+ * @return 0 on success or a negative error code
+ * @retval -NLE_EXIST Identical object already present in hashtable
+ */
+int nl_hash_table_add(nl_hash_table_t *ht, struct nl_object *obj)
+{
+       nl_hash_node_t *node;
+       uint32_t key_hash;
+
+       nl_object_keygen(obj, &key_hash, ht->size);
+       node = ht->nodes[key_hash];
+
+       while (node) {
+              if (nl_object_identical(node->obj, obj)) {
+                  NL_DBG(2, "Warning: Add to hashtable found duplicate...\n");
+                  return -NLE_EXIST;
+              }
+              node = node->next;
+       }
+
+       NL_DBG (5, "adding cache entry of obj %p in table %p, with hash 0x%x\n",
+               obj, ht, key_hash);
+
+       node = malloc(sizeof(nl_hash_node_t));
+       if (!node)
+               return -NLE_NOMEM;
+       nl_object_get(obj);
+       node->obj = obj;
+       node->key = key_hash;
+       node->key_size = sizeof(uint32_t);
+       node->next = ht->nodes[key_hash];
+       ht->nodes[key_hash] = node;
+
+       return 0;
+}
+
+/**
+ * Remove object from hashtable
+ * @arg ht             Hashtable
+ * @arg obj            Object to remove
+ *
+ * Remove `obj` from hashtable if it exists.
+ *
+ * @note Reference counter of object will be decremented.
+ *
+ * @return 0 on success or a negative error code.
+ * @retval -NLE_OBJ_NOTFOUND Object not present in hashtable.
+ */
+int nl_hash_table_del(nl_hash_table_t *ht, struct nl_object *obj)
+{
+       nl_hash_node_t *node, *prev;
+       uint32_t key_hash;
+
+       nl_object_keygen(obj, &key_hash, ht->size);
+       prev = node = ht->nodes[key_hash];
+
+       while (node) {
+              if (nl_object_identical(node->obj, obj)) {
+                  nl_object_put(obj);
+
+                  NL_DBG (5, "deleting cache entry of obj %p in table %p, with"
+                          " hash 0x%x\n", obj, ht, key_hash);
+
+                  if (node == ht->nodes[key_hash])
+                      ht->nodes[key_hash] = node->next;
+                  else
+                      prev->next = node->next;
+
+                  free(node);
+
+                  return 0;
+               }
+               prev = node;
+               node = node->next;
+       }
+
+       return -NLE_OBJ_NOTFOUND;
+}
+
+uint32_t nl_hash(void *k, size_t length, uint32_t initval)
+{
+       return(__nl_hash(k, length, initval));
+}
+
+/** @} */
diff --git a/lib/msg.c b/lib/msg.c
new file mode 100644 (file)
index 0000000..6478507
--- /dev/null
+++ b/lib/msg.c
@@ -0,0 +1,996 @@
+/*
+ * lib/msg.c           Netlink Messages Interface
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup msg Message Construction & Parsing
+ * Netlink Message Construction/Parsing Interface
+ * 
+ * Related sections in the development guide:
+ * - @core_doc{_message_parsing_amp_construction,Message Parsing & Construction}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/msg.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/cache.h>
+#include <netlink/attr.h>
+#include <linux/socket.h>
+
+static size_t default_msg_size;
+
+static void __init init_msg_size(void)
+{
+       default_msg_size = getpagesize();
+}
+
+/**
+ * @name Size Calculations
+ * @{
+ */
+
+/**
+ * Calculates size of netlink message based on payload length.
+ * @arg payload                Length of payload
+ *
+ * @return size of netlink message without padding.
+ */
+int nlmsg_size(int payload)
+{
+       return NLMSG_HDRLEN + payload;
+}
+
+static int nlmsg_msg_size(int payload)
+{
+       return nlmsg_size(payload);
+}
+
+/**
+ * Calculates size of netlink message including padding based on payload length
+ * @arg payload                Length of payload
+ *
+ * This function is idential to nlmsg_size() + nlmsg_padlen().
+ *
+ * @return Size of netlink message including padding.
+ */
+int nlmsg_total_size(int payload)
+{
+       return NLMSG_ALIGN(nlmsg_msg_size(payload));
+}
+
+/**
+ * Size of padding that needs to be added at end of message
+ * @arg payload                Length of payload
+ *
+ * Calculates the number of bytes of padding which is required to be added to
+ * the end of the message to ensure that the next netlink message header begins
+ * properly aligned to NLMSG_ALIGNTO.
+ *
+ * @return Number of bytes of padding needed.
+ */
+int nlmsg_padlen(int payload)
+{
+       return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
+}
+
+/** @} */
+
+/**
+ * @name Access to Message Payload
+ * @{
+ */
+
+/**
+ * Return pointer to message payload
+ * @arg nlh            Netlink message header
+ *
+ * @return Pointer to start of message payload.
+ */
+void *nlmsg_data(const struct nlmsghdr *nlh)
+{
+       return (unsigned char *) nlh + NLMSG_HDRLEN;
+}
+
+void *nlmsg_tail(const struct nlmsghdr *nlh)
+{
+       return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
+}
+
+/**
+ * Return length of message payload
+ * @arg nlh            Netlink message header
+ *
+ * @return Length of message payload in bytes.
+ */
+int nlmsg_datalen(const struct nlmsghdr *nlh)
+{
+       return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+static int nlmsg_len(const struct nlmsghdr *nlh)
+{
+       return nlmsg_datalen(nlh);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * head of attributes data
+ * @arg nlh            netlink message header
+ * @arg hdrlen         length of family specific header
+ */
+struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
+{
+       unsigned char *data = nlmsg_data(nlh);
+       return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
+}
+
+/**
+ * length of attributes data
+ * @arg nlh            netlink message header
+ * @arg hdrlen         length of family specific header
+ */
+int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
+{
+       return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/** @} */
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
+{
+       if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
+               return 0;
+
+       return 1;
+}
+
+/**
+ * check if the netlink message fits into the remaining bytes
+ * @arg nlh            netlink message header
+ * @arg remaining      number of bytes remaining in message stream
+ */
+int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
+{
+       return (remaining >= (int)sizeof(struct nlmsghdr) &&
+               nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
+               nlh->nlmsg_len <= remaining);
+}
+
+/**
+ * next netlink message in message stream
+ * @arg nlh            netlink message header
+ * @arg remaining      number of bytes remaining in message stream
+ *
+ * @returns the next netlink message in the message stream and
+ * decrements remaining by the size of the current message.
+ */
+struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
+{
+       int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
+
+       *remaining -= totlen;
+
+       return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
+}
+
+/**
+ * parse attributes of a netlink message
+ * @arg nlh            netlink message header
+ * @arg hdrlen         length of family specific header
+ * @arg tb             destination array with maxtype+1 elements
+ * @arg maxtype                maximum attribute type to be expected
+ * @arg policy         validation policy
+ *
+ * See nla_parse()
+ */
+int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+               int maxtype, struct nla_policy *policy)
+{
+       if (!nlmsg_valid_hdr(nlh, hdrlen))
+               return -NLE_MSG_TOOSHORT;
+
+       return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
+                        nlmsg_attrlen(nlh, hdrlen), policy);
+}
+
+/**
+ * nlmsg_find_attr - find a specific attribute in a netlink message
+ * @arg nlh            netlink message header
+ * @arg hdrlen         length of familiy specific header
+ * @arg attrtype       type of attribute to look for
+ *
+ * Returns the first attribute which matches the specified type.
+ */
+struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
+{
+       return nla_find(nlmsg_attrdata(nlh, hdrlen),
+                       nlmsg_attrlen(nlh, hdrlen), attrtype);
+}
+
+/**
+ * nlmsg_validate - validate a netlink message including attributes
+ * @arg nlh            netlinket message header
+ * @arg hdrlen         length of familiy specific header
+ * @arg maxtype                maximum attribute type to be expected
+ * @arg policy         validation policy
+ */
+int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
+                  struct nla_policy *policy)
+{
+       if (!nlmsg_valid_hdr(nlh, hdrlen))
+               return -NLE_MSG_TOOSHORT;
+
+       return nla_validate(nlmsg_attrdata(nlh, hdrlen),
+                           nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
+}
+
+/** @} */
+
+/**
+ * @name Message Building/Access
+ * @{
+ */
+
+static struct nl_msg *__nlmsg_alloc(size_t len)
+{
+       struct nl_msg *nm;
+
+       if (len < sizeof(struct nlmsghdr))
+               len = sizeof(struct nlmsghdr);
+
+       nm = calloc(1, sizeof(*nm));
+       if (!nm)
+               goto errout;
+
+       nm->nm_refcnt = 1;
+
+       nm->nm_nlh = calloc(1, len);
+       if (!nm->nm_nlh)
+               goto errout;
+
+       memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr));
+
+       nm->nm_protocol = -1;
+       nm->nm_size = len;
+       nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
+
+       NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
+
+       return nm;
+errout:
+       free(nm);
+       return NULL;
+}
+
+/**
+ * Allocate a new netlink message with the default maximum payload size.
+ *
+ * Allocates a new netlink message without any further payload. The
+ * maximum payload size defaults to PAGESIZE or as otherwise specified
+ * with nlmsg_set_default_size().
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_alloc(void)
+{
+       return __nlmsg_alloc(default_msg_size);
+}
+
+/**
+ * Allocate a new netlink message with maximum payload size specified.
+ */
+struct nl_msg *nlmsg_alloc_size(size_t max)
+{
+       return __nlmsg_alloc(max);
+}
+
+/**
+ * Allocate a new netlink message and inherit netlink message header
+ * @arg hdr            Netlink message header template
+ *
+ * Allocates a new netlink message and inherits the original message
+ * header. If \a hdr is not NULL it will be used as a template for
+ * the netlink message header, otherwise the header is left blank.
+ * 
+ * @return Newly allocated netlink message or NULL
+ */ 
+struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
+{
+       struct nl_msg *nm;
+
+       nm = nlmsg_alloc();
+       if (nm && hdr) {
+               struct nlmsghdr *new = nm->nm_nlh;
+
+               new->nlmsg_type = hdr->nlmsg_type;
+               new->nlmsg_flags = hdr->nlmsg_flags;
+               new->nlmsg_seq = hdr->nlmsg_seq;
+               new->nlmsg_pid = hdr->nlmsg_pid;
+       }
+
+       return nm;
+}
+
+/**
+ * Allocate a new netlink message
+ * @arg nlmsgtype      Netlink message type
+ * @arg flags          Message flags.
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
+{
+       struct nl_msg *msg;
+       struct nlmsghdr nlh = {
+               .nlmsg_type = nlmsgtype,
+               .nlmsg_flags = flags,
+       };
+
+       msg = nlmsg_inherit(&nlh);
+       if (msg)
+               NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
+
+       return msg;
+}
+
+/**
+ * Set the default maximum message payload size for allocated messages
+ * @arg max            Size of payload in bytes.
+ */
+void nlmsg_set_default_size(size_t max)
+{
+       if (max < nlmsg_total_size(0))
+               max = nlmsg_total_size(0);
+
+       default_msg_size = max;
+}
+
+/**
+ * Convert a netlink message received from a netlink socket to a nl_msg
+ * @arg hdr            Netlink message received from netlink socket.
+ *
+ * Allocates a new netlink message and copies all of the data pointed to
+ * by \a hdr into the new message object.
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
+{
+       struct nl_msg *nm;
+
+       nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
+       if (!nm)
+               goto errout;
+
+       memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
+
+       return nm;
+errout:
+       nlmsg_free(nm);
+       return NULL;
+}
+
+/**
+ * Reserve room for additional data in a netlink message
+ * @arg n              netlink message
+ * @arg len            length of additional data to reserve room for
+ * @arg pad            number of bytes to align data to
+ *
+ * Reserves room for additional data at the tail of the an
+ * existing netlink message. Eventual padding required will
+ * be zeroed out.
+ *
+ * @return Pointer to start of additional data tailroom or NULL.
+ */
+void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
+{
+       void *buf = n->nm_nlh;
+       size_t nlmsg_len = n->nm_nlh->nlmsg_len;
+       size_t tlen;
+
+       tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
+
+       if ((tlen + nlmsg_len) > n->nm_size)
+               return NULL;
+
+       buf += nlmsg_len;
+       n->nm_nlh->nlmsg_len += tlen;
+
+       if (tlen > len)
+               memset(buf + len, 0, tlen - len);
+
+       NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n",
+                 n, tlen, len, pad, n->nm_nlh->nlmsg_len);
+
+       return buf;
+}
+
+/**
+ * Append data to tail of a netlink message
+ * @arg n              netlink message
+ * @arg data           data to add
+ * @arg len            length of data
+ * @arg pad            Number of bytes to align data to.
+ *
+ * Extends the netlink message as needed and appends the data of given
+ * length to the message. 
+ *
+ * @return 0 on success or a negative error code
+ */
+int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
+{
+       void *tmp;
+
+       tmp = nlmsg_reserve(n, len, pad);
+       if (tmp == NULL)
+               return -NLE_NOMEM;
+
+       memcpy(tmp, data, len);
+       NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
+
+       return 0;
+}
+
+/**
+ * Expand maximum payload size of a netlink message
+ * @arg n              Netlink message.
+ * @arg newlen         New maximum payload size.
+ *
+ * Reallocates the payload section of a netlink message and increases
+ * the maximum payload size of the message.
+ *
+ * @note Any pointers pointing to old payload block will be stale and
+ *       need to be refetched. Therfore, do not expand while constructing
+ *       nested attributes or while reserved data blocks are held.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nlmsg_expand(struct nl_msg *n, size_t newlen)
+{
+       void *tmp;
+
+       if (newlen <= n->nm_size)
+               return -NLE_INVAL;
+
+       tmp = realloc(n->nm_nlh, newlen);
+       if (tmp == NULL)
+               return -NLE_NOMEM;
+
+       n->nm_nlh = tmp;
+       n->nm_size = newlen;
+
+       return 0;
+}
+
+/**
+ * Add a netlink message header to a netlink message
+ * @arg n              netlink message
+ * @arg pid            netlink process id or NL_AUTO_PID
+ * @arg seq            sequence number of message or NL_AUTO_SEQ
+ * @arg type           message type
+ * @arg payload                length of message payload
+ * @arg flags          message flags
+ *
+ * Adds or overwrites the netlink message header in an existing message
+ * object. If \a payload is greater-than zero additional room will be
+ * reserved, f.e. for family specific headers. It can be accesed via
+ * nlmsg_data().
+ *
+ * @return A pointer to the netlink message header or NULL.
+ */
+struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
+                          int type, int payload, int flags)
+{
+       struct nlmsghdr *nlh;
+
+       if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
+               BUG();
+
+       nlh = (struct nlmsghdr *) n->nm_nlh;
+       nlh->nlmsg_type = type;
+       nlh->nlmsg_flags = flags;
+       nlh->nlmsg_pid = pid;
+       nlh->nlmsg_seq = seq;
+
+       NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
+                 "seq=%d\n", n, type, flags, pid, seq);
+
+       if (payload > 0 &&
+           nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
+               return NULL;
+
+       return nlh;
+}
+
+/**
+ * Return actual netlink message
+ * @arg n              netlink message
+ * 
+ * Returns the actual netlink message casted to the type of the netlink
+ * message header.
+ * 
+ * @return A pointer to the netlink message.
+ */
+struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
+{
+       return n->nm_nlh;
+}
+
+/**
+ * Acquire a reference on a netlink message
+ * @arg msg            message to acquire reference from
+ */
+void nlmsg_get(struct nl_msg *msg)
+{
+       msg->nm_refcnt++;
+       NL_DBG(4, "New reference to message %p, total %d\n",
+              msg, msg->nm_refcnt);
+}
+
+/**
+ * Release a reference from an netlink message
+ * @arg msg            message to release reference from
+ *
+ * Frees memory after the last reference has been released.
+ */
+void nlmsg_free(struct nl_msg *msg)
+{
+       if (!msg)
+               return;
+
+       msg->nm_refcnt--;
+       NL_DBG(4, "Returned message reference %p, %d remaining\n",
+              msg, msg->nm_refcnt);
+
+       if (msg->nm_refcnt < 0)
+               BUG();
+
+       if (msg->nm_refcnt <= 0) {
+               free(msg->nm_nlh);
+               free(msg);
+               NL_DBG(2, "msg %p: Freed\n", msg);
+       }
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nlmsg_set_proto(struct nl_msg *msg, int protocol)
+{
+       msg->nm_protocol = protocol;
+}
+
+int nlmsg_get_proto(struct nl_msg *msg)
+{
+       return msg->nm_protocol;
+}
+
+size_t nlmsg_get_max_size(struct nl_msg *msg)
+{
+       return msg->nm_size;
+}
+
+void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
+{
+       memcpy(&msg->nm_src, addr, sizeof(*addr));
+}
+
+struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
+{
+       return &msg->nm_src;
+}
+
+void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
+{
+       memcpy(&msg->nm_dst, addr, sizeof(*addr));
+}
+
+struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
+{
+       return &msg->nm_dst;
+}
+
+void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
+{
+       memcpy(&msg->nm_creds, creds, sizeof(*creds));
+       msg->nm_flags |= NL_MSG_CRED_PRESENT;
+}
+
+struct ucred *nlmsg_get_creds(struct nl_msg *msg)
+{
+       if (msg->nm_flags & NL_MSG_CRED_PRESENT)
+               return &msg->nm_creds;
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Netlink Message Type Translations
+ * @{
+ */
+
+static const struct trans_tbl nl_msgtypes[] = {
+       __ADD(NLMSG_NOOP,NOOP)
+       __ADD(NLMSG_ERROR,ERROR)
+       __ADD(NLMSG_DONE,DONE)
+       __ADD(NLMSG_OVERRUN,OVERRUN)
+};
+
+char *nl_nlmsgtype2str(int type, char *buf, size_t size)
+{
+       return __type2str(type, buf, size, nl_msgtypes,
+                         ARRAY_SIZE(nl_msgtypes));
+}
+
+int nl_str2nlmsgtype(const char *name)
+{
+       return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
+}
+
+/** @} */
+
+/**
+ * @name Netlink Message Flags Translations
+ * @{
+ */
+
+char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
+{
+       memset(buf, 0, len);
+
+#define PRINT_FLAG(f) \
+       if (flags & NLM_F_##f) { \
+               flags &= ~NLM_F_##f; \
+               strncat(buf, #f, len - strlen(buf) - 1); \
+               if (flags) \
+                       strncat(buf, ",", len - strlen(buf) - 1); \
+       }
+       
+       PRINT_FLAG(REQUEST);
+       PRINT_FLAG(MULTI);
+       PRINT_FLAG(ACK);
+       PRINT_FLAG(ECHO);
+       PRINT_FLAG(ROOT);
+       PRINT_FLAG(MATCH);
+       PRINT_FLAG(ATOMIC);
+       PRINT_FLAG(REPLACE);
+       PRINT_FLAG(EXCL);
+       PRINT_FLAG(CREATE);
+       PRINT_FLAG(APPEND);
+
+       if (flags) {
+               char s[32];
+               snprintf(s, sizeof(s), "0x%x", flags);
+               strncat(buf, s, len - strlen(buf) - 1);
+       }
+#undef PRINT_FLAG
+
+       return buf;
+}
+
+/** @} */
+
+/**
+ * @name Direct Parsing
+ * @{
+ */
+
+/** @cond SKIP */
+struct dp_xdata {
+       void (*cb)(struct nl_object *, void *);
+       void *arg;
+};
+/** @endcond */
+
+static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
+{
+       struct dp_xdata *x = p->pp_arg;
+
+       x->cb(obj, x->arg);
+       return 0;
+}
+
+int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
+                void *arg)
+{
+       struct nl_cache_ops *ops;
+       struct nl_parser_param p = {
+               .pp_cb = parse_cb
+       };
+       struct dp_xdata x = {
+               .cb = cb,
+               .arg = arg,
+       };
+       int err;
+
+       ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg),
+                                         nlmsg_hdr(msg)->nlmsg_type);
+       if (ops == NULL)
+               return -NLE_MSGTYPE_NOSUPPORT;
+       p.pp_arg = &x;
+
+       err = nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
+       nl_cache_ops_put(ops);
+
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Dumping
+ * @{
+ */
+
+static void prefix_line(FILE *ofd, int prefix)
+{
+       int i;
+
+       for (i = 0; i < prefix; i++)
+               fprintf(ofd, "  ");
+}
+
+static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
+{
+       int i, a, c, limit;
+       char ascii[21] = {0};
+
+       limit = 16 - (prefix * 2);
+       prefix_line(ofd, prefix);
+       fprintf(ofd, "    ");
+
+       for (i = 0, a = 0, c = 0; i < len; i++) {
+               int v = *(uint8_t *) (start + i);
+
+               fprintf(ofd, "%02x ", v);
+               ascii[a++] = isprint(v) ? v : '.';
+
+               if (++c >= limit) {
+                       fprintf(ofd, "%s\n", ascii);
+                       if (i < (len - 1)) {
+                               prefix_line(ofd, prefix);
+                               fprintf(ofd, "    ");
+                       }
+                       a = c = 0;
+                       memset(ascii, 0, sizeof(ascii));
+               }
+       }
+
+       if (c != 0) {
+               for (i = 0; i < (limit - c); i++)
+                       fprintf(ofd, "   ");
+               fprintf(ofd, "%s\n", ascii);
+       }
+}
+
+static void print_hdr(FILE *ofd, struct nl_msg *msg)
+{
+       struct nlmsghdr *nlh = nlmsg_hdr(msg);
+       struct nl_cache_ops *ops;
+       struct nl_msgtype *mt;
+       char buf[128];
+
+       fprintf(ofd, "    .nlmsg_len = %d\n", nlh->nlmsg_len);
+
+       ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg), nlh->nlmsg_type);
+       if (ops) {
+               mt = nl_msgtype_lookup(ops, nlh->nlmsg_type);
+               if (!mt)
+                       BUG();
+
+               snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name);
+               nl_cache_ops_put(ops);
+       } else
+               nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf));
+
+       fprintf(ofd, "    .type = %d <%s>\n", nlh->nlmsg_type, buf);
+       fprintf(ofd, "    .flags = %d <%s>\n", nlh->nlmsg_flags,
+               nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
+       fprintf(ofd, "    .seq = %d\n", nlh->nlmsg_seq);
+       fprintf(ofd, "    .port = %d\n", nlh->nlmsg_pid);
+
+}
+
+static void print_genl_hdr(FILE *ofd, void *start)
+{
+       struct genlmsghdr *ghdr = start;
+
+       fprintf(ofd, "  [GENERIC NETLINK HEADER] %zu octets\n", GENL_HDRLEN);
+       fprintf(ofd, "    .cmd = %u\n", ghdr->cmd);
+       fprintf(ofd, "    .version = %u\n", ghdr->version);
+       fprintf(ofd, "    .unused = %#x\n", ghdr->reserved);
+}
+
+static void *print_genl_msg(struct nl_msg *msg, FILE *ofd, struct nlmsghdr *hdr,
+                           struct nl_cache_ops *ops, int *payloadlen)
+{
+       void *data = nlmsg_data(hdr);
+
+       if (*payloadlen < GENL_HDRLEN)
+               return data;
+
+       print_genl_hdr(ofd, data);
+
+       *payloadlen -= GENL_HDRLEN;
+       data += GENL_HDRLEN;
+
+       if (ops) {
+               int hdrsize = ops->co_hdrsize - GENL_HDRLEN;
+
+               if (hdrsize > 0) {
+                       if (*payloadlen < hdrsize)
+                               return data;
+
+                       fprintf(ofd, "  [HEADER] %d octets\n", hdrsize);
+                       dump_hex(ofd, data, hdrsize, 0);
+
+                       *payloadlen -= hdrsize;
+                       data += hdrsize;
+               }
+       }
+
+       return data;
+}
+
+static void dump_attr(FILE *ofd, struct nlattr *attr, int prefix)
+{
+       int len = nla_len(attr);
+
+       dump_hex(ofd, nla_data(attr), len, prefix);
+}
+
+static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
+                      int prefix)
+{
+       int rem;
+       struct nlattr *nla;
+
+       nla_for_each_attr(nla, attrs, attrlen, rem) {
+               int padlen, alen = nla_len(nla);
+
+               prefix_line(ofd, prefix);
+
+               if (nla->nla_type == 0)
+                       fprintf(ofd, "  [ATTR PADDING] %d octets\n", alen);
+               else
+                       fprintf(ofd, "  [ATTR %02d%s] %d octets\n", nla_type(nla),
+                               nla_is_nested(nla) ? " NESTED" : "",
+                               alen);
+
+               if (nla_is_nested(nla))
+                       dump_attrs(ofd, nla_data(nla), alen, prefix+1);
+               else
+                       dump_attr(ofd, nla, prefix);
+
+               padlen = nla_padlen(alen);
+               if (padlen > 0) {
+                       prefix_line(ofd, prefix);
+                       fprintf(ofd, "  [PADDING] %d octets\n",
+                               padlen);
+                       dump_hex(ofd, nla_data(nla) + alen,
+                                padlen, prefix);
+               }
+       }
+
+       if (rem) {
+               prefix_line(ofd, prefix);
+               fprintf(ofd, "  [LEFTOVER] %d octets\n", rem);
+       }
+}
+
+static void dump_error_msg(struct nl_msg *msg, FILE *ofd)
+{
+       struct nlmsghdr *hdr = nlmsg_hdr(msg);
+       struct nlmsgerr *err = nlmsg_data(hdr);
+
+       fprintf(ofd, "  [ERRORMSG] %zu octets\n", sizeof(*err));
+
+       if (nlmsg_len(hdr) >= sizeof(*err)) {
+               char buf[256];
+               struct nl_msg *errmsg;
+
+               fprintf(ofd, "    .error = %d \"%s\"\n", err->error,
+                       strerror_r(-err->error, buf, sizeof(buf)));
+               fprintf(ofd, "  [ORIGINAL MESSAGE] %zu octets\n", sizeof(*hdr));
+
+               errmsg = nlmsg_inherit(&err->msg);
+               print_hdr(ofd, errmsg);
+               nlmsg_free(errmsg);
+       }
+}
+
+static void print_msg(struct nl_msg *msg, FILE *ofd, struct nlmsghdr *hdr)
+{
+       struct nl_cache_ops *ops;
+       int payloadlen = nlmsg_len(hdr);
+       int attrlen = 0;
+       void *data;
+
+       data = nlmsg_data(hdr);
+       ops = nl_cache_ops_associate_safe(nlmsg_get_proto(msg),
+                                         hdr->nlmsg_type);
+       if (ops) {
+               attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
+               payloadlen -= attrlen;
+       }
+
+       if (msg->nm_protocol == NETLINK_GENERIC)
+               data = print_genl_msg(msg, ofd, hdr, ops, &payloadlen);
+
+       if (payloadlen) {
+               fprintf(ofd, "  [PAYLOAD] %d octets\n", payloadlen);
+               dump_hex(ofd, data, payloadlen, 0);
+       }
+
+       if (attrlen) {
+               struct nlattr *attrs;
+               int attrlen;
+               
+               attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
+               attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
+               dump_attrs(ofd, attrs, attrlen, 0);
+       }
+
+       if (ops)
+               nl_cache_ops_put(ops);
+}
+
+/**
+ * Dump message in human readable format to file descriptor
+ * @arg msg            Message to print
+ * @arg ofd            File descriptor.
+ */
+void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
+{
+       struct nlmsghdr *hdr = nlmsg_hdr(msg);
+       
+       fprintf(ofd, 
+       "--------------------------   BEGIN NETLINK MESSAGE ---------------------------\n");
+
+       fprintf(ofd, "  [NETLINK HEADER] %zu octets\n", sizeof(struct nlmsghdr));
+       print_hdr(ofd, msg);
+
+       if (hdr->nlmsg_type == NLMSG_ERROR)
+               dump_error_msg(msg, ofd);
+       else if (nlmsg_len(hdr) > 0)
+               print_msg(msg, ofd, hdr);
+
+       fprintf(ofd, 
+       "---------------------------  END NETLINK MESSAGE   ---------------------------\n");
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/netfilter/ct.c b/lib/netfilter/ct.c
new file mode 100644 (file)
index 0000000..794932f
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * lib/netfilter/ct.c  Conntrack
+ *
+ *     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) 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>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup ct Conntrack
+ * @brief
+ * @{
+ */
+
+#include <byteswap.h>
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/ct.h>
+
+static struct nl_cache_ops nfnl_ct_ops;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+       return x;
+}
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+       return bswap_64(x);
+}
+#endif
+
+static struct nla_policy ct_policy[CTA_MAX+1] = {
+       [CTA_TUPLE_ORIG]        = { .type = NLA_NESTED },
+       [CTA_TUPLE_REPLY]       = { .type = NLA_NESTED },
+       [CTA_STATUS]            = { .type = NLA_U32 },
+       [CTA_PROTOINFO]         = { .type = NLA_NESTED },
+       //[CTA_HELP]
+       //[CTA_NAT_SRC]
+       [CTA_TIMEOUT]           = { .type = NLA_U32 },
+       [CTA_MARK]              = { .type = NLA_U32 },
+       [CTA_COUNTERS_ORIG]     = { .type = NLA_NESTED },
+       [CTA_COUNTERS_REPLY]    = { .type = NLA_NESTED },
+       [CTA_USE]               = { .type = NLA_U32 },
+       [CTA_ID]                = { .type = NLA_U32 },
+       //[CTA_NAT_DST]
+};
+
+static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
+       [CTA_TUPLE_IP]          = { .type = NLA_NESTED },
+       [CTA_TUPLE_PROTO]       = { .type = NLA_NESTED },
+};
+
+static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
+       [CTA_IP_V4_SRC]         = { .type = NLA_U32 },
+       [CTA_IP_V4_DST]         = { .type = NLA_U32 },
+       [CTA_IP_V6_SRC]         = { .minlen = 16 },
+       [CTA_IP_V6_DST]         = { .minlen = 16 },
+};
+
+static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
+       [CTA_PROTO_NUM]         = { .type = NLA_U8 },
+       [CTA_PROTO_SRC_PORT]    = { .type = NLA_U16 },
+       [CTA_PROTO_DST_PORT]    = { .type = NLA_U16 },
+       [CTA_PROTO_ICMP_ID]     = { .type = NLA_U16 },
+       [CTA_PROTO_ICMP_TYPE]   = { .type = NLA_U8 },
+       [CTA_PROTO_ICMP_CODE]   = { .type = NLA_U8 },
+       [CTA_PROTO_ICMPV6_ID]   = { .type = NLA_U16 },
+       [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
+       [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
+};
+
+static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
+       [CTA_PROTOINFO_TCP]     = { .type = NLA_NESTED },
+};
+
+static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
+       [CTA_PROTOINFO_TCP_STATE]               = { .type = NLA_U8 },
+       [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]     = { .type = NLA_U8 },
+       [CTA_PROTOINFO_TCP_WSCALE_REPLY]        = { .type = NLA_U8 },
+       [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]      = { .minlen = 2 },
+       [CTA_PROTOINFO_TCP_FLAGS_REPLY]         = { .minlen = 2 },
+
+};
+
+static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
+       [CTA_COUNTERS_PACKETS]  = { .type = NLA_U64 },
+       [CTA_COUNTERS_BYTES]    = { .type = NLA_U64 },
+       [CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
+       [CTA_COUNTERS32_BYTES]  = { .type = NLA_U32 },
+};
+
+static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_IP_MAX+1];
+       struct nl_addr *addr;
+       int err;
+
+        err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
+       if (err < 0)
+               goto errout;
+
+       if (tb[CTA_IP_V4_SRC]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_ct_set_src(ct, repl, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_IP_V4_DST]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_ct_set_dst(ct, repl, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_IP_V6_SRC]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_ct_set_src(ct, repl, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_IP_V6_DST]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_ct_set_dst(ct, repl, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+
+       return 0;
+
+errout_enomem:
+       err = -NLE_NOMEM;
+errout:
+       return err;
+}
+
+static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_PROTO_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
+       if (err < 0)
+               return err;
+
+       if (!repl && tb[CTA_PROTO_NUM])
+               nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
+       if (tb[CTA_PROTO_SRC_PORT])
+               nfnl_ct_set_src_port(ct, repl,
+                       ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
+       if (tb[CTA_PROTO_DST_PORT])
+               nfnl_ct_set_dst_port(ct, repl,
+                       ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
+
+       if (ct->ct_family == AF_INET) {
+               if (tb[CTA_PROTO_ICMP_ID])
+                       nfnl_ct_set_icmp_id(ct, repl,
+                               ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
+               if (tb[CTA_PROTO_ICMP_TYPE])
+                       nfnl_ct_set_icmp_type(ct, repl,
+                               nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
+               if (tb[CTA_PROTO_ICMP_CODE])
+                       nfnl_ct_set_icmp_code(ct, repl,
+                               nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
+       } else if (ct->ct_family == AF_INET6) {
+               if (tb[CTA_PROTO_ICMPV6_ID])
+                       nfnl_ct_set_icmp_id(ct, repl,
+                           ntohs(nla_get_u16(tb[CTA_PROTO_ICMPV6_ID])));
+               if (tb[CTA_PROTO_ICMPV6_TYPE])
+                       nfnl_ct_set_icmp_type(ct, repl,
+                               nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]));
+               if (tb[CTA_PROTO_ICMPV6_CODE])
+                       nfnl_ct_set_icmp_code(ct, repl,
+                               nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]));
+       }
+
+       return 0;
+}
+
+static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_TUPLE_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[CTA_TUPLE_IP]) {
+               err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
+               if (err < 0)
+                       return err;
+       }
+
+       if (tb[CTA_TUPLE_PROTO]) {
+               err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
+                              ct_protoinfo_tcp_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[CTA_PROTOINFO_TCP_STATE])
+               nfnl_ct_set_tcp_state(ct,
+                               nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
+
+       return 0;
+}
+
+static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_PROTOINFO_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
+                              ct_protoinfo_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[CTA_PROTOINFO_TCP]) {
+               err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_COUNTERS_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[CTA_COUNTERS_PACKETS])
+               nfnl_ct_set_packets(ct, repl,
+                       ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
+       if (tb[CTA_COUNTERS32_PACKETS])
+               nfnl_ct_set_packets(ct, repl,
+                       ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
+       if (tb[CTA_COUNTERS_BYTES])
+               nfnl_ct_set_bytes(ct, repl,
+                       ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
+       if (tb[CTA_COUNTERS32_BYTES])
+               nfnl_ct_set_bytes(ct, repl,
+                       ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
+
+       return 0;
+}
+
+int nfnlmsg_ct_group(struct nlmsghdr *nlh)
+{
+       switch (nfnlmsg_subtype(nlh)) {
+       case IPCTNL_MSG_CT_NEW:
+               if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
+                       return NFNLGRP_CONNTRACK_NEW;
+               else
+                       return NFNLGRP_CONNTRACK_UPDATE;
+       case IPCTNL_MSG_CT_DELETE:
+               return NFNLGRP_CONNTRACK_DESTROY;
+       default:
+               return NFNLGRP_NONE;
+       }
+}
+
+int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
+{
+       struct nfnl_ct *ct;
+       struct nlattr *tb[CTA_MAX+1];
+       int err;
+
+       ct = nfnl_ct_alloc();
+       if (!ct)
+               return -NLE_NOMEM;
+
+       ct->ce_msgtype = nlh->nlmsg_type;
+
+       err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
+                         ct_policy);
+       if (err < 0)
+               goto errout;
+
+       nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
+
+       if (tb[CTA_TUPLE_ORIG]) {
+               err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_TUPLE_REPLY]) {
+               err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
+               if (err < 0)
+                       goto errout;
+       }
+
+       if (tb[CTA_PROTOINFO]) {
+               err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
+               if (err < 0)
+                       goto errout;
+       }
+
+       if (tb[CTA_STATUS])
+               nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
+       if (tb[CTA_TIMEOUT])
+               nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
+       if (tb[CTA_MARK])
+               nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
+       if (tb[CTA_USE])
+               nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
+       if (tb[CTA_ID])
+               nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
+
+       if (tb[CTA_COUNTERS_ORIG]) {
+               err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
+               if (err < 0)
+                       goto errout;
+       }
+
+       if (tb[CTA_COUNTERS_REPLY]) {
+               err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
+               if (err < 0)
+                       goto errout;
+       }
+
+       *result = ct;
+       return 0;
+
+errout:
+       nfnl_ct_put(ct);
+       return err;
+}
+
+static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                        struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct nfnl_ct *ct;
+       int err;
+
+       if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
+               goto errout;
+
+       err = pp->pp_cb((struct nl_object *) ct, pp);
+errout:
+       nfnl_ct_put(ct);
+       return err;
+}
+
+int nfnl_ct_dump_request(struct nl_sock *sk)
+{
+       return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
+                               NLM_F_DUMP, AF_UNSPEC, 0);
+}
+
+static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+       return nfnl_ct_dump_request(sk);
+}
+
+static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
+                              int repl)
+{
+       struct nlattr *tuple, *ip, *proto;
+       struct nl_addr *addr;
+       int family;
+
+       family = nfnl_ct_get_family(ct);
+
+       tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
+       if (!tuple)
+               goto nla_put_failure;
+
+       ip = nla_nest_start(msg, CTA_TUPLE_IP);
+       if (!ip)
+               goto nla_put_failure;
+
+       addr = nfnl_ct_get_src(ct, repl);
+       if (addr)
+               NLA_PUT_ADDR(msg,
+                            family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
+                            addr);
+
+       addr = nfnl_ct_get_dst(ct, repl);
+       if (addr)
+               NLA_PUT_ADDR(msg,
+                            family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
+                            addr);
+
+       nla_nest_end(msg, ip);
+
+       proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
+       if (!proto)
+               goto nla_put_failure;
+
+       if (nfnl_ct_test_proto(ct))
+               NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
+
+       if (nfnl_ct_test_src_port(ct, repl))
+               NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
+                       htons(nfnl_ct_get_src_port(ct, repl)));
+
+       if (nfnl_ct_test_dst_port(ct, repl))
+               NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
+                       htons(nfnl_ct_get_dst_port(ct, repl)));
+
+       if (family == AF_INET) {
+               if (nfnl_ct_test_icmp_id(ct, repl))
+                       NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
+                                               htons(nfnl_ct_get_icmp_id(ct, repl)));
+
+               if (nfnl_ct_test_icmp_type(ct, repl))
+                       NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
+                                          nfnl_ct_get_icmp_type(ct, repl));
+
+               if (nfnl_ct_test_icmp_code(ct, repl))
+                       NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
+                                          nfnl_ct_get_icmp_code(ct, repl));
+       } else if (family == AF_INET6) {
+               if (nfnl_ct_test_icmp_id(ct, repl))
+                       NLA_PUT_U16(msg, CTA_PROTO_ICMPV6_ID,
+                                               htons(nfnl_ct_get_icmp_id(ct, repl)));
+
+               if (nfnl_ct_test_icmp_type(ct, repl))
+                       NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_TYPE,
+                                          nfnl_ct_get_icmp_type(ct, repl));
+
+               if (nfnl_ct_test_icmp_code(ct, repl))
+                       NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_CODE,
+                                          nfnl_ct_get_icmp_code(ct, repl));
+       }
+
+       nla_nest_end(msg, proto);
+
+       nla_nest_end(msg, tuple);
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+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 -NLE_NOMEM;
+
+       if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
+               goto err_out;
+
+       *result = msg;
+       return 0;
+
+err_out:
+       nlmsg_free(msg);
+       return err;
+}
+
+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, result);
+}
+
+int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+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, result);
+}
+
+int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+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, result);
+}
+
+int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Build a conntrack cache holding all conntrack currently in the kernel
+ * @arg sk             Netlink socket.
+ * @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.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+       return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
+}
+
+/** @} */
+
+/**
+ * @name Conntrack Addition
+ * @{
+ */
+
+/** @} */
+
+static struct nl_af_group ct_groups[] = {
+       { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
+       { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
+       { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
+       { END_OF_GROUP_LIST },
+};
+
+#define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
+static struct nl_cache_ops nfnl_ct_ops = {
+       .co_name                = "netfilter/ct",
+       .co_hdrsize             = NFNL_HDRLEN,
+       .co_msgtypes            = {
+               { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
+               { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
+               { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
+               END_OF_MSGTYPES_LIST,
+       },
+       .co_protocol            = NETLINK_NETFILTER,
+       .co_groups              = ct_groups,
+       .co_request_update      = ct_request_update,
+       .co_msg_parser          = ct_msg_parser,
+       .co_obj_ops             = &ct_obj_ops,
+};
+
+static void __init ct_init(void)
+{
+       nl_cache_mngt_register(&nfnl_ct_ops);
+}
+
+static void __exit ct_exit(void)
+{
+       nl_cache_mngt_unregister(&nfnl_ct_ops);
+}
+
+/** @} */
diff --git a/lib/netfilter/ct_obj.c b/lib/netfilter/ct_obj.c
new file mode 100644 (file)
index 0000000..bac775b
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ * lib/netfilter/ct_obj.c      Conntrack Object
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/ct.h>
+
+/** @cond SKIP */
+#define CT_ATTR_FAMILY         (1UL << 0)
+#define CT_ATTR_PROTO          (1UL << 1)
+
+#define CT_ATTR_TCP_STATE      (1UL << 2)
+
+#define CT_ATTR_STATUS         (1UL << 3)
+#define CT_ATTR_TIMEOUT                (1UL << 4)
+#define CT_ATTR_MARK           (1UL << 5)
+#define CT_ATTR_USE            (1UL << 6)
+#define CT_ATTR_ID             (1UL << 7)
+
+#define CT_ATTR_ORIG_SRC       (1UL << 8)
+#define CT_ATTR_ORIG_DST       (1UL << 9)
+#define CT_ATTR_ORIG_SRC_PORT  (1UL << 10)
+#define CT_ATTR_ORIG_DST_PORT  (1UL << 11)
+#define CT_ATTR_ORIG_ICMP_ID   (1UL << 12)
+#define CT_ATTR_ORIG_ICMP_TYPE (1UL << 13)
+#define CT_ATTR_ORIG_ICMP_CODE (1UL << 14)
+#define CT_ATTR_ORIG_PACKETS   (1UL << 15)
+#define CT_ATTR_ORIG_BYTES     (1UL << 16)
+
+#define CT_ATTR_REPL_SRC       (1UL << 17)
+#define CT_ATTR_REPL_DST       (1UL << 18)
+#define CT_ATTR_REPL_SRC_PORT  (1UL << 19)
+#define CT_ATTR_REPL_DST_PORT  (1UL << 20)
+#define CT_ATTR_REPL_ICMP_ID   (1UL << 21)
+#define CT_ATTR_REPL_ICMP_TYPE (1UL << 22)
+#define CT_ATTR_REPL_ICMP_CODE (1UL << 23)
+#define CT_ATTR_REPL_PACKETS   (1UL << 24)
+#define CT_ATTR_REPL_BYTES     (1UL << 25)
+/** @endcond */
+
+static void ct_free_data(struct nl_object *c)
+{
+       struct nfnl_ct *ct = (struct nfnl_ct *) c;
+
+       if (ct == NULL)
+               return;
+
+       nl_addr_put(ct->ct_orig.src);
+       nl_addr_put(ct->ct_orig.dst);
+       nl_addr_put(ct->ct_repl.src);
+       nl_addr_put(ct->ct_repl.dst);
+}
+
+static int ct_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct nfnl_ct *dst = (struct nfnl_ct *) _dst;
+       struct nfnl_ct *src = (struct nfnl_ct *) _src;
+       struct nl_addr *addr;
+
+       if (src->ct_orig.src) {
+               addr = nl_addr_clone(src->ct_orig.src);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->ct_orig.src = addr;
+       }
+
+       if (src->ct_orig.dst) {
+               addr = nl_addr_clone(src->ct_orig.dst);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->ct_orig.dst = addr;
+       }
+
+       if (src->ct_repl.src) {
+               addr = nl_addr_clone(src->ct_repl.src);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->ct_repl.src = addr;
+       }
+
+       if (src->ct_repl.dst) {
+               addr = nl_addr_clone(src->ct_repl.dst);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->ct_repl.dst = addr;
+       }
+
+       return 0;
+}
+
+static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port)
+{
+       char buf[64];
+
+       if (addr)
+               nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf)));
+
+       if (port)
+               nl_dump(p, ":%u ", port);
+       else if (addr)
+               nl_dump(p, " ");
+}
+
+static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int reply)
+{
+       if (nfnl_ct_test_icmp_type(ct, reply))
+               nl_dump(p, "icmp type %d ", nfnl_ct_get_icmp_type(ct, reply));
+
+       if (nfnl_ct_test_icmp_code(ct, reply))
+               nl_dump(p, "code %d ", nfnl_ct_get_icmp_code(ct, reply));
+
+       if (nfnl_ct_test_icmp_id(ct, reply))
+               nl_dump(p, "id %d ", nfnl_ct_get_icmp_id(ct, reply));
+}
+
+static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p)
+{
+       struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst;
+       int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0;
+       int sync = 0;
+
+       orig_src = nfnl_ct_get_src(ct, 0);
+       orig_dst = nfnl_ct_get_dst(ct, 0);
+       reply_src = nfnl_ct_get_src(ct, 1);
+       reply_dst = nfnl_ct_get_dst(ct, 1);
+
+       if (nfnl_ct_test_src_port(ct, 0))
+               orig_sport = nfnl_ct_get_src_port(ct, 0);
+
+       if (nfnl_ct_test_dst_port(ct, 0))
+               orig_dport = nfnl_ct_get_dst_port(ct, 0);
+
+       if (nfnl_ct_test_src_port(ct, 1))
+               reply_sport = nfnl_ct_get_src_port(ct, 1);
+
+       if (nfnl_ct_test_dst_port(ct, 1))
+               reply_dport = nfnl_ct_get_dst_port(ct, 1);
+
+       if (orig_src && orig_dst && reply_src && reply_dst &&
+           orig_sport == reply_dport && orig_dport == reply_sport &&
+           !nl_addr_cmp(orig_src, reply_dst) &&
+           !nl_addr_cmp(orig_dst, reply_src))
+               sync = 1;
+
+       dump_addr(p, orig_src, orig_sport);
+       nl_dump(p, sync ? "<-> " : "-> ");
+       dump_addr(p, orig_dst, orig_dport);
+       dump_icmp(p, ct, 0);
+
+       if (!sync) {
+               dump_addr(p, reply_src, reply_sport);
+               nl_dump(p, "<- ");
+               dump_addr(p, reply_dst, reply_dport);
+               dump_icmp(p, ct, 1);
+       }
+}
+
+/* Compatible with /proc/net/nf_conntrack */
+static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_ct *ct = (struct nfnl_ct *) a;
+       char buf[64];
+
+       nl_new_line(p);
+
+       if (nfnl_ct_test_proto(ct))
+               nl_dump(p, "%s ",
+                 nl_ip_proto2str(nfnl_ct_get_proto(ct), buf, sizeof(buf)));
+
+       if (nfnl_ct_test_tcp_state(ct))
+               nl_dump(p, "%s ",
+                       nfnl_ct_tcp_state2str(nfnl_ct_get_tcp_state(ct),
+                                             buf, sizeof(buf)));
+
+       ct_dump_tuples(ct, p);
+
+       if (nfnl_ct_test_mark(ct) && nfnl_ct_get_mark(ct))
+               nl_dump(p, "mark %u ", nfnl_ct_get_mark(ct));
+
+       nl_dump(p, "\n");
+}
+
+static void ct_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_ct *ct = (struct nfnl_ct *) a;
+       char buf[64];
+       int fp = 0;
+
+       ct_dump_line(a, p);
+
+       nl_dump(p, "    id 0x%x ", ct->ct_id);
+       nl_dump_line(p, "family %s ",
+               nl_af2str(ct->ct_family, buf, sizeof(buf)));
+
+       if (nfnl_ct_test_use(ct))
+               nl_dump(p, "refcnt %u ", nfnl_ct_get_use(ct));
+
+       if (nfnl_ct_test_timeout(ct)) {
+               uint64_t timeout_ms = nfnl_ct_get_timeout(ct) * 1000UL;
+               nl_dump(p, "timeout %s ",
+                       nl_msec2str(timeout_ms, buf, sizeof(buf)));
+       }
+
+       if (ct->ct_status)
+               nl_dump(p, "<");
+
+#define PRINT_FLAG(str) \
+       { nl_dump(p, "%s%s", fp++ ? "," : "", (str)); }
+
+       if (ct->ct_status & IPS_EXPECTED)
+               PRINT_FLAG("EXPECTED");
+       if (!(ct->ct_status & IPS_SEEN_REPLY))
+               PRINT_FLAG("NOREPLY");
+       if (ct->ct_status & IPS_ASSURED)
+               PRINT_FLAG("ASSURED");
+       if (!(ct->ct_status & IPS_CONFIRMED))
+               PRINT_FLAG("NOTSENT");
+       if (ct->ct_status & IPS_SRC_NAT)
+               PRINT_FLAG("SNAT");
+       if (ct->ct_status & IPS_DST_NAT)
+               PRINT_FLAG("DNAT");
+       if (ct->ct_status & IPS_SEQ_ADJUST)
+               PRINT_FLAG("SEQADJUST");
+       if (!(ct->ct_status & IPS_SRC_NAT_DONE))
+               PRINT_FLAG("SNAT_INIT");
+       if (!(ct->ct_status & IPS_DST_NAT_DONE))
+               PRINT_FLAG("DNAT_INIT");
+       if (ct->ct_status & IPS_DYING)
+               PRINT_FLAG("DYING");
+       if (ct->ct_status & IPS_FIXED_TIMEOUT)
+               PRINT_FLAG("FIXED_TIMEOUT");
+#undef PRINT_FLAG
+
+       if (ct->ct_status)
+               nl_dump(p, ">");
+       nl_dump(p, "\n");
+}
+
+static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_ct *ct = (struct nfnl_ct *) a;
+       double res;
+       char *unit;
+       uint64_t packets;
+       const char * const names[] = {"rx", "tx"};
+       int i;
+
+       ct_dump_details(a, p);
+
+       if (!nfnl_ct_test_bytes(ct, 0) ||
+           !nfnl_ct_test_packets(ct, 0) ||
+           !nfnl_ct_test_bytes(ct, 1) ||
+           !nfnl_ct_test_packets(ct, 1))
+           {
+               nl_dump_line(p, "    Statistics are not available.\n");
+               nl_dump_line(p, "    Please set sysctl net.netfilter.nf_conntrack_acct=1\n");
+               nl_dump_line(p, "    (Require kernel 2.6.27)\n");
+               return;
+           }
+
+       nl_dump_line(p, "        # packets      volume\n");
+       for (i=0; i<=1; i++) {
+               res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, i), &unit);
+               packets = nfnl_ct_get_packets(ct, i);
+               nl_dump_line(p, "    %s %10" PRIu64  " %7.2f %s\n", names[i], packets, res, unit);
+       }
+}
+
+static int ct_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       struct nfnl_ct *a = (struct nfnl_ct *) _a;
+       struct nfnl_ct *b = (struct nfnl_ct *) _b;
+       int diff = 0;
+
+#define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR)
+#define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD)
+#define CT_DIFF_ADDR(ATTR, FIELD) \
+       ((flags & LOOSE_COMPARISON) \
+               ? CT_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \
+               : CT_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD)))
+
+       diff |= CT_DIFF_VAL(FAMILY,             ct_family);
+       diff |= CT_DIFF_VAL(PROTO,              ct_proto);
+       diff |= CT_DIFF_VAL(TCP_STATE,          ct_protoinfo.tcp.state);
+       diff |= CT_DIFF_VAL(TIMEOUT,            ct_timeout);
+       diff |= CT_DIFF_VAL(MARK,               ct_mark);
+       diff |= CT_DIFF_VAL(USE,                ct_use);
+       diff |= CT_DIFF_VAL(ID,                 ct_id);
+       diff |= CT_DIFF_ADDR(ORIG_SRC,          ct_orig.src);
+       diff |= CT_DIFF_ADDR(ORIG_DST,          ct_orig.dst);
+       diff |= CT_DIFF_VAL(ORIG_SRC_PORT,      ct_orig.proto.port.src);
+       diff |= CT_DIFF_VAL(ORIG_DST_PORT,      ct_orig.proto.port.dst);
+       diff |= CT_DIFF_VAL(ORIG_ICMP_ID,       ct_orig.proto.icmp.id);
+       diff |= CT_DIFF_VAL(ORIG_ICMP_TYPE,     ct_orig.proto.icmp.type);
+       diff |= CT_DIFF_VAL(ORIG_ICMP_CODE,     ct_orig.proto.icmp.code);
+       diff |= CT_DIFF_VAL(ORIG_PACKETS,       ct_orig.packets);
+       diff |= CT_DIFF_VAL(ORIG_BYTES,         ct_orig.bytes);
+       diff |= CT_DIFF_ADDR(REPL_SRC,          ct_repl.src);
+       diff |= CT_DIFF_ADDR(REPL_DST,          ct_repl.dst);
+       diff |= CT_DIFF_VAL(REPL_SRC_PORT,      ct_repl.proto.port.src);
+       diff |= CT_DIFF_VAL(REPL_DST_PORT,      ct_repl.proto.port.dst);
+       diff |= CT_DIFF_VAL(REPL_ICMP_ID,       ct_repl.proto.icmp.id);
+       diff |= CT_DIFF_VAL(REPL_ICMP_TYPE,     ct_repl.proto.icmp.type);
+       diff |= CT_DIFF_VAL(REPL_ICMP_CODE,     ct_repl.proto.icmp.code);
+       diff |= CT_DIFF_VAL(REPL_PACKETS,       ct_repl.packets);
+       diff |= CT_DIFF_VAL(REPL_BYTES,         ct_repl.bytes);
+
+       if (flags & LOOSE_COMPARISON)
+               diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) &
+                                       b->ct_status_mask);
+       else
+               diff |= CT_DIFF(STATUS, a->ct_status != b->ct_status);
+
+#undef CT_DIFF
+#undef CT_DIFF_VAL
+#undef CT_DIFF_ADDR
+
+       return diff;
+}
+
+static const struct trans_tbl ct_attrs[] = {
+       __ADD(CT_ATTR_FAMILY,           family)
+       __ADD(CT_ATTR_PROTO,            proto)
+       __ADD(CT_ATTR_TCP_STATE,        tcpstate)
+       __ADD(CT_ATTR_STATUS,           status)
+       __ADD(CT_ATTR_TIMEOUT,          timeout)
+       __ADD(CT_ATTR_MARK,             mark)
+       __ADD(CT_ATTR_USE,              use)
+       __ADD(CT_ATTR_ID,               id)
+       __ADD(CT_ATTR_ORIG_SRC,         origsrc)
+       __ADD(CT_ATTR_ORIG_DST,         origdst)
+       __ADD(CT_ATTR_ORIG_SRC_PORT,    origsrcport)
+       __ADD(CT_ATTR_ORIG_DST_PORT,    origdstport)
+       __ADD(CT_ATTR_ORIG_ICMP_ID,     origicmpid)
+       __ADD(CT_ATTR_ORIG_ICMP_TYPE,   origicmptype)
+       __ADD(CT_ATTR_ORIG_ICMP_CODE,   origicmpcode)
+       __ADD(CT_ATTR_ORIG_PACKETS,     origpackets)
+       __ADD(CT_ATTR_ORIG_BYTES,       origbytes)
+       __ADD(CT_ATTR_REPL_SRC,         replysrc)
+       __ADD(CT_ATTR_REPL_DST,         replydst)
+       __ADD(CT_ATTR_REPL_SRC_PORT,    replysrcport)
+       __ADD(CT_ATTR_REPL_DST_PORT,    replydstport)
+       __ADD(CT_ATTR_REPL_ICMP_ID,     replyicmpid)
+       __ADD(CT_ATTR_REPL_ICMP_TYPE,   replyicmptype)
+       __ADD(CT_ATTR_REPL_ICMP_CODE,   replyicmpcode)
+       __ADD(CT_ATTR_REPL_PACKETS,     replypackets)
+       __ADD(CT_ATTR_REPL_BYTES,       replybytes)
+};
+
+static char *ct_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, ct_attrs, ARRAY_SIZE(ct_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_ct *nfnl_ct_alloc(void)
+{
+       return (struct nfnl_ct *) nl_object_alloc(&ct_obj_ops);
+}
+
+void nfnl_ct_get(struct nfnl_ct *ct)
+{
+       nl_object_get((struct nl_object *) ct);
+}
+
+void nfnl_ct_put(struct nfnl_ct *ct)
+{
+       nl_object_put((struct nl_object *) ct);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_ct_set_family(struct nfnl_ct *ct, uint8_t family)
+{
+       ct->ct_family = family;
+       ct->ce_mask |= CT_ATTR_FAMILY;
+}
+
+uint8_t nfnl_ct_get_family(const struct nfnl_ct *ct)
+{
+       if (ct->ce_mask & CT_ATTR_FAMILY)
+               return ct->ct_family;
+       else
+               return AF_UNSPEC;
+}
+
+void nfnl_ct_set_proto(struct nfnl_ct *ct, uint8_t proto)
+{
+       ct->ct_proto = proto;
+       ct->ce_mask |= CT_ATTR_PROTO;
+}
+
+int nfnl_ct_test_proto(const struct nfnl_ct *ct)
+{
+       return !!(ct->ce_mask & CT_ATTR_PROTO);
+}
+
+uint8_t nfnl_ct_get_proto(const struct nfnl_ct *ct)
+{
+       return ct->ct_proto;
+}
+
+void nfnl_ct_set_tcp_state(struct nfnl_ct *ct, uint8_t state)
+{
+       ct->ct_protoinfo.tcp.state = state;
+       ct->ce_mask |= CT_ATTR_TCP_STATE;
+}
+
+int nfnl_ct_test_tcp_state(const struct nfnl_ct *ct)
+{
+       return !!(ct->ce_mask & CT_ATTR_TCP_STATE);
+}
+
+uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *ct)
+{
+       return ct->ct_protoinfo.tcp.state;
+}
+
+static const struct trans_tbl tcp_states[] = {
+       __ADD(TCP_CONNTRACK_NONE,NONE)
+       __ADD(TCP_CONNTRACK_SYN_SENT,SYN_SENT)
+       __ADD(TCP_CONNTRACK_SYN_RECV,SYN_RECV)
+       __ADD(TCP_CONNTRACK_ESTABLISHED,ESTABLISHED)
+       __ADD(TCP_CONNTRACK_FIN_WAIT,FIN_WAIT)
+       __ADD(TCP_CONNTRACK_CLOSE_WAIT,CLOSE_WAIT)
+       __ADD(TCP_CONNTRACK_LAST_ACK,LAST_ACK)
+       __ADD(TCP_CONNTRACK_TIME_WAIT,TIME_WAIT)
+       __ADD(TCP_CONNTRACK_CLOSE,CLOSE)
+       __ADD(TCP_CONNTRACK_LISTEN,LISTEN)
+};
+
+char *nfnl_ct_tcp_state2str(uint8_t state, char *buf, size_t len)
+{
+       return __type2str(state, buf, len, tcp_states, ARRAY_SIZE(tcp_states));
+}
+
+int nfnl_ct_str2tcp_state(const char *name)
+{
+        return __str2type(name, tcp_states, ARRAY_SIZE(tcp_states));
+}
+
+void nfnl_ct_set_status(struct nfnl_ct *ct, uint32_t status)
+{
+       ct->ct_status_mask |= status;
+       ct->ct_status |= status;
+       ct->ce_mask |= CT_ATTR_STATUS;
+}
+
+void nfnl_ct_unset_status(struct nfnl_ct *ct, uint32_t status)
+{
+       ct->ct_status_mask |= status;
+       ct->ct_status &= ~status;
+       ct->ce_mask |= CT_ATTR_STATUS;
+}
+
+uint32_t nfnl_ct_get_status(const struct nfnl_ct *ct)
+{
+       return ct->ct_status;
+}
+
+static const struct trans_tbl status_flags[] = {
+       __ADD(IPS_EXPECTED, expected)
+       __ADD(IPS_SEEN_REPLY, seen_reply)
+       __ADD(IPS_ASSURED, assured)
+       __ADD(IPS_CONFIRMED, confirmed)
+       __ADD(IPS_SRC_NAT, snat)
+       __ADD(IPS_DST_NAT, dnat)
+       __ADD(IPS_SEQ_ADJUST, seqadjust)
+       __ADD(IPS_SRC_NAT_DONE, snat_done)
+       __ADD(IPS_DST_NAT_DONE, dnat_done)
+       __ADD(IPS_DYING, dying)
+       __ADD(IPS_FIXED_TIMEOUT, fixed_timeout)
+};
+
+char * nfnl_ct_status2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, status_flags,
+                          ARRAY_SIZE(status_flags));
+}
+
+int nfnl_ct_str2status(const char *name)
+{
+       return __str2flags(name, status_flags, ARRAY_SIZE(status_flags));
+}
+
+void nfnl_ct_set_timeout(struct nfnl_ct *ct, uint32_t timeout)
+{
+       ct->ct_timeout = timeout;
+       ct->ce_mask |= CT_ATTR_TIMEOUT;
+}
+
+int nfnl_ct_test_timeout(const struct nfnl_ct *ct)
+{
+       return !!(ct->ce_mask & CT_ATTR_TIMEOUT);
+}
+
+uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *ct)
+{
+       return ct->ct_timeout;
+}
+
+void nfnl_ct_set_mark(struct nfnl_ct *ct, uint32_t mark)
+{
+       ct->ct_mark = mark;
+       ct->ce_mask |= CT_ATTR_MARK;
+}
+
+int nfnl_ct_test_mark(const struct nfnl_ct *ct)
+{
+       return !!(ct->ce_mask & CT_ATTR_MARK);
+}
+
+uint32_t nfnl_ct_get_mark(const struct nfnl_ct *ct)
+{
+       return ct->ct_mark;
+}
+
+void nfnl_ct_set_use(struct nfnl_ct *ct, uint32_t use)
+{
+       ct->ct_use = use;
+       ct->ce_mask |= CT_ATTR_USE;
+}
+
+int nfnl_ct_test_use(const struct nfnl_ct *ct)
+{
+       return !!(ct->ce_mask & CT_ATTR_USE);
+}
+
+uint32_t nfnl_ct_get_use(const struct nfnl_ct *ct)
+{
+       return ct->ct_use;
+}
+
+void nfnl_ct_set_id(struct nfnl_ct *ct, uint32_t id)
+{
+       ct->ct_id = id;
+       ct->ce_mask |= CT_ATTR_ID;
+}
+
+int nfnl_ct_test_id(const struct nfnl_ct *ct)
+{
+       return !!(ct->ce_mask & CT_ATTR_ID);
+}
+
+uint32_t nfnl_ct_get_id(const struct nfnl_ct *ct)
+{
+       return ct->ct_id;
+}
+
+static int ct_set_addr(struct nfnl_ct *ct, struct nl_addr *addr,
+               int attr, struct nl_addr ** ct_addr)
+{
+       if (ct->ce_mask & CT_ATTR_FAMILY) {
+               if (addr->a_family != ct->ct_family)
+                       return -NLE_AF_MISMATCH;
+       } else
+               nfnl_ct_set_family(ct, addr->a_family);
+
+       if (*ct_addr)
+               nl_addr_put(*ct_addr);
+
+       nl_addr_get(addr);
+       *ct_addr = addr;
+       ct->ce_mask |= attr;
+
+       return 0;
+}
+
+int nfnl_ct_set_src(struct nfnl_ct *ct, int repl, struct nl_addr *addr)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
+       return ct_set_addr(ct, addr, attr, &dir->src);
+}
+
+int nfnl_ct_set_dst(struct nfnl_ct *ct, int repl, struct nl_addr *addr)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
+       return ct_set_addr(ct, addr, attr, &dir->dst);
+}
+
+struct nl_addr *nfnl_ct_get_src(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
+       if (!(ct->ce_mask & attr))
+               return NULL;
+       return dir->src;
+}
+
+struct nl_addr *nfnl_ct_get_dst(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
+       if (!(ct->ce_mask & attr))
+               return NULL;
+       return dir->dst;
+}
+
+void nfnl_ct_set_src_port(struct nfnl_ct *ct, int repl, uint16_t port)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
+
+       dir->proto.port.src = port;
+       ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_src_port(const struct nfnl_ct *ct, int repl)
+{
+       int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
+       return !!(ct->ce_mask & attr);
+}
+
+uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+       return dir->proto.port.src;
+}
+
+void nfnl_ct_set_dst_port(struct nfnl_ct *ct, int repl, uint16_t port)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
+
+       dir->proto.port.dst = port;
+       ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_dst_port(const struct nfnl_ct *ct, int repl)
+{
+       int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
+       return !!(ct->ce_mask & attr);
+}
+
+uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+       return dir->proto.port.dst;
+}
+
+void nfnl_ct_set_icmp_id(struct nfnl_ct *ct, int repl, uint16_t id)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
+
+       dir->proto.icmp.id = id;
+       ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_icmp_id(const struct nfnl_ct *ct, int repl)
+{
+       int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
+       return !!(ct->ce_mask & attr);
+}
+
+uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+       return dir->proto.icmp.id;
+}
+
+void nfnl_ct_set_icmp_type(struct nfnl_ct *ct, int repl, uint8_t type)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
+
+       dir->proto.icmp.type = type;
+       ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_icmp_type(const struct nfnl_ct *ct, int repl)
+{
+       int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
+       return !!(ct->ce_mask & attr);
+}
+
+uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+       return dir->proto.icmp.type;
+}
+
+void nfnl_ct_set_icmp_code(struct nfnl_ct *ct, int repl, uint8_t code)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
+
+       dir->proto.icmp.code = code;
+       ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_icmp_code(const struct nfnl_ct *ct, int repl)
+{
+       int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
+       return !!(ct->ce_mask & attr);
+}
+
+uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+       return dir->proto.icmp.code;
+}
+
+void nfnl_ct_set_packets(struct nfnl_ct *ct, int repl, uint64_t packets)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS;
+
+       dir->packets = packets;
+       ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_packets(const struct nfnl_ct *ct, int repl)
+{
+       int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS;
+       return !!(ct->ce_mask & attr);
+}
+
+uint64_t nfnl_ct_get_packets(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+       return dir->packets;
+}
+
+void nfnl_ct_set_bytes(struct nfnl_ct *ct, int repl, uint64_t bytes)
+{
+       struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+       int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES;
+
+       dir->bytes = bytes;
+       ct->ce_mask |= attr;
+}
+
+int nfnl_ct_test_bytes(const struct nfnl_ct *ct, int repl)
+{
+       int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES;
+       return !!(ct->ce_mask & attr);
+}
+
+uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *ct, int repl)
+{
+       const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
+
+       return dir->bytes;
+}
+
+/** @} */
+
+struct nl_object_ops ct_obj_ops = {
+       .oo_name                = "netfilter/ct",
+       .oo_size                = sizeof(struct nfnl_ct),
+       .oo_free_data           = ct_free_data,
+       .oo_clone               = ct_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = ct_dump_line,
+           [NL_DUMP_DETAILS]   = ct_dump_details,
+           [NL_DUMP_STATS]     = ct_dump_stats,
+       },
+       .oo_compare             = ct_compare,
+       .oo_attrs2str           = ct_attrs2str,
+};
+
+/** @} */
diff --git a/lib/netfilter/exp.c b/lib/netfilter/exp.c
new file mode 100644 (file)
index 0000000..86ed8d1
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * lib/netfilter/exp.c Conntrack Expectation
+ *
+ *     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) 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>
+ * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup exp Expectation
+ * @brief
+ * @{
+ */
+
+#include <byteswap.h>
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/exp.h>
+
+static struct nl_cache_ops nfnl_exp_ops;
+
+static struct nla_policy exp_policy[CTA_EXPECT_MAX+1] = {
+       [CTA_EXPECT_MASTER]     = { .type = NLA_NESTED },
+       [CTA_EXPECT_TUPLE]      = { .type = NLA_NESTED },
+       [CTA_EXPECT_MASK]       = { .type = NLA_NESTED },
+       [CTA_EXPECT_TIMEOUT]    = { .type = NLA_U32 },
+       [CTA_EXPECT_ID]         = { .type = NLA_U32 },
+       [CTA_EXPECT_HELP_NAME]  = { .type = NLA_STRING },
+       [CTA_EXPECT_ZONE]       = { .type = NLA_U16 },
+       [CTA_EXPECT_FLAGS]      = { .type = NLA_U32 },    // Added in kernel 2.6.37
+       [CTA_EXPECT_CLASS]      = { .type = NLA_U32 },    // Added in kernel 3.5
+       [CTA_EXPECT_NAT]        = { .type = NLA_NESTED }, // Added in kernel 3.5
+       [CTA_EXPECT_FN]         = { .type = NLA_STRING }, // Added in kernel 3.5
+};
+
+static struct nla_policy exp_tuple_policy[CTA_TUPLE_MAX+1] = {
+       [CTA_TUPLE_IP]          = { .type = NLA_NESTED },
+       [CTA_TUPLE_PROTO]       = { .type = NLA_NESTED },
+};
+
+static struct nla_policy exp_ip_policy[CTA_IP_MAX+1] = {
+       [CTA_IP_V4_SRC]         = { .type = NLA_U32 },
+       [CTA_IP_V4_DST]         = { .type = NLA_U32 },
+       [CTA_IP_V6_SRC]         = { .minlen = 16 },
+       [CTA_IP_V6_DST]         = { .minlen = 16 },
+};
+
+static struct nla_policy exp_proto_policy[CTA_PROTO_MAX+1] = {
+       [CTA_PROTO_NUM]         = { .type = NLA_U8 },
+       [CTA_PROTO_SRC_PORT]    = { .type = NLA_U16 },
+       [CTA_PROTO_DST_PORT]    = { .type = NLA_U16 },
+       [CTA_PROTO_ICMP_ID]     = { .type = NLA_U16 },
+       [CTA_PROTO_ICMP_TYPE]   = { .type = NLA_U8 },
+       [CTA_PROTO_ICMP_CODE]   = { .type = NLA_U8 },
+       [CTA_PROTO_ICMPV6_ID]   = { .type = NLA_U16 },
+       [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
+       [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
+};
+
+static struct nla_policy exp_nat_policy[CTA_EXPECT_NAT_MAX+1] = {
+       [CTA_EXPECT_NAT_DIR]    = { .type = NLA_U32 },
+       [CTA_EXPECT_NAT_TUPLE]  = { .type = NLA_NESTED },
+};
+
+static int exp_parse_ip(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_IP_MAX+1];
+       struct nl_addr *addr;
+       int err;
+
+       err = nla_parse_nested(tb, CTA_IP_MAX, attr, exp_ip_policy);
+       if (err < 0)
+               goto errout;
+
+       if (tb[CTA_IP_V4_SRC]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_exp_set_src(exp, tuple, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_IP_V4_DST]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_exp_set_dst(exp, tuple, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_IP_V6_SRC]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_exp_set_src(exp, tuple, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_IP_V6_DST]) {
+               addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
+               if (addr == NULL)
+                       goto errout_enomem;
+               err = nfnl_exp_set_dst(exp, tuple, addr);
+               nl_addr_put(addr);
+               if (err < 0)
+                       goto errout;
+       }
+
+       return 0;
+
+errout_enomem:
+       err = -NLE_NOMEM;
+errout:
+       return err;
+}
+
+static int exp_parse_proto(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_PROTO_MAX+1];
+       int err;
+       uint16_t srcport = 0, dstport = 0, icmpid = 0;
+       uint8_t icmptype = 0, icmpcode = 0;
+
+       err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, exp_proto_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[CTA_PROTO_NUM])
+               nfnl_exp_set_l4protonum(exp, tuple, nla_get_u8(tb[CTA_PROTO_NUM]));
+
+       if (tb[CTA_PROTO_SRC_PORT])
+               srcport = ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT]));
+       if (tb[CTA_PROTO_DST_PORT])
+               dstport = ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT]));
+       if (tb[CTA_PROTO_SRC_PORT] || tb[CTA_PROTO_DST_PORT])
+               nfnl_exp_set_ports(exp, tuple, srcport, dstport);
+
+       if (tb[CTA_PROTO_ICMP_ID])
+               icmpid = ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID]));
+       if (tb[CTA_PROTO_ICMP_TYPE])
+               icmptype = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]);
+       if (tb[CTA_PROTO_ICMP_CODE])
+               icmpcode = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]);
+       if (tb[CTA_PROTO_ICMP_ID] || tb[CTA_PROTO_ICMP_TYPE] || tb[CTA_PROTO_ICMP_CODE])
+               nfnl_exp_set_icmp(exp, tuple, icmpid, icmptype, icmpcode);
+       return 0;
+}
+
+static int exp_parse_tuple(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_TUPLE_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, exp_tuple_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[CTA_TUPLE_IP]) {
+               err = exp_parse_ip(exp, tuple, tb[CTA_TUPLE_IP]);
+               if (err < 0)
+                       return err;
+       }
+
+       if (tb[CTA_TUPLE_PROTO]) {
+               err = exp_parse_proto(exp, tuple, tb[CTA_TUPLE_PROTO]);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int exp_parse_nat(struct nfnl_exp *exp, struct nlattr *attr)
+{
+       struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[CTA_EXPECT_NAT_DIR])
+               nfnl_exp_set_nat_dir(exp, nla_get_u32(tb[CTA_EXPECT_NAT_DIR]));
+
+       if (tb[CTA_EXPECT_NAT_TUPLE]) {
+               err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_NAT, tb[CTA_EXPECT_NAT_TUPLE]);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+int nfnlmsg_exp_group(struct nlmsghdr *nlh)
+{
+       switch (nfnlmsg_subtype(nlh)) {
+       case IPCTNL_MSG_EXP_NEW:
+               if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
+                       return NFNLGRP_CONNTRACK_EXP_NEW;
+               else
+                       return NFNLGRP_CONNTRACK_EXP_UPDATE;
+       case IPCTNL_MSG_EXP_DELETE:
+               return NFNLGRP_CONNTRACK_EXP_DESTROY;
+       default:
+               return NFNLGRP_NONE;
+       }
+}
+
+int nfnlmsg_exp_parse(struct nlmsghdr *nlh, struct nfnl_exp **result)
+{
+       struct nfnl_exp *exp;
+       struct nlattr *tb[CTA_MAX+1];
+       int err;
+
+       exp = nfnl_exp_alloc();
+       if (!exp)
+               return -NLE_NOMEM;
+
+       exp->ce_msgtype = nlh->nlmsg_type;
+
+       err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_EXPECT_MAX,
+                         exp_policy);
+       if (err < 0)
+               goto errout;
+
+       nfnl_exp_set_family(exp, nfnlmsg_family(nlh));
+
+       if (tb[CTA_EXPECT_TUPLE]) {
+               err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_EXPECT, tb[CTA_EXPECT_TUPLE]);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_EXPECT_MASTER]) {
+               err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASTER, tb[CTA_EXPECT_MASTER]);
+               if (err < 0)
+                       goto errout;
+       }
+       if (tb[CTA_EXPECT_MASK]) {
+               err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASK, tb[CTA_EXPECT_MASK]);
+               if (err < 0)
+                       goto errout;
+       }
+
+       if (tb[CTA_EXPECT_NAT]) {
+               err = exp_parse_nat(exp, tb[CTA_EXPECT_MASK]);
+               if (err < 0)
+                       goto errout;
+       }
+
+       if (tb[CTA_EXPECT_CLASS])
+               nfnl_exp_set_class(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_CLASS])));
+
+       if (tb[CTA_EXPECT_FN])
+               nfnl_exp_set_fn(exp, nla_data(tb[CTA_EXPECT_FN]));
+
+       if (tb[CTA_EXPECT_TIMEOUT])
+               nfnl_exp_set_timeout(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_TIMEOUT])));
+
+       if (tb[CTA_EXPECT_ID])
+               nfnl_exp_set_id(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_ID])));
+
+       if (tb[CTA_EXPECT_HELP_NAME])
+               nfnl_exp_set_helper_name(exp, nla_data(tb[CTA_EXPECT_HELP_NAME]));
+
+       if (tb[CTA_EXPECT_ZONE])
+               nfnl_exp_set_zone(exp, ntohs(nla_get_u16(tb[CTA_EXPECT_ZONE])));
+
+       if (tb[CTA_EXPECT_FLAGS])
+               nfnl_exp_set_flags(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_FLAGS])));
+
+       *result = exp;
+       return 0;
+
+errout:
+       nfnl_exp_put(exp);
+       return err;
+}
+
+static int exp_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                        struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct nfnl_exp *exp;
+       int err;
+
+       if ((err = nfnlmsg_exp_parse(nlh, &exp)) < 0)
+               goto errout;
+
+       err = pp->pp_cb((struct nl_object *) exp, pp);
+errout:
+       nfnl_exp_put(exp);
+       return err;
+}
+
+int nfnl_exp_dump_request(struct nl_sock *sk)
+{
+       return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET,
+                               NLM_F_DUMP, AF_UNSPEC, 0);
+}
+
+static int exp_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+       return nfnl_exp_dump_request(sk);
+}
+
+static int exp_get_tuple_attr(int tuple)
+{
+       int attr = 0;
+
+       switch (tuple) {
+               case CTA_EXPECT_MASTER:
+                       attr = NFNL_EXP_TUPLE_MASTER;
+                       break;
+               case CTA_EXPECT_MASK:
+                       attr = NFNL_EXP_TUPLE_MASK;
+                       break;
+               case CTA_EXPECT_NAT:
+                       attr = NFNL_EXP_TUPLE_NAT;
+                       break;
+               case CTA_EXPECT_TUPLE:
+               default :
+                       attr = NFNL_EXP_TUPLE_EXPECT;
+                       break;
+       }
+
+       return attr;
+}
+
+static int nfnl_exp_build_tuple(struct nl_msg *msg, const struct nfnl_exp *exp,
+                              int cta)
+{
+       struct nlattr *tuple, *ip, *proto;
+       struct nl_addr *addr;
+       int family;
+
+       family = nfnl_exp_get_family(exp);
+
+       int type = exp_get_tuple_attr(cta);
+
+    if (cta == CTA_EXPECT_NAT)
+        tuple = nla_nest_start(msg, CTA_EXPECT_NAT_TUPLE);
+    else
+        tuple = nla_nest_start(msg, cta);
+
+       if (!tuple)
+               goto nla_put_failure;
+
+       ip = nla_nest_start(msg, CTA_TUPLE_IP);
+       if (!ip)
+               goto nla_put_failure;
+
+       addr = nfnl_exp_get_src(exp, type);
+       if (addr)
+               NLA_PUT_ADDR(msg,
+                            family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
+                            addr);
+
+       addr = nfnl_exp_get_dst(exp, type);
+       if (addr)
+               NLA_PUT_ADDR(msg,
+                            family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
+                            addr);
+
+       nla_nest_end(msg, ip);
+
+       proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
+       if (!proto)
+               goto nla_put_failure;
+
+       if (nfnl_exp_test_l4protonum(exp, type))
+               NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_exp_get_l4protonum(exp, type));
+
+       if (nfnl_exp_test_ports(exp, type)) {
+               NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
+                       htons(nfnl_exp_get_src_port(exp, type)));
+
+               NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
+                       htons(nfnl_exp_get_dst_port(exp, type)));
+       }
+
+       if (nfnl_exp_test_icmp(exp, type)) {
+               NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
+                       htons(nfnl_exp_get_icmp_id(exp, type)));
+
+               NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
+                           nfnl_exp_get_icmp_type(exp, type));
+
+               NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
+                           nfnl_exp_get_icmp_code(exp, type));
+       }
+
+       nla_nest_end(msg, proto);
+
+       nla_nest_end(msg, tuple);
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+static int nfnl_exp_build_nat(struct nl_msg *msg, const struct nfnl_exp *exp)
+{
+       struct nlattr *nat;
+       int err;
+
+       nat = nla_nest_start(msg, CTA_EXPECT_NAT);
+
+       if (nfnl_exp_test_nat_dir(exp)) {
+               NLA_PUT_U32(msg, CTA_EXPECT_NAT_DIR,
+                               nfnl_exp_get_nat_dir(exp));
+       }
+
+       if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_NAT)) < 0)
+               goto nla_put_failure;
+
+       nla_nest_end(msg, nat);
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+static int nfnl_exp_build_message(const struct nfnl_exp *exp, int cmd, int flags,
+                                struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       int err;
+
+       msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK_EXP, cmd, flags,
+                                  nfnl_exp_get_family(exp), 0);
+       if (msg == NULL)
+               return -NLE_NOMEM;
+
+       if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_TUPLE)) < 0)
+               goto err_out;
+
+       if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASTER)) < 0)
+               goto err_out;
+
+       if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASK)) < 0)
+               goto err_out;
+
+       if (nfnl_exp_test_src(exp, NFNL_EXP_TUPLE_NAT)) {
+               if ((err = nfnl_exp_build_nat(msg, exp)) < 0)
+                       goto err_out;
+       }
+
+       if (nfnl_exp_test_class(exp))
+               NLA_PUT_U32(msg, CTA_EXPECT_CLASS, htonl(nfnl_exp_get_class(exp)));
+
+       if (nfnl_exp_test_fn(exp))
+               NLA_PUT_STRING(msg, CTA_EXPECT_FN, nfnl_exp_get_fn(exp));
+
+       if (nfnl_exp_test_id(exp))
+               NLA_PUT_U32(msg, CTA_EXPECT_ID, htonl(nfnl_exp_get_id(exp)));
+
+       if (nfnl_exp_test_timeout(exp))
+               NLA_PUT_U32(msg, CTA_EXPECT_TIMEOUT, htonl(nfnl_exp_get_timeout(exp)));
+
+       if (nfnl_exp_test_helper_name(exp))
+               NLA_PUT_STRING(msg, CTA_EXPECT_HELP_NAME, nfnl_exp_get_helper_name(exp));
+
+       if (nfnl_exp_test_zone(exp))
+               NLA_PUT_U16(msg, CTA_EXPECT_ZONE, htons(nfnl_exp_get_zone(exp)));
+
+       if (nfnl_exp_test_flags(exp))
+               NLA_PUT_U32(msg, CTA_EXPECT_FLAGS, htonl(nfnl_exp_get_flags(exp)));
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+err_out:
+       nlmsg_free(msg);
+       return err;
+}
+
+int nfnl_exp_build_add_request(const struct nfnl_exp *exp, int flags,
+                             struct nl_msg **result)
+{
+       return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_NEW, flags, result);
+}
+
+int nfnl_exp_add(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_exp_build_add_request(exp, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+int nfnl_exp_build_delete_request(const struct nfnl_exp *exp, int flags,
+                                struct nl_msg **result)
+{
+       return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_DELETE, flags, result);
+}
+
+int nfnl_exp_del(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_exp_build_delete_request(exp, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+int nfnl_exp_build_query_request(const struct nfnl_exp *exp, int flags,
+                               struct nl_msg **result)
+{
+       return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_GET, flags, result);
+}
+
+int nfnl_exp_query(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_exp_build_query_request(exp, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Build a expectation cache holding all expectations currently in the kernel
+ * @arg sk             Netlink socket.
+ * @arg result         Pointer to store resulting cache.
+ *
+ * Allocates a new cache, initializes it properly and updates it to
+ * contain all expectations currently in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nfnl_exp_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+       return nl_cache_alloc_and_fill(&nfnl_exp_ops, sk, result);
+}
+
+/** @} */
+
+/**
+ * @name Expectation Addition
+ * @{
+ */
+
+/** @} */
+
+static struct nl_af_group exp_groups[] = {
+       { AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_NEW },
+       { AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_UPDATE },
+       { AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_DESTROY },
+       { END_OF_GROUP_LIST },
+};
+
+#define NFNLMSG_EXP_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK_EXP, (type))
+static struct nl_cache_ops nfnl_exp_ops = {
+       .co_name                    = "netfilter/exp",
+       .co_hdrsize                 = NFNL_HDRLEN,
+       .co_msgtypes            = {
+               { NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_NEW), NL_ACT_NEW, "new" },
+               { NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_GET), NL_ACT_GET, "get" },
+               { NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_DELETE), NL_ACT_DEL, "del" },
+               END_OF_MSGTYPES_LIST,
+       },
+       .co_protocol            = NETLINK_NETFILTER,
+       .co_groups              = exp_groups,
+       .co_request_update      = exp_request_update,
+       .co_msg_parser          = exp_msg_parser,
+       .co_obj_ops             = &exp_obj_ops,
+};
+
+static void __init exp_init(void)
+{
+       nl_cache_mngt_register(&nfnl_exp_ops);
+}
+
+static void __exit exp_exit(void)
+{
+       nl_cache_mngt_unregister(&nfnl_exp_ops);
+}
+
+/** @} */
diff --git a/lib/netfilter/exp_obj.c b/lib/netfilter/exp_obj.c
new file mode 100644 (file)
index 0000000..69b4dd3
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ * lib/netfilter/exp_obj.c     Conntrack Expectation Object
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/exp.h>
+
+// The 32-bit attribute mask in the common object header isn't
+// big enough to handle all attributes of an expectation.  So
+// we'll for sure specify optional attributes + parent attributes
+// that are required for valid object comparison.  Comparison of
+// these parent attributes will include nested attributes.
+
+/** @cond SKIP */
+#define EXP_ATTR_FAMILY                        (1UL << 0) // 8-bit
+#define EXP_ATTR_TIMEOUT               (1UL << 1) // 32-bit
+#define EXP_ATTR_ID                    (1UL << 2) // 32-bit
+#define EXP_ATTR_HELPER_NAME           (1UL << 3) // string
+#define EXP_ATTR_ZONE                  (1UL << 4) // 16-bit
+#define EXP_ATTR_FLAGS                 (1UL << 5) // 32-bit
+#define EXP_ATTR_CLASS                 (1UL << 6) // 32-bit
+#define EXP_ATTR_FN                    (1UL << 7) // String
+// Tuples
+#define EXP_ATTR_EXPECT_IP_SRC         (1UL << 8)
+#define EXP_ATTR_EXPECT_IP_DST         (1UL << 9)
+#define EXP_ATTR_EXPECT_L4PROTO_NUM    (1UL << 10)
+#define EXP_ATTR_EXPECT_L4PROTO_PORTS  (1UL << 11)
+#define EXP_ATTR_EXPECT_L4PROTO_ICMP   (1UL << 12)
+#define EXP_ATTR_MASTER_IP_SRC         (1UL << 13)
+#define EXP_ATTR_MASTER_IP_DST         (1UL << 14)
+#define EXP_ATTR_MASTER_L4PROTO_NUM    (1UL << 15)
+#define EXP_ATTR_MASTER_L4PROTO_PORTS  (1UL << 16)
+#define EXP_ATTR_MASTER_L4PROTO_ICMP   (1UL << 17)
+#define EXP_ATTR_MASK_IP_SRC           (1UL << 18)
+#define EXP_ATTR_MASK_IP_DST           (1UL << 19)
+#define EXP_ATTR_MASK_L4PROTO_NUM      (1UL << 20)
+#define EXP_ATTR_MASK_L4PROTO_PORTS    (1UL << 21)
+#define EXP_ATTR_MASK_L4PROTO_ICMP     (1UL << 22)
+#define EXP_ATTR_NAT_IP_SRC            (1UL << 23)
+#define EXP_ATTR_NAT_IP_DST            (1UL << 24)
+#define EXP_ATTR_NAT_L4PROTO_NUM       (1UL << 25)
+#define EXP_ATTR_NAT_L4PROTO_PORTS     (1UL << 26)
+#define EXP_ATTR_NAT_L4PROTO_ICMP      (1UL << 27)
+#define EXP_ATTR_NAT_DIR               (1UL << 28)
+/** @endcond */
+
+static void exp_free_data(struct nl_object *c)
+{
+       struct nfnl_exp *exp = (struct nfnl_exp *) c;
+
+       if (exp == NULL)
+               return;
+
+       nl_addr_put(exp->exp_expect.src);
+       nl_addr_put(exp->exp_expect.dst);
+       nl_addr_put(exp->exp_master.src);
+       nl_addr_put(exp->exp_master.dst);
+       nl_addr_put(exp->exp_mask.src);
+       nl_addr_put(exp->exp_mask.dst);
+       nl_addr_put(exp->exp_nat.src);
+       nl_addr_put(exp->exp_nat.dst);
+
+       free(exp->exp_fn);
+       free(exp->exp_helper_name);
+}
+
+static int exp_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct nfnl_exp *dst = (struct nfnl_exp *) _dst;
+       struct nfnl_exp *src = (struct nfnl_exp *) _src;
+       struct nl_addr *addr;
+
+       // Expectation
+       if (src->exp_expect.src) {
+               addr = nl_addr_clone(src->exp_expect.src);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_expect.src = addr;
+       }
+
+       if (src->exp_expect.dst) {
+               addr = nl_addr_clone(src->exp_expect.dst);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_expect.dst = addr;
+       }
+
+       // Master CT
+       if (src->exp_master.src) {
+               addr = nl_addr_clone(src->exp_master.src);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_master.src = addr;
+       }
+
+       if (src->exp_master.dst) {
+               addr = nl_addr_clone(src->exp_master.dst);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_master.dst = addr;
+       }
+
+       // Mask
+       if (src->exp_mask.src) {
+               addr = nl_addr_clone(src->exp_mask.src);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_mask.src = addr;
+       }
+
+       if (src->exp_mask.dst) {
+               addr = nl_addr_clone(src->exp_mask.dst);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_mask.dst = addr;
+       }
+
+    // NAT
+       if (src->exp_nat.src) {
+               addr = nl_addr_clone(src->exp_nat.src);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_nat.src = addr;
+       }
+
+       if (src->exp_nat.dst) {
+               addr = nl_addr_clone(src->exp_nat.dst);
+               if (!addr)
+                       return -NLE_NOMEM;
+               dst->exp_nat.dst = addr;
+       }
+
+       if (src->exp_fn)
+               dst->exp_fn = strdup(src->exp_fn);
+
+       if (src->exp_helper_name)
+               dst->exp_helper_name = strdup(src->exp_helper_name);
+
+       return 0;
+}
+
+static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port)
+{
+       char buf[64];
+
+       if (addr)
+               nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf)));
+
+       if (port)
+               nl_dump(p, ":%u ", port);
+       else if (addr)
+               nl_dump(p, " ");
+}
+
+static void dump_icmp(struct nl_dump_params *p, struct nfnl_exp *exp, int tuple)
+{
+       if (nfnl_exp_test_icmp(exp, tuple)) {
+
+               nl_dump(p, "icmp type %d ", nfnl_exp_get_icmp_type(exp, tuple));
+
+               nl_dump(p, "code %d ", nfnl_exp_get_icmp_code(exp, tuple));
+
+               nl_dump(p, "id %d ", nfnl_exp_get_icmp_id(exp, tuple));
+       }
+}
+
+static void exp_dump_tuples(struct nfnl_exp *exp, struct nl_dump_params *p)
+{
+       struct nl_addr *tuple_src, *tuple_dst;
+       int tuple_sport, tuple_dport;
+       int i = 0;
+       char buf[64];
+
+       for (i = NFNL_EXP_TUPLE_EXPECT; i < NFNL_EXP_TUPLE_MAX; i++) {
+               tuple_src = NULL;
+               tuple_dst = NULL;
+               tuple_sport = 0;
+               tuple_dport = 0;
+
+               // Test needed for NAT case
+               if (nfnl_exp_test_src(exp, i))
+                       tuple_src = nfnl_exp_get_src(exp, i);
+               if (nfnl_exp_test_dst(exp, i))
+                       tuple_dst = nfnl_exp_get_dst(exp, i);
+
+        // Don't have tests for individual ports/types/codes/ids,
+               if (nfnl_exp_test_l4protonum(exp, i)) {
+                       nl_dump(p, "%s ",
+                               nl_ip_proto2str(nfnl_exp_get_l4protonum(exp, i), buf, sizeof(buf)));
+               }
+
+               if (nfnl_exp_test_ports(exp, i)) {
+                       tuple_sport = nfnl_exp_get_src_port(exp, i);
+                       tuple_dport = nfnl_exp_get_dst_port(exp, i);
+               }
+
+               dump_addr(p, tuple_src, tuple_sport);
+               dump_addr(p, tuple_dst, tuple_dport);
+               dump_icmp(p, exp, 0);
+       }
+
+       if (nfnl_exp_test_nat_dir(exp))
+               nl_dump(p, "nat dir %s ", exp->exp_nat_dir);
+
+}
+
+/* FIXME Compatible with /proc/net/nf_conntrack */
+static void exp_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_exp *exp = (struct nfnl_exp *) a;
+
+       nl_new_line(p);
+
+       exp_dump_tuples(exp, p);
+
+       nl_dump(p, "\n");
+}
+
+static void exp_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_exp *exp = (struct nfnl_exp *) a;
+       char buf[64];
+       int fp = 0;
+
+       exp_dump_line(a, p);
+
+       nl_dump(p, "    id 0x%x ", exp->exp_id);
+       nl_dump_line(p, "family %s ",
+               nl_af2str(exp->exp_family, buf, sizeof(buf)));
+
+       if (nfnl_exp_test_timeout(exp)) {
+               uint64_t timeout_ms = nfnl_exp_get_timeout(exp) * 1000UL;
+               nl_dump(p, "timeout %s ",
+                       nl_msec2str(timeout_ms, buf, sizeof(buf)));
+       }
+
+       if (nfnl_exp_test_helper_name(exp))
+               nl_dump(p, "helper %s ", exp->exp_helper_name);
+
+       if (nfnl_exp_test_fn(exp))
+               nl_dump(p, "fn %s ", exp->exp_fn);
+
+       if (nfnl_exp_test_class(exp))
+               nl_dump(p, "class %u ", nfnl_exp_get_class(exp));
+
+       if (nfnl_exp_test_zone(exp))
+               nl_dump(p, "zone %u ", nfnl_exp_get_zone(exp));
+
+       if (nfnl_exp_test_flags(exp))
+               nl_dump(p, "<");
+#define PRINT_FLAG(str) \
+       { nl_dump(p, "%s%s", fp++ ? "," : "", (str)); }
+
+       if (exp->exp_flags & NF_CT_EXPECT_PERMANENT)
+               PRINT_FLAG("PERMANENT");
+       if (exp->exp_flags & NF_CT_EXPECT_INACTIVE)
+               PRINT_FLAG("INACTIVE");
+       if (exp->exp_flags & NF_CT_EXPECT_USERSPACE)
+               PRINT_FLAG("USERSPACE");
+#undef PRINT_FLAG
+
+       if (nfnl_exp_test_flags(exp))
+               nl_dump(p, ">");
+
+       nl_dump(p, "\n");
+}
+
+static int exp_cmp_l4proto_ports (union nfnl_exp_protodata *a, union nfnl_exp_protodata *b) {
+       // Must return 0 for match, 1 for mismatch
+       int d = 0;
+       d = ( (a->port.src != b->port.src) ||
+                 (a->port.dst != b->port.dst) );
+
+       return d;
+}
+
+static int exp_cmp_l4proto_icmp (union nfnl_exp_protodata *a, union nfnl_exp_protodata *b) {
+    // Must return 0 for match, 1 for mismatch
+       int d = 0;
+       d = ( (a->icmp.code != b->icmp.code) ||
+                 (a->icmp.type != b->icmp.type) ||
+                 (a->icmp.id != b->icmp.id) );
+
+       return d;
+}
+
+static int exp_compare(struct nl_object *_a, struct nl_object *_b,
+                                                       uint32_t attrs, int flags)
+{
+       struct nfnl_exp *a = (struct nfnl_exp *) _a;
+       struct nfnl_exp *b = (struct nfnl_exp *) _b;
+       int diff = 0;
+
+#define EXP_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, EXP_ATTR_##ATTR, a, b, EXPR)
+#define EXP_DIFF_VAL(ATTR, FIELD) EXP_DIFF(ATTR, a->FIELD != b->FIELD)
+#define EXP_DIFF_STRING(ATTR, FIELD) EXP_DIFF(ATTR, (strcmp(a->FIELD, b->FIELD) != 0))
+#define EXP_DIFF_ADDR(ATTR, FIELD) \
+               ((flags & LOOSE_COMPARISON) \
+               ? EXP_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \
+               : EXP_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD)))
+#define EXP_DIFF_L4PROTO_PORTS(ATTR, FIELD) \
+               EXP_DIFF(ATTR, exp_cmp_l4proto_ports(&(a->FIELD), &(b->FIELD)))
+#define EXP_DIFF_L4PROTO_ICMP(ATTR, FIELD) \
+               EXP_DIFF(ATTR, exp_cmp_l4proto_icmp(&(a->FIELD), &(b->FIELD)))
+
+               diff |= EXP_DIFF_VAL(FAMILY,                    exp_family);
+               diff |= EXP_DIFF_VAL(TIMEOUT,                   exp_timeout);
+               diff |= EXP_DIFF_VAL(ID,                        exp_id);
+               diff |= EXP_DIFF_VAL(ZONE,                      exp_zone);
+               diff |= EXP_DIFF_VAL(CLASS,                     exp_class);
+               diff |= EXP_DIFF_VAL(FLAGS,                     exp_flags);
+               diff |= EXP_DIFF_VAL(NAT_DIR,                   exp_nat_dir);
+
+               diff |= EXP_DIFF_STRING(FN,                     exp_fn);
+               diff |= EXP_DIFF_STRING(HELPER_NAME,            exp_helper_name);
+
+               diff |= EXP_DIFF_ADDR(EXPECT_IP_SRC,                    exp_expect.src);
+               diff |= EXP_DIFF_ADDR(EXPECT_IP_DST,                    exp_expect.dst);
+               diff |= EXP_DIFF_VAL(EXPECT_L4PROTO_NUM,                exp_expect.proto.l4protonum);
+               diff |= EXP_DIFF_L4PROTO_PORTS(EXPECT_L4PROTO_PORTS,    exp_expect.proto.l4protodata);
+               diff |= EXP_DIFF_L4PROTO_ICMP(EXPECT_L4PROTO_ICMP,      exp_expect.proto.l4protodata);
+
+               diff |= EXP_DIFF_ADDR(MASTER_IP_SRC,                    exp_master.src);
+               diff |= EXP_DIFF_ADDR(MASTER_IP_DST,                    exp_master.dst);
+               diff |= EXP_DIFF_VAL(MASTER_L4PROTO_NUM,                exp_master.proto.l4protonum);
+               diff |= EXP_DIFF_L4PROTO_PORTS(MASTER_L4PROTO_PORTS,    exp_master.proto.l4protodata);
+               diff |= EXP_DIFF_L4PROTO_ICMP(MASTER_L4PROTO_ICMP,      exp_master.proto.l4protodata);
+
+               diff |= EXP_DIFF_ADDR(MASK_IP_SRC,                      exp_mask.src);
+               diff |= EXP_DIFF_ADDR(MASK_IP_DST,                      exp_mask.dst);
+               diff |= EXP_DIFF_VAL(MASK_L4PROTO_NUM,                  exp_mask.proto.l4protonum);
+               diff |= EXP_DIFF_L4PROTO_PORTS(MASK_L4PROTO_PORTS,      exp_mask.proto.l4protodata);
+               diff |= EXP_DIFF_L4PROTO_ICMP(MASK_L4PROTO_ICMP,        exp_mask.proto.l4protodata);
+
+               diff |= EXP_DIFF_ADDR(NAT_IP_SRC,                       exp_nat.src);
+               diff |= EXP_DIFF_ADDR(NAT_IP_DST,                       exp_nat.dst);
+               diff |= EXP_DIFF_VAL(NAT_L4PROTO_NUM,                   exp_nat.proto.l4protonum);
+               diff |= EXP_DIFF_L4PROTO_PORTS(NAT_L4PROTO_PORTS,       exp_nat.proto.l4protodata);
+               diff |= EXP_DIFF_L4PROTO_ICMP(NAT_L4PROTO_ICMP,         exp_nat.proto.l4protodata);
+
+#undef EXP_DIFF
+#undef EXP_DIFF_VAL
+#undef EXP_DIFF_STRING
+#undef EXP_DIFF_ADDR
+#undef EXP_DIFF_L4PROTO_PORTS
+#undef EXP_DIFF_L4PROTO_ICMP
+
+       return diff;
+}
+
+// CLI arguments?
+static const struct trans_tbl exp_attrs[] = {
+       __ADD(EXP_ATTR_FAMILY,                          family)
+       __ADD(EXP_ATTR_TIMEOUT,                         timeout)
+       __ADD(EXP_ATTR_ID,                              id)
+       __ADD(EXP_ATTR_HELPER_NAME,                     helpername)
+       __ADD(EXP_ATTR_ZONE,                            zone)
+       __ADD(EXP_ATTR_CLASS,                           class)
+       __ADD(EXP_ATTR_FLAGS,                           flags)
+       __ADD(EXP_ATTR_FN,                              function)
+       __ADD(EXP_ATTR_EXPECT_IP_SRC,                   expectipsrc)
+       __ADD(EXP_ATTR_EXPECT_IP_DST,                   expectipdst)
+       __ADD(EXP_ATTR_EXPECT_L4PROTO_NUM,              expectprotonum)
+       __ADD(EXP_ATTR_EXPECT_L4PROTO_PORTS,            expectports)
+       __ADD(EXP_ATTR_EXPECT_L4PROTO_ICMP,             expecticmp)
+       __ADD(EXP_ATTR_MASTER_IP_SRC,                   masteripsrc)
+       __ADD(EXP_ATTR_MASTER_IP_DST,                   masteripdst)
+       __ADD(EXP_ATTR_MASTER_L4PROTO_NUM,              masterprotonum)
+       __ADD(EXP_ATTR_MASTER_L4PROTO_PORTS,            masterports)
+       __ADD(EXP_ATTR_MASTER_L4PROTO_ICMP,             mastericmp)
+       __ADD(EXP_ATTR_MASK_IP_SRC,                     maskipsrc)
+       __ADD(EXP_ATTR_MASK_IP_DST,                     maskipdst)
+       __ADD(EXP_ATTR_MASK_L4PROTO_NUM,                maskprotonum)
+       __ADD(EXP_ATTR_MASK_L4PROTO_PORTS,              maskports)
+       __ADD(EXP_ATTR_MASK_L4PROTO_ICMP,               maskicmp)
+       __ADD(EXP_ATTR_NAT_IP_SRC,                      natipsrc)
+       __ADD(EXP_ATTR_NAT_IP_DST,                      natipdst)
+       __ADD(EXP_ATTR_NAT_L4PROTO_NUM,                 natprotonum)
+       __ADD(EXP_ATTR_NAT_L4PROTO_PORTS,               natports)
+       __ADD(EXP_ATTR_NAT_L4PROTO_ICMP,                naticmp)
+       __ADD(EXP_ATTR_NAT_DIR,                         natdir)
+};
+
+static char *exp_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, exp_attrs, ARRAY_SIZE(exp_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_exp *nfnl_exp_alloc(void)
+{
+       return (struct nfnl_exp *) nl_object_alloc(&exp_obj_ops);
+}
+
+void nfnl_exp_get(struct nfnl_exp *exp)
+{
+       nl_object_get((struct nl_object *) exp);
+}
+
+void nfnl_exp_put(struct nfnl_exp *exp)
+{
+       nl_object_put((struct nl_object *) exp);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_exp_set_family(struct nfnl_exp *exp, uint8_t family)
+{
+       exp->exp_family = family;
+       exp->ce_mask |= EXP_ATTR_FAMILY;
+}
+
+uint8_t nfnl_exp_get_family(const struct nfnl_exp *exp)
+{
+       if (exp->ce_mask & EXP_ATTR_FAMILY)
+               return exp->exp_family;
+       else
+               return AF_UNSPEC;
+}
+
+void nfnl_exp_set_flags(struct nfnl_exp *exp, uint32_t flags)
+{
+       exp->exp_flags |= flags;
+       exp->ce_mask |= EXP_ATTR_FLAGS;
+}
+
+int nfnl_exp_test_flags(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_FLAGS);
+}
+
+void nfnl_exp_unset_flags(struct nfnl_exp *exp, uint32_t flags)
+{
+       exp->exp_flags &= ~flags;
+       exp->ce_mask |= EXP_ATTR_FLAGS;
+}
+
+uint32_t nfnl_exp_get_flags(const struct nfnl_exp *exp)
+{
+       return exp->exp_flags;
+}
+
+static const struct trans_tbl flag_table[] = {
+       __ADD(IPS_EXPECTED, expected)
+       __ADD(IPS_SEEN_REPLY, seen_reply)
+       __ADD(IPS_ASSURED, assured)
+};
+
+char * nfnl_exp_flags2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, flag_table,
+                          ARRAY_SIZE(flag_table));
+}
+
+int nfnl_exp_str2flags(const char *name)
+{
+       return __str2flags(name, flag_table, ARRAY_SIZE(flag_table));
+}
+
+void nfnl_exp_set_timeout(struct nfnl_exp *exp, uint32_t timeout)
+{
+       exp->exp_timeout = timeout;
+       exp->ce_mask |= EXP_ATTR_TIMEOUT;
+}
+
+int nfnl_exp_test_timeout(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_TIMEOUT);
+}
+
+uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *exp)
+{
+       return exp->exp_timeout;
+}
+
+void nfnl_exp_set_id(struct nfnl_exp *exp, uint32_t id)
+{
+       exp->exp_id = id;
+       exp->ce_mask |= EXP_ATTR_ID;
+}
+
+int nfnl_exp_test_id(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_ID);
+}
+
+uint32_t nfnl_exp_get_id(const struct nfnl_exp *exp)
+{
+       return exp->exp_id;
+}
+
+int nfnl_exp_set_helper_name(struct nfnl_exp *exp, void *name)
+{
+       free(exp->exp_helper_name);
+       exp->exp_helper_name = strdup(name);
+       if (!exp->exp_helper_name)
+               return -NLE_NOMEM;
+
+       exp->ce_mask |= EXP_ATTR_HELPER_NAME;
+       return 0;
+}
+
+int  nfnl_exp_test_helper_name(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_HELPER_NAME);
+}
+
+const char * nfnl_exp_get_helper_name(const struct nfnl_exp *exp)
+{
+       return exp->exp_helper_name;
+}
+
+void nfnl_exp_set_zone(struct nfnl_exp *exp, uint16_t zone)
+{
+       exp->exp_zone = zone;
+       exp->ce_mask |= EXP_ATTR_ZONE;
+}
+
+int nfnl_exp_test_zone(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_ZONE);
+}
+
+uint16_t nfnl_exp_get_zone(const struct nfnl_exp *exp)
+{
+       return exp->exp_zone;
+}
+
+void nfnl_exp_set_class(struct nfnl_exp *exp, uint32_t class)
+{
+       exp->exp_class = class;
+       exp->ce_mask |= EXP_ATTR_CLASS;
+}
+
+int nfnl_exp_test_class(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_CLASS);
+}
+
+uint32_t nfnl_exp_get_class(const struct nfnl_exp *exp)
+{
+       return exp->exp_class;
+}
+
+int nfnl_exp_set_fn(struct nfnl_exp *exp, void *fn)
+{
+       free(exp->exp_fn);
+       exp->exp_fn = strdup(fn);
+       if (!exp->exp_fn)
+               return -NLE_NOMEM;
+
+       exp->ce_mask |= EXP_ATTR_FN;
+       return 0;
+}
+
+int nfnl_exp_test_fn(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_FN);
+}
+
+const char * nfnl_exp_get_fn(const struct nfnl_exp *exp)
+{
+       return exp->exp_fn;
+}
+
+void nfnl_exp_set_nat_dir(struct nfnl_exp *exp, uint8_t nat_dir)
+{
+       exp->exp_nat_dir = nat_dir;
+       exp->ce_mask |= EXP_ATTR_NAT_DIR;
+}
+
+int nfnl_exp_test_nat_dir(const struct nfnl_exp *exp)
+{
+       return !!(exp->ce_mask & EXP_ATTR_NAT_DIR);
+}
+
+uint8_t nfnl_exp_get_nat_dir(const struct nfnl_exp *exp)
+{
+       return exp->exp_nat_dir;
+}
+
+#define EXP_GET_TUPLE(e, t) \
+       (t == NFNL_EXP_TUPLE_MASTER) ? \
+               &(e->exp_master) : \
+       (t == NFNL_EXP_TUPLE_MASK) ? \
+               &(e->exp_mask) : \
+       (t == NFNL_EXP_TUPLE_NAT) ? \
+               &(e->exp_nat) : &(exp->exp_expect)
+
+static int exp_get_src_attr(int tuple)
+{
+       int attr = 0;
+
+       switch (tuple) {
+               case NFNL_EXP_TUPLE_MASTER:
+                       attr = EXP_ATTR_MASTER_IP_SRC;
+                       break;
+               case NFNL_EXP_TUPLE_MASK:
+                       attr = EXP_ATTR_MASK_IP_SRC;
+                       break;
+               case NFNL_EXP_TUPLE_NAT:
+                       attr = EXP_ATTR_NAT_IP_SRC;
+                       break;
+               case NFNL_EXP_TUPLE_EXPECT:
+               default :
+                       attr = EXP_ATTR_EXPECT_IP_SRC;
+       }
+
+       return attr;
+}
+
+static int exp_get_dst_attr(int tuple)
+{
+       int attr = 0;
+
+       switch (tuple) {
+               case NFNL_EXP_TUPLE_MASTER:
+                       attr = EXP_ATTR_MASTER_IP_DST;
+                       break;
+               case NFNL_EXP_TUPLE_MASK:
+                       attr = EXP_ATTR_MASK_IP_DST;
+                       break;
+               case NFNL_EXP_TUPLE_NAT:
+                       attr = EXP_ATTR_NAT_IP_DST;
+                       break;
+               case NFNL_EXP_TUPLE_EXPECT:
+               default :
+                       attr = EXP_ATTR_EXPECT_IP_DST;
+       }
+
+       return attr;
+}
+
+
+static int exp_set_addr(struct nfnl_exp *exp, struct nl_addr *addr,
+                          int attr, struct nl_addr ** exp_addr)
+{
+       if (exp->ce_mask & EXP_ATTR_FAMILY) {
+               if (addr->a_family != exp->exp_family)
+                       return -NLE_AF_MISMATCH;
+       } else
+               nfnl_exp_set_family(exp, addr->a_family);
+
+       if (*exp_addr)
+               nl_addr_put(*exp_addr);
+
+       nl_addr_get(addr);
+       *exp_addr = addr;
+       exp->ce_mask |= attr;
+
+       return 0;
+}
+
+int nfnl_exp_set_src(struct nfnl_exp *exp, int tuple, struct nl_addr *addr)
+{
+       struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       return exp_set_addr(exp, addr, exp_get_src_attr(tuple), &dir->src);
+}
+
+int nfnl_exp_set_dst(struct nfnl_exp *exp, int tuple, struct nl_addr *addr)
+{
+       struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       return exp_set_addr(exp, addr, exp_get_dst_attr(tuple), &dir->dst);
+}
+
+int nfnl_exp_test_src(const struct nfnl_exp *exp, int tuple)
+{
+       return !!(exp->ce_mask & exp_get_src_attr(tuple));
+}
+
+int nfnl_exp_test_dst(const struct nfnl_exp *exp, int tuple)
+{
+       return !!(exp->ce_mask & exp_get_dst_attr(tuple));
+}
+
+struct nl_addr *nfnl_exp_get_src(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       if (!(exp->ce_mask & exp_get_src_attr(tuple)))
+               return NULL;
+       return dir->src;
+}
+
+struct nl_addr *nfnl_exp_get_dst(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       if (!(exp->ce_mask & exp_get_dst_attr(tuple)))
+               return NULL;
+       return dir->dst;
+}
+
+static int exp_get_l4protonum_attr(int tuple)
+{
+       int attr = 0;
+
+       switch (tuple) {
+               case NFNL_EXP_TUPLE_MASTER:
+                       attr = EXP_ATTR_MASTER_L4PROTO_NUM;
+                       break;
+               case NFNL_EXP_TUPLE_MASK:
+                       attr = EXP_ATTR_MASK_L4PROTO_NUM;
+                       break;
+               case NFNL_EXP_TUPLE_NAT:
+                       attr = EXP_ATTR_NAT_L4PROTO_NUM;
+                       break;
+               case NFNL_EXP_TUPLE_EXPECT:
+               default :
+                       attr = EXP_ATTR_EXPECT_L4PROTO_NUM;
+       }
+
+       return attr;
+}
+
+void nfnl_exp_set_l4protonum(struct nfnl_exp *exp, int tuple, uint8_t l4protonum)
+{
+       struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       dir->proto.l4protonum = l4protonum;
+       exp->ce_mask |= exp_get_l4protonum_attr(tuple);
+}
+
+int nfnl_exp_test_l4protonum(const struct nfnl_exp *exp, int tuple)
+{
+       return !!(exp->ce_mask & exp_get_l4protonum_attr(tuple));
+}
+
+uint8_t nfnl_exp_get_l4protonum(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+       return dir->proto.l4protonum;
+}
+
+static int exp_get_l4ports_attr(int tuple)
+{
+       int attr = 0;
+
+       switch (tuple) {
+               case NFNL_EXP_TUPLE_MASTER:
+                       attr = EXP_ATTR_MASTER_L4PROTO_PORTS;
+                       break;
+               case NFNL_EXP_TUPLE_MASK:
+                       attr = EXP_ATTR_MASK_L4PROTO_PORTS;
+                       break;
+               case NFNL_EXP_TUPLE_NAT:
+                       attr = EXP_ATTR_NAT_L4PROTO_PORTS;
+                       break;
+               case NFNL_EXP_TUPLE_EXPECT:
+               default :
+                       attr = EXP_ATTR_EXPECT_L4PROTO_PORTS;
+       }
+
+       return attr;
+}
+
+void nfnl_exp_set_ports(struct nfnl_exp *exp, int tuple, uint16_t srcport, uint16_t dstport)
+{
+       struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       dir->proto.l4protodata.port.src = srcport;
+       dir->proto.l4protodata.port.dst = dstport;
+
+       exp->ce_mask |= exp_get_l4ports_attr(tuple);
+}
+
+int nfnl_exp_test_ports(const struct nfnl_exp *exp, int tuple)
+{
+       return !!(exp->ce_mask & exp_get_l4ports_attr(tuple));
+}
+
+uint16_t nfnl_exp_get_src_port(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+       return dir->proto.l4protodata.port.src;
+}
+
+uint16_t nfnl_exp_get_dst_port(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       return dir->proto.l4protodata.port.dst;
+}
+
+static int exp_get_l4icmp_attr(int tuple)
+{
+       int attr = 0;
+
+       switch (tuple) {
+               case NFNL_EXP_TUPLE_MASTER:
+                       attr = EXP_ATTR_MASTER_L4PROTO_ICMP;
+                       break;
+               case NFNL_EXP_TUPLE_MASK:
+                       attr = EXP_ATTR_MASK_L4PROTO_ICMP;
+                       break;
+               case NFNL_EXP_TUPLE_NAT:
+                       attr = EXP_ATTR_NAT_L4PROTO_ICMP;
+                       break;
+               case NFNL_EXP_TUPLE_EXPECT:
+               default :
+                       attr = EXP_ATTR_EXPECT_L4PROTO_ICMP;
+       }
+
+       return attr;
+}
+
+void nfnl_exp_set_icmp(struct nfnl_exp *exp, int tuple, uint16_t id, uint8_t type, uint8_t code)
+{
+       struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       dir->proto.l4protodata.icmp.id = id;
+       dir->proto.l4protodata.icmp.type = type;
+       dir->proto.l4protodata.icmp.code = code;
+
+       exp->ce_mask |= exp_get_l4icmp_attr(tuple);
+}
+
+int nfnl_exp_test_icmp(const struct nfnl_exp *exp, int tuple)
+{
+       int attr = exp_get_l4icmp_attr(tuple);
+       return !!(exp->ce_mask & attr);
+}
+
+uint16_t nfnl_exp_get_icmp_id(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       return dir->proto.l4protodata.icmp.id;
+}
+
+uint8_t nfnl_exp_get_icmp_type(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       return dir->proto.l4protodata.icmp.type;
+}
+
+uint8_t nfnl_exp_get_icmp_code(const struct nfnl_exp *exp, int tuple)
+{
+       const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
+
+       return dir->proto.l4protodata.icmp.code;
+}
+
+/** @} */
+
+struct nl_object_ops exp_obj_ops = {
+       .oo_name        = "netfilter/exp",
+       .oo_size        = sizeof(struct nfnl_exp),
+       .oo_free_data   = exp_free_data,
+       .oo_clone       = exp_clone,
+       .oo_dump = {
+               [NL_DUMP_LINE]          = exp_dump_line,
+               [NL_DUMP_DETAILS]       = exp_dump_details,
+       },
+       .oo_compare     = exp_compare,
+       .oo_attrs2str   = exp_attrs2str,
+};
+
+/** @} */
diff --git a/lib/netfilter/log.c b/lib/netfilter/log.c
new file mode 100644 (file)
index 0000000..1bab9b6
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * lib/netfilter/log.c Netfilter Log
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup log Log
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_log.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log.h>
+
+/**
+ * @name Log Commands
+ * @{
+ */
+
+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;
+
+       msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
+                                  family, queuenum);
+       if (msg == NULL)
+               return -NLE_NOMEM;
+
+       cmd.command = command;
+       if (nla_put(msg, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
+               goto nla_put_failure;
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+static int send_log_request(struct nl_sock *sk, struct nl_msg *msg)
+{
+       int err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+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, result);
+}
+
+int nfnl_log_pf_bind(struct nl_sock *nlh, uint8_t pf)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_log_build_pf_bind(pf, &msg)) < 0)
+               return err;
+
+       return send_log_request(nlh, msg);
+}
+
+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, result);
+}
+
+int nfnl_log_pf_unbind(struct nl_sock *nlh, uint8_t pf)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_log_build_pf_unbind(pf, &msg)) < 0)
+               return err;
+
+       return send_log_request(nlh, msg);
+}
+
+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 -NLE_MISSING_ATTR;
+
+       msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
+                                  0, nfnl_log_get_group(log));
+       if (msg == NULL)
+               return -NLE_NOMEM;
+
+       /* This sucks. The nfnetlink_log interface always expects both
+        * parameters to be present. Needs to be done properly.
+        */
+       if (nfnl_log_test_copy_mode(log)) {
+               struct nfulnl_msg_config_mode mode;
+
+               switch (nfnl_log_get_copy_mode(log)) {
+               case NFNL_LOG_COPY_NONE:
+                       mode.copy_mode = NFULNL_COPY_NONE;
+                       break;
+               case NFNL_LOG_COPY_META:
+                       mode.copy_mode = NFULNL_COPY_META;
+                       break;
+               case NFNL_LOG_COPY_PACKET:
+                       mode.copy_mode = NFULNL_COPY_PACKET;
+                       break;
+               }
+               mode.copy_range = htonl(nfnl_log_get_copy_range(log));
+               mode._pad = 0;
+
+               if (nla_put(msg, NFULA_CFG_MODE, sizeof(mode), &mode) < 0)
+                       goto nla_put_failure;
+       }
+
+       if (nfnl_log_test_flush_timeout(log) &&
+           nla_put_u32(msg, NFULA_CFG_TIMEOUT,
+                       htonl(nfnl_log_get_flush_timeout(log))) < 0)
+               goto nla_put_failure;
+
+       if (nfnl_log_test_alloc_size(log) &&
+           nla_put_u32(msg, NFULA_CFG_NLBUFSIZ,
+                       htonl(nfnl_log_get_alloc_size(log))) < 0)
+               goto nla_put_failure;
+
+       if (nfnl_log_test_queue_threshold(log) &&
+           nla_put_u32(msg, NFULA_CFG_QTHRESH,
+                       htonl(nfnl_log_get_queue_threshold(log))) < 0)
+               goto nla_put_failure;
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+int nfnl_log_build_create_request(const struct nfnl_log *log,
+                                 struct nl_msg **result)
+{
+       struct nfulnl_msg_config_cmd cmd;
+       int err;
+
+       if ((err = nfnl_log_build_request(log, result)) < 0)
+               return err;
+
+       cmd.command = NFULNL_CFG_CMD_BIND;
+
+       if (nla_put(*result, NFULA_CFG_CMD, sizeof(cmd), &cmd) < 0)
+               goto nla_put_failure;
+
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(*result);
+       return -NLE_MSGSIZE;
+}
+
+int nfnl_log_create(struct nl_sock *nlh, const struct nfnl_log *log)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_log_build_create_request(log, &msg)) < 0)
+               return err;
+
+       return send_log_request(nlh, msg);
+}
+
+int nfnl_log_build_change_request(const struct nfnl_log *log,
+                                 struct nl_msg **result)
+{
+       return nfnl_log_build_request(log, result);
+}
+
+int nfnl_log_change(struct nl_sock *nlh, const struct nfnl_log *log)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_log_build_change_request(log, &msg)) < 0)
+               return err;
+
+       return send_log_request(nlh, msg);
+}
+
+int nfnl_log_build_delete_request(const struct nfnl_log *log,
+                                 struct nl_msg **result)
+{
+       if (!nfnl_log_test_group(log))
+               return -NLE_MISSING_ATTR;
+
+       return build_log_cmd_request(0, nfnl_log_get_group(log),
+                                    NFULNL_CFG_CMD_UNBIND, result);
+}
+
+int nfnl_log_delete(struct nl_sock *nlh, const struct nfnl_log *log)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_log_build_delete_request(log, &msg)) < 0)
+               return err;
+
+       return send_log_request(nlh, msg);
+}
+
+/** @} */
+
+static struct nl_cache_ops nfnl_log_ops = {
+       .co_name                = "netfilter/log",
+       .co_obj_ops             = &log_obj_ops,
+       .co_msgtypes            = {
+               END_OF_MSGTYPES_LIST,
+       },
+};
+
+static void __init log_init(void)
+{
+       nl_cache_mngt_register(&nfnl_log_ops);
+}
+
+static void __exit log_exit(void)
+{
+       nl_cache_mngt_unregister(&nfnl_log_ops);
+}
+
+/** @} */
diff --git a/lib/netfilter/log_msg.c b/lib/netfilter/log_msg.c
new file mode 100644 (file)
index 0000000..6e09da2
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * lib/netfilter/log_msg.c     Netfilter Log Message
+ *
+ *     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) 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>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup log Log
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_log.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log_msg.h>
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+       return x;
+}
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+       return bswap_64(x);
+}
+#endif
+
+static struct nla_policy log_msg_policy[NFULA_MAX+1] = {
+       [NFULA_PACKET_HDR]              = {
+               .minlen = sizeof(struct nfulnl_msg_packet_hdr)
+       },
+       [NFULA_MARK]                    = { .type = NLA_U32 },
+       [NFULA_TIMESTAMP]               = {
+               .minlen = sizeof(struct nfulnl_msg_packet_timestamp)
+       },
+       [NFULA_IFINDEX_INDEV]           = { .type = NLA_U32 },
+       [NFULA_IFINDEX_OUTDEV]          = { .type = NLA_U32 },
+       [NFULA_IFINDEX_PHYSINDEV]       = { .type = NLA_U32 },
+       [NFULA_IFINDEX_PHYSOUTDEV]      = { .type = NLA_U32 },
+       [NFULA_HWADDR]                  = {
+               .minlen = sizeof(struct nfulnl_msg_packet_hw)
+       },
+       //[NFULA_PAYLOAD]
+       [NFULA_PREFIX]                  = { .type = NLA_STRING, },
+       [NFULA_UID]                     = { .type = NLA_U32 },
+       [NFULA_GID]                     = { .type = NLA_U32 },
+       [NFULA_SEQ]                     = { .type = NLA_U32 },
+       [NFULA_SEQ_GLOBAL]              = { .type = NLA_U32 },
+};
+
+int nfnlmsg_log_msg_parse(struct nlmsghdr *nlh, struct nfnl_log_msg **result)
+{
+       struct nfnl_log_msg *msg;
+       struct nlattr *tb[NFULA_MAX+1];
+       struct nlattr *attr;
+       int err;
+
+       msg = nfnl_log_msg_alloc();
+       if (!msg)
+               return -NLE_NOMEM;
+
+       msg->ce_msgtype = nlh->nlmsg_type;
+
+       err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFULA_MAX,
+                         log_msg_policy);
+       if (err < 0)
+               goto errout;
+
+       nfnl_log_msg_set_family(msg, nfnlmsg_family(nlh));
+
+       attr = tb[NFULA_PACKET_HDR];
+       if (attr) {
+               struct nfulnl_msg_packet_hdr *hdr = nla_data(attr);
+
+               if (hdr->hw_protocol)
+                       nfnl_log_msg_set_hwproto(msg, hdr->hw_protocol);
+               nfnl_log_msg_set_hook(msg, hdr->hook);
+       }
+
+       attr = tb[NFULA_MARK];
+       if (attr)
+               nfnl_log_msg_set_mark(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_TIMESTAMP];
+       if (attr) {
+               struct nfulnl_msg_packet_timestamp *timestamp = nla_data(attr);
+               struct timeval tv;
+
+               tv.tv_sec = ntohll(timestamp->sec);
+               tv.tv_usec = ntohll(timestamp->usec);
+               nfnl_log_msg_set_timestamp(msg, &tv);
+       }
+
+       attr = tb[NFULA_IFINDEX_INDEV];
+       if (attr)
+               nfnl_log_msg_set_indev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_IFINDEX_OUTDEV];
+       if (attr)
+               nfnl_log_msg_set_outdev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_IFINDEX_PHYSINDEV];
+       if (attr)
+               nfnl_log_msg_set_physindev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_IFINDEX_PHYSOUTDEV];
+       if (attr)
+               nfnl_log_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_HWADDR];
+       if (attr) {
+               struct nfulnl_msg_packet_hw *hw = nla_data(attr);
+
+               nfnl_log_msg_set_hwaddr(msg, hw->hw_addr, ntohs(hw->hw_addrlen));
+       }
+
+       attr = tb[NFULA_PAYLOAD];
+       if (attr) {
+               err = nfnl_log_msg_set_payload(msg, nla_data(attr), nla_len(attr));
+               if (err < 0)
+                       goto errout;
+       }
+
+       attr = tb[NFULA_PREFIX];
+       if (attr) {
+               err = nfnl_log_msg_set_prefix(msg, nla_data(attr));
+               if (err < 0)
+                       goto errout;
+       }
+
+       attr = tb[NFULA_UID];
+       if (attr)
+               nfnl_log_msg_set_uid(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_GID];
+       if (attr)
+               nfnl_log_msg_set_gid(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_SEQ];
+       if (attr)
+               nfnl_log_msg_set_seq(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFULA_SEQ_GLOBAL];
+       if (attr)
+               nfnl_log_msg_set_seq_global(msg, ntohl(nla_get_u32(attr)));
+
+       *result = msg;
+       return 0;
+
+errout:
+       nfnl_log_msg_put(msg);
+       return err;
+}
+
+static int log_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                         struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct nfnl_log_msg *msg;
+       int err;
+
+       if ((err = nfnlmsg_log_msg_parse(nlh, &msg)) < 0)
+               goto errout;
+
+       err = pp->pp_cb((struct nl_object *) msg, pp);
+errout:
+       nfnl_log_msg_put(msg);
+       return err;
+}
+
+/** @} */
+
+#define NFNLMSG_LOG_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_ULOG, (type))
+static struct nl_cache_ops nfnl_log_msg_ops = {
+       .co_name                = "netfilter/log_msg",
+       .co_hdrsize             = NFNL_HDRLEN,
+       .co_msgtypes            = {
+               { NFNLMSG_LOG_TYPE(NFULNL_MSG_PACKET), NL_ACT_NEW, "new" },
+               END_OF_MSGTYPES_LIST,
+       },
+       .co_protocol            = NETLINK_NETFILTER,
+       .co_msg_parser          = log_msg_parser,
+       .co_obj_ops             = &log_msg_obj_ops,
+};
+
+static void __init log_msg_init(void)
+{
+       nl_cache_mngt_register(&nfnl_log_msg_ops);
+}
+
+static void __exit log_msg_exit(void)
+{
+       nl_cache_mngt_unregister(&nfnl_log_msg_ops);
+}
+
+/** @} */
diff --git a/lib/netfilter/log_msg_obj.c b/lib/netfilter/log_msg_obj.c
new file mode 100644 (file)
index 0000000..57db9d4
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * lib/netfilter/log_msg_obj.c Netfilter Log Object
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/netfilter.h>
+#include <netlink/netfilter/log_msg.h>
+
+/** @cond SKIP */
+#define LOG_MSG_ATTR_FAMILY            (1UL << 0)
+#define LOG_MSG_ATTR_HWPROTO           (1UL << 1)
+#define LOG_MSG_ATTR_HOOK              (1UL << 2)
+#define LOG_MSG_ATTR_MARK              (1UL << 3)
+#define LOG_MSG_ATTR_TIMESTAMP         (1UL << 4)
+#define LOG_MSG_ATTR_INDEV             (1UL << 5)
+#define LOG_MSG_ATTR_OUTDEV            (1UL << 6)
+#define LOG_MSG_ATTR_PHYSINDEV         (1UL << 7)
+#define LOG_MSG_ATTR_PHYSOUTDEV                (1UL << 8)
+#define LOG_MSG_ATTR_HWADDR            (1UL << 9)
+#define LOG_MSG_ATTR_PAYLOAD           (1UL << 10)
+#define LOG_MSG_ATTR_PREFIX            (1UL << 11)
+#define LOG_MSG_ATTR_UID               (1UL << 12)
+#define LOG_MSG_ATTR_GID               (1UL << 13)
+#define LOG_MSG_ATTR_SEQ               (1UL << 14)
+#define LOG_MSG_ATTR_SEQ_GLOBAL                (1UL << 15)
+/** @endcond */
+
+static void log_msg_free_data(struct nl_object *c)
+{
+       struct nfnl_log_msg *msg = (struct nfnl_log_msg *) c;
+
+       if (msg == NULL)
+               return;
+
+       free(msg->log_msg_payload);
+       free(msg->log_msg_prefix);
+}
+
+static int log_msg_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct nfnl_log_msg *dst = (struct nfnl_log_msg *) _dst;
+       struct nfnl_log_msg *src = (struct nfnl_log_msg *) _src;
+       int err;
+
+       if (src->log_msg_payload) {
+               err = nfnl_log_msg_set_payload(dst, src->log_msg_payload,
+                                              src->log_msg_payload_len);
+               if (err < 0)
+                       goto errout;
+       }
+
+       if (src->log_msg_prefix) {
+               err = nfnl_log_msg_set_prefix(dst, src->log_msg_prefix);
+               if (err < 0)
+                       goto errout;
+       }
+
+       return 0;
+errout:
+       return err;
+}
+
+static void log_msg_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_log_msg *msg = (struct nfnl_log_msg *) a;
+       struct nl_cache *link_cache;
+       char buf[64];
+
+       link_cache = nl_cache_mngt_require_safe("route/link");
+
+       nl_new_line(p);
+
+       if (msg->ce_mask & LOG_MSG_ATTR_PREFIX)
+               nl_dump(p, "%s", msg->log_msg_prefix);
+
+       if (msg->ce_mask & LOG_MSG_ATTR_INDEV) {
+               if (link_cache)
+                       nl_dump(p, "IN=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->log_msg_indev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "IN=%d ", msg->log_msg_indev);
+       }
+
+       if (msg->ce_mask & LOG_MSG_ATTR_PHYSINDEV) {
+               if (link_cache)
+                       nl_dump(p, "PHYSIN=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->log_msg_physindev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "IN=%d ", msg->log_msg_physindev);
+       }
+
+       if (msg->ce_mask & LOG_MSG_ATTR_OUTDEV) {
+               if (link_cache)
+                       nl_dump(p, "OUT=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->log_msg_outdev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "OUT=%d ", msg->log_msg_outdev);
+       }
+
+       if (msg->ce_mask & LOG_MSG_ATTR_PHYSOUTDEV) {
+               if (link_cache)
+                       nl_dump(p, "PHYSOUT=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->log_msg_physoutdev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "PHYSOUT=%d ", msg->log_msg_physoutdev);
+       }
+
+       if (msg->ce_mask & LOG_MSG_ATTR_HWADDR) {
+               int i;
+
+               nl_dump(p, "MAC");
+               for (i = 0; i < msg->log_msg_hwaddr_len; i++)
+                       nl_dump(p, "%c%02x", i?':':'=', msg->log_msg_hwaddr[i]);
+               nl_dump(p, " ");
+       }
+
+       /* FIXME: parse the payload to get iptables LOG compatible format */
+
+       if (msg->ce_mask & LOG_MSG_ATTR_FAMILY)
+               nl_dump(p, "FAMILY=%s ",
+                       nl_af2str(msg->log_msg_family, buf, sizeof(buf)));
+
+       if (msg->ce_mask & LOG_MSG_ATTR_HWPROTO)
+               nl_dump(p, "HWPROTO=%s ",
+                       nl_ether_proto2str(ntohs(msg->log_msg_hwproto),
+                                          buf, sizeof(buf)));
+
+       if (msg->ce_mask & LOG_MSG_ATTR_HOOK)
+               nl_dump(p, "HOOK=%s ",
+                       nfnl_inet_hook2str(msg->log_msg_hook,
+                                          buf, sizeof(buf)));
+
+       if (msg->ce_mask & LOG_MSG_ATTR_MARK)
+               nl_dump(p, "MARK=%u ", msg->log_msg_mark);
+
+       if (msg->ce_mask & LOG_MSG_ATTR_PAYLOAD)
+               nl_dump(p, "PAYLOADLEN=%d ", msg->log_msg_payload_len);
+
+       if (msg->ce_mask & LOG_MSG_ATTR_UID)
+               nl_dump(p, "UID=%u ", msg->log_msg_uid);
+
+       if (msg->ce_mask & LOG_MSG_ATTR_GID)
+               nl_dump(p, "GID=%u ", msg->log_msg_gid);
+
+       if (msg->ce_mask & LOG_MSG_ATTR_SEQ)
+               nl_dump(p, "SEQ=%d ", msg->log_msg_seq);
+
+       if (msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL)
+               nl_dump(p, "SEQGLOBAL=%d ", msg->log_msg_seq_global);
+
+       nl_dump(p, "\n");
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_log_msg *nfnl_log_msg_alloc(void)
+{
+       return (struct nfnl_log_msg *) nl_object_alloc(&log_msg_obj_ops);
+}
+
+void nfnl_log_msg_get(struct nfnl_log_msg *msg)
+{
+       nl_object_get((struct nl_object *) msg);
+}
+
+void nfnl_log_msg_put(struct nfnl_log_msg *msg)
+{
+       nl_object_put((struct nl_object *) msg);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_log_msg_set_family(struct nfnl_log_msg *msg, uint8_t family)
+{
+       msg->log_msg_family = family;
+       msg->ce_mask |= LOG_MSG_ATTR_FAMILY;
+}
+
+uint8_t nfnl_log_msg_get_family(const struct nfnl_log_msg *msg)
+{
+       if (msg->ce_mask & LOG_MSG_ATTR_FAMILY)
+               return msg->log_msg_family;
+       else
+               return AF_UNSPEC;
+}
+
+void nfnl_log_msg_set_hwproto(struct nfnl_log_msg *msg, uint16_t hwproto)
+{
+       msg->log_msg_hwproto = hwproto;
+       msg->ce_mask |= LOG_MSG_ATTR_HWPROTO;
+}
+
+int nfnl_log_msg_test_hwproto(const struct nfnl_log_msg *msg)
+{
+       return !!(msg->ce_mask & LOG_MSG_ATTR_HWPROTO);
+}
+
+uint16_t nfnl_log_msg_get_hwproto(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_hwproto;
+}
+
+void nfnl_log_msg_set_hook(struct nfnl_log_msg *msg, uint8_t hook)
+{
+       msg->log_msg_hook = hook;
+       msg->ce_mask |= LOG_MSG_ATTR_HOOK;
+}
+
+int nfnl_log_msg_test_hook(const struct nfnl_log_msg *msg)
+{
+       return !!(msg->ce_mask & LOG_MSG_ATTR_HOOK);
+}
+
+uint8_t nfnl_log_msg_get_hook(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_hook;
+}
+
+void nfnl_log_msg_set_mark(struct nfnl_log_msg *msg, uint32_t mark)
+{
+       msg->log_msg_mark = mark;
+       msg->ce_mask |= LOG_MSG_ATTR_MARK;
+}
+
+int nfnl_log_msg_test_mark(const struct nfnl_log_msg *msg)
+{
+       return !!(msg->ce_mask & LOG_MSG_ATTR_MARK);
+}
+
+uint32_t nfnl_log_msg_get_mark(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_mark;
+}
+
+void nfnl_log_msg_set_timestamp(struct nfnl_log_msg *msg, struct timeval *tv)
+{
+       msg->log_msg_timestamp.tv_sec = tv->tv_sec;
+       msg->log_msg_timestamp.tv_usec = tv->tv_usec;
+       msg->ce_mask |= LOG_MSG_ATTR_TIMESTAMP;
+}
+
+const struct timeval *nfnl_log_msg_get_timestamp(const struct nfnl_log_msg *msg)
+{
+       if (!(msg->ce_mask & LOG_MSG_ATTR_TIMESTAMP))
+               return NULL;
+       return &msg->log_msg_timestamp;
+}
+
+void nfnl_log_msg_set_indev(struct nfnl_log_msg *msg, uint32_t indev)
+{
+       msg->log_msg_indev = indev;
+       msg->ce_mask |= LOG_MSG_ATTR_INDEV;
+}
+
+uint32_t nfnl_log_msg_get_indev(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_indev;
+}
+
+void nfnl_log_msg_set_outdev(struct nfnl_log_msg *msg, uint32_t outdev)
+{
+       msg->log_msg_outdev = outdev;
+       msg->ce_mask |= LOG_MSG_ATTR_OUTDEV;
+}
+
+uint32_t nfnl_log_msg_get_outdev(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_outdev;
+}
+
+void nfnl_log_msg_set_physindev(struct nfnl_log_msg *msg, uint32_t physindev)
+{
+       msg->log_msg_physindev = physindev;
+       msg->ce_mask |= LOG_MSG_ATTR_PHYSINDEV;
+}
+
+uint32_t nfnl_log_msg_get_physindev(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_physindev;
+}
+
+void nfnl_log_msg_set_physoutdev(struct nfnl_log_msg *msg, uint32_t physoutdev)
+{
+       msg->log_msg_physoutdev = physoutdev;
+       msg->ce_mask |= LOG_MSG_ATTR_PHYSOUTDEV;
+}
+
+uint32_t nfnl_log_msg_get_physoutdev(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_physoutdev;
+}
+
+void nfnl_log_msg_set_hwaddr(struct nfnl_log_msg *msg, uint8_t *hwaddr, int len)
+{
+       if (len > sizeof(msg->log_msg_hwaddr))
+               len = sizeof(msg->log_msg_hwaddr);
+       msg->log_msg_hwaddr_len = len;
+       memcpy(msg->log_msg_hwaddr, hwaddr, len);
+       msg->ce_mask |= LOG_MSG_ATTR_HWADDR;
+}
+
+const uint8_t *nfnl_log_msg_get_hwaddr(const struct nfnl_log_msg *msg, int *len)
+{
+       if (!(msg->ce_mask & LOG_MSG_ATTR_HWADDR)) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = msg->log_msg_hwaddr_len;
+       return msg->log_msg_hwaddr;
+}
+
+int nfnl_log_msg_set_payload(struct nfnl_log_msg *msg, uint8_t *payload, int len)
+{
+       free(msg->log_msg_payload);
+       msg->log_msg_payload = malloc(len);
+       if (!msg->log_msg_payload)
+               return -NLE_NOMEM;
+
+       memcpy(msg->log_msg_payload, payload, len);
+       msg->log_msg_payload_len = len;
+       msg->ce_mask |= LOG_MSG_ATTR_PAYLOAD;
+       return 0;
+}
+
+const void *nfnl_log_msg_get_payload(const struct nfnl_log_msg *msg, int *len)
+{
+       if (!(msg->ce_mask & LOG_MSG_ATTR_PAYLOAD)) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = msg->log_msg_payload_len;
+       return msg->log_msg_payload;
+}
+
+int nfnl_log_msg_set_prefix(struct nfnl_log_msg *msg, void *prefix)
+{
+       free(msg->log_msg_prefix);
+       msg->log_msg_prefix = strdup(prefix);
+       if (!msg->log_msg_prefix)
+               return -NLE_NOMEM;
+
+       msg->ce_mask |= LOG_MSG_ATTR_PREFIX;
+       return 0;
+}
+
+const char *nfnl_log_msg_get_prefix(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_prefix;
+}
+
+void nfnl_log_msg_set_uid(struct nfnl_log_msg *msg, uint32_t uid)
+{
+       msg->log_msg_uid = uid;
+       msg->ce_mask |= LOG_MSG_ATTR_UID;
+}
+
+int nfnl_log_msg_test_uid(const struct nfnl_log_msg *msg)
+{
+       return !!(msg->ce_mask & LOG_MSG_ATTR_UID);
+}
+
+uint32_t nfnl_log_msg_get_uid(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_uid;
+}
+
+void nfnl_log_msg_set_gid(struct nfnl_log_msg *msg, uint32_t gid)
+{
+       msg->log_msg_gid = gid;
+       msg->ce_mask |= LOG_MSG_ATTR_GID;
+}
+
+int nfnl_log_msg_test_gid(const struct nfnl_log_msg *msg)
+{
+       return !!(msg->ce_mask & LOG_MSG_ATTR_GID);
+}
+
+uint32_t nfnl_log_msg_get_gid(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_gid;
+}
+
+
+void nfnl_log_msg_set_seq(struct nfnl_log_msg *msg, uint32_t seq)
+{
+       msg->log_msg_seq = seq;
+       msg->ce_mask |= LOG_MSG_ATTR_SEQ;
+}
+
+int nfnl_log_msg_test_seq(const struct nfnl_log_msg *msg)
+{
+       return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ);
+}
+
+uint32_t nfnl_log_msg_get_seq(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_seq;
+}
+
+void nfnl_log_msg_set_seq_global(struct nfnl_log_msg *msg, uint32_t seq_global)
+{
+       msg->log_msg_seq_global = seq_global;
+       msg->ce_mask |= LOG_MSG_ATTR_SEQ_GLOBAL;
+}
+
+int nfnl_log_msg_test_seq_global(const struct nfnl_log_msg *msg)
+{
+       return !!(msg->ce_mask & LOG_MSG_ATTR_SEQ_GLOBAL);
+}
+
+uint32_t nfnl_log_msg_get_seq_global(const struct nfnl_log_msg *msg)
+{
+       return msg->log_msg_seq_global;
+}
+
+/** @} */
+
+struct nl_object_ops log_msg_obj_ops = {
+       .oo_name                = "netfilter/log_msg",
+       .oo_size                = sizeof(struct nfnl_log_msg),
+       .oo_free_data           = log_msg_free_data,
+       .oo_clone               = log_msg_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = log_msg_dump,
+           [NL_DUMP_DETAILS]   = log_msg_dump,
+           [NL_DUMP_STATS]     = log_msg_dump,
+       },
+};
+
+/** @} */
diff --git a/lib/netfilter/log_obj.c b/lib/netfilter/log_obj.c
new file mode 100644 (file)
index 0000000..2b11414
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * lib/netfilter/log_obj.c     Netfilter Log Object
+ *
+ *     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) 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>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log.h>
+
+/** @cond SKIP */
+#define LOG_ATTR_GROUP                 (1UL << 0)
+#define LOG_ATTR_COPY_MODE             (1UL << 1)
+#define LOG_ATTR_COPY_RANGE            (1UL << 3)
+#define LOG_ATTR_FLUSH_TIMEOUT         (1UL << 4)
+#define LOG_ATTR_ALLOC_SIZE            (1UL << 5)
+#define LOG_ATTR_QUEUE_THRESHOLD       (1UL << 6)
+
+/** @endcond */
+
+static void nfnl_log_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_log *log = (struct nfnl_log *) a;
+       char buf[64];
+
+       nl_new_line(p);
+
+       if (log->ce_mask & LOG_ATTR_GROUP)
+               nl_dump(p, "group=%u ", log->log_group);
+
+       if (log->ce_mask & LOG_ATTR_COPY_MODE)
+               nl_dump(p, "copy_mode=%s ",
+                       nfnl_log_copy_mode2str(log->log_copy_mode,
+                                              buf, sizeof(buf)));
+
+       if (log->ce_mask & LOG_ATTR_COPY_RANGE)
+               nl_dump(p, "copy_range=%u ", log->log_copy_range);
+
+       if (log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT)
+               nl_dump(p, "flush_timeout=%u ", log->log_flush_timeout);
+
+       if (log->ce_mask & LOG_ATTR_ALLOC_SIZE)
+               nl_dump(p, "alloc_size=%u ", log->log_alloc_size);
+
+       if (log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD)
+               nl_dump(p, "queue_threshold=%u ", log->log_queue_threshold);
+
+       nl_dump(p, "\n");
+}
+
+static const struct trans_tbl copy_modes[] = {
+       __ADD(NFNL_LOG_COPY_NONE,       none)
+       __ADD(NFNL_LOG_COPY_META,       meta)
+       __ADD(NFNL_LOG_COPY_PACKET,     packet)
+};
+
+char *nfnl_log_copy_mode2str(enum nfnl_log_copy_mode copy_mode, char *buf,
+                            size_t len)
+{
+       return __type2str(copy_mode, buf, len, copy_modes,
+                         ARRAY_SIZE(copy_modes));
+}
+
+enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *name)
+{
+       return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_log *nfnl_log_alloc(void)
+{
+       return (struct nfnl_log *) nl_object_alloc(&log_obj_ops);
+}
+
+void nfnl_log_get(struct nfnl_log *log)
+{
+       nl_object_get((struct nl_object *) log);
+}
+
+void nfnl_log_put(struct nfnl_log *log)
+{
+       nl_object_put((struct nl_object *) log);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_log_set_group(struct nfnl_log *log, uint16_t group)
+{
+       log->log_group = group;
+       log->ce_mask |= LOG_ATTR_GROUP;
+}
+
+int nfnl_log_test_group(const struct nfnl_log *log)
+{
+       return !!(log->ce_mask & LOG_ATTR_GROUP);
+}
+
+uint16_t nfnl_log_get_group(const struct nfnl_log *log)
+{
+       return log->log_group;
+}
+
+void nfnl_log_set_copy_mode(struct nfnl_log *log, enum nfnl_log_copy_mode mode)
+{
+       log->log_copy_mode = mode;
+       log->ce_mask |= LOG_ATTR_COPY_MODE;
+}
+
+int nfnl_log_test_copy_mode(const struct nfnl_log *log)
+{
+       return !!(log->ce_mask & LOG_ATTR_COPY_MODE);
+}
+
+enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *log)
+{
+       return log->log_copy_mode;
+}
+
+void nfnl_log_set_copy_range(struct nfnl_log *log, uint32_t copy_range)
+{
+       log->log_copy_range = copy_range;
+       log->ce_mask |= LOG_ATTR_COPY_RANGE;
+}
+
+int nfnl_log_test_copy_range(const struct nfnl_log *log)
+{
+       return !!(log->ce_mask & LOG_ATTR_COPY_RANGE);
+}
+
+uint32_t nfnl_log_get_copy_range(const struct nfnl_log *log)
+{
+       return log->log_copy_range;
+}
+
+void nfnl_log_set_flush_timeout(struct nfnl_log *log, uint32_t timeout)
+{
+       log->log_flush_timeout = timeout;
+       log->ce_mask |= LOG_ATTR_FLUSH_TIMEOUT;
+}
+
+int nfnl_log_test_flush_timeout(const struct nfnl_log *log)
+{
+       return !!(log->ce_mask & LOG_ATTR_FLUSH_TIMEOUT);
+}
+
+uint32_t nfnl_log_get_flush_timeout(const struct nfnl_log *log)
+{
+       return log->log_flush_timeout;
+}
+
+void nfnl_log_set_alloc_size(struct nfnl_log *log, uint32_t alloc_size)
+{
+       log->log_alloc_size = alloc_size;
+       log->ce_mask |= LOG_ATTR_ALLOC_SIZE;
+}
+
+int nfnl_log_test_alloc_size(const struct nfnl_log *log)
+{
+       return !!(log->ce_mask & LOG_ATTR_ALLOC_SIZE);
+}
+
+uint32_t nfnl_log_get_alloc_size(const struct nfnl_log *log)
+{
+       return log->log_alloc_size;
+}
+
+void nfnl_log_set_queue_threshold(struct nfnl_log *log, uint32_t threshold)
+{
+       log->log_queue_threshold = threshold;
+       log->ce_mask |= LOG_ATTR_QUEUE_THRESHOLD;
+}
+
+int nfnl_log_test_queue_threshold(const struct nfnl_log *log)
+{
+       return !!(log->ce_mask & LOG_ATTR_QUEUE_THRESHOLD);
+}
+
+uint32_t nfnl_log_get_queue_threshold(const struct nfnl_log *log)
+{
+       return log->log_queue_threshold;
+}
+
+/* We don't actually use the flags for anything yet since the
+ * nfnetlog_log interface truly sucks - it only contains the
+ * flag value, but not mask, so we would have to make assumptions
+ * about the supported flags.
+ */
+void nfnl_log_set_flags(struct nfnl_log *log, unsigned int flags)
+{
+       log->log_flags |= flags;
+       log->log_flag_mask |= flags;
+}
+
+void nfnl_log_unset_flags(struct nfnl_log *log, unsigned int flags)
+{
+       log->log_flags &= ~flags;
+       log->log_flag_mask |= flags;
+}
+
+static const struct trans_tbl log_flags[] = {
+       __ADD(NFNL_LOG_FLAG_SEQ,        seq)
+       __ADD(NFNL_LOG_FLAG_SEQ_GLOBAL, seq_global)
+};
+
+char *nfnl_log_flags2str(unsigned int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, log_flags, ARRAY_SIZE(log_flags));
+}
+
+unsigned int nfnl_log_str2flags(const char *name)
+{
+       return __str2flags(name, log_flags, ARRAY_SIZE(log_flags));
+}
+
+static int nfnl_log_compare(struct nl_object *_a, struct nl_object *_b,
+                           uint32_t attrs, int flags)
+{
+       struct nfnl_log *a = (struct nfnl_log *) _a;
+       struct nfnl_log *b = (struct nfnl_log *) _b;
+       int diff = 0;
+
+#define NFNL_LOG_DIFF(ATTR, EXPR) \
+       ATTR_DIFF(attrs, LOG_ATTR_##ATTR, a, b, EXPR)
+#define NFNL_LOG_DIFF_VAL(ATTR, FIELD) \
+       NFNL_LOG_DIFF(ATTR, a->FIELD != b->FIELD)
+
+       diff |= NFNL_LOG_DIFF_VAL(GROUP,                log_group);
+       diff |= NFNL_LOG_DIFF_VAL(COPY_MODE,            log_copy_mode);
+       diff |= NFNL_LOG_DIFF_VAL(COPY_RANGE,           log_copy_range);
+       diff |= NFNL_LOG_DIFF_VAL(FLUSH_TIMEOUT,        log_flush_timeout);
+       diff |= NFNL_LOG_DIFF_VAL(ALLOC_SIZE,           log_alloc_size);
+       diff |= NFNL_LOG_DIFF_VAL(QUEUE_THRESHOLD,      log_queue_threshold);
+
+#undef NFNL_LOG_DIFF
+#undef NFNL_LOG_DIFF_VAL
+
+       return diff;
+}
+
+static const struct trans_tbl nfnl_log_attrs[] = {
+       __ADD(LOG_ATTR_GROUP,           group)
+       __ADD(LOG_ATTR_COPY_MODE,       copy_mode)
+       __ADD(LOG_ATTR_COPY_RANGE,      copy_range)
+       __ADD(LOG_ATTR_FLUSH_TIMEOUT,   flush_timeout)
+       __ADD(LOG_ATTR_ALLOC_SIZE,      alloc_size)
+       __ADD(LOG_ATTR_QUEUE_THRESHOLD, queue_threshold)
+};
+
+static char *nfnl_log_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, nfnl_log_attrs,
+                          ARRAY_SIZE(nfnl_log_attrs));
+}
+
+/** @} */
+
+struct nl_object_ops log_obj_ops = {
+       .oo_name                = "netfilter/log",
+       .oo_size                = sizeof(struct nfnl_log),
+       .oo_dump = {
+           [NL_DUMP_LINE]      = nfnl_log_dump,
+           [NL_DUMP_DETAILS]   = nfnl_log_dump,
+           [NL_DUMP_STATS]     = nfnl_log_dump,
+       },
+       .oo_compare             = nfnl_log_compare,
+       .oo_attrs2str           = nfnl_log_attrs2str,
+       .oo_id_attrs            = LOG_ATTR_GROUP,
+};
+
+/** @} */
diff --git a/lib/netfilter/netfilter.c b/lib/netfilter/netfilter.c
new file mode 100644 (file)
index 0000000..0062994
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * lib/netfilter/netfilter.c    Netfilter Generic Functions
+ *
+ *     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 Patrick McHardy <kaber@trash.net>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netfilter/netfilter.h>
+#include <linux/netfilter.h>
+
+static const struct trans_tbl nfnl_verdicts[] = {
+       __ADD(NF_DROP,          NF_DROP)
+       __ADD(NF_ACCEPT,        NF_ACCEPT)
+       __ADD(NF_STOLEN,        NF_STOLEN)
+       __ADD(NF_QUEUE,         NF_QUEUE)
+       __ADD(NF_REPEAT,        NF_REPEAT)
+       __ADD(NF_STOP,          NF_STOP)
+};
+
+char *nfnl_verdict2str(unsigned int verdict, char *buf, size_t len)
+{
+       return __type2str(verdict, buf, len, nfnl_verdicts,
+                         ARRAY_SIZE(nfnl_verdicts));
+}
+
+unsigned int nfnl_str2verdict(const char *name)
+{
+       return __str2type(name, nfnl_verdicts, ARRAY_SIZE(nfnl_verdicts));
+}
+
+static const struct trans_tbl nfnl_inet_hooks[] = {
+       __ADD(NF_INET_PRE_ROUTING,      NF_INET_PREROUTING)
+       __ADD(NF_INET_LOCAL_IN,         NF_INET_LOCAL_IN)
+       __ADD(NF_INET_FORWARD,          NF_INET_FORWARD)
+       __ADD(NF_INET_LOCAL_OUT,        NF_INET_LOCAL_OUT)
+       __ADD(NF_INET_POST_ROUTING,     NF_INET_POST_ROUTING)
+};
+
+char *nfnl_inet_hook2str(unsigned int hook, char *buf, size_t len)
+{
+       return __type2str(hook, buf, len, nfnl_inet_hooks,
+                         ARRAY_SIZE(nfnl_inet_hooks));
+}
+
+unsigned int nfnl_str2inet_hook(const char *name)
+{
+       return __str2type(name, nfnl_inet_hooks, ARRAY_SIZE(nfnl_inet_hooks));
+}
diff --git a/lib/netfilter/nfnl.c b/lib/netfilter/nfnl.c
new file mode 100644 (file)
index 0000000..f028a85
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * lib/netfilter/nfnl.c                Netfilter Netlink
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+/**
+ * @defgroup nfnl Netfilter Library (libnl-nf)
+ *
+ * @par Message Format
+ * @code
+ *  <------- NLMSG_ALIGN(hlen) ------> <---- NLMSG_ALIGN(len) --->
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * |           Header           | Pad |       Payload       | Pad |
+ * |      struct nlmsghdr       |     |                     |     |
+ * +----------------------------+- - -+- - - - - - - - - - -+- - -+
+ * @endcode
+ * @code
+ *  <-------- NFNL_HDRLEN --------->
+ * +--------------------------+- - -+------------+
+ * | Netfilter Netlink Header | Pad | Attributes |
+ * |    struct nfgenmsg       |     |            |
+ * +--------------------------+- - -+------------+
+ * nfnlmsg_attrdata(nfg, hdrlen)-----^
+ * @endcode
+ *
+ * @par 1) Creating a new netfilter netlink message
+ * @code
+ * struct nl_msg *msg;
+ *
+ * // Create a new empty netlink message
+ * msg = nlmsg_alloc();
+ *
+ * // Append the netlink and netfilter netlink message header
+ * hdr = nfnlmsg_put(msg, PID, SEQ, SUBSYS, TYPE, NLM_F_ECHO,
+ *                   FAMILY, RES_ID);
+ *
+ * // Append the attributes.
+ * nla_put_u32(msg, 1, 0x10);
+ *
+ * // Message is ready to be sent.
+ * nl_send_auto_complete(sk, msg);
+ *
+ * // All done? Free the message.
+ * nlmsg_free(msg);
+ * @endcode
+ *
+ * @par 2) Sending of trivial messages
+ * @code
+ * // For trivial messages not requiring any subsys specific header or
+ * // attributes, nfnl_send_simple() may be used to send messages directly.
+ * nfnl_send_simple(sk, SUBSYS, TYPE, 0, FAMILY, RES_ID);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+
+/**
+ * @name Socket Creating
+ * @{
+ */
+
+/**
+ * Create and connect netfilter netlink socket.
+ * @arg sk             Netlink socket.
+ *
+ * Creates a NETLINK_NETFILTER netlink socket, binds the socket and
+ * issues a connection attempt.
+ *
+ * @see nl_connect()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nfnl_connect(struct nl_sock *sk)
+{
+       return nl_connect(sk, NETLINK_NETFILTER);
+}
+
+/** @} */
+
+/**
+ * @name Sending
+ * @{
+ */
+
+/**
+ * Send trivial netfilter netlink message
+ * @arg sk             Netlink socket.
+ * @arg subsys_id      nfnetlink subsystem
+ * @arg type           nfnetlink message type
+ * @arg flags          message flags
+ * @arg family         nfnetlink address family
+ * @arg res_id         nfnetlink resource id
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type,
+                    int flags, uint8_t family, uint16_t res_id)
+{
+       struct nfgenmsg hdr = {
+               .nfgen_family = family,
+               .version = NFNETLINK_V0,
+               .res_id = htons(res_id),
+       };
+
+       return nl_send_simple(sk, NFNLMSG_TYPE(subsys_id, type), flags,
+                             &hdr, sizeof(hdr));
+}
+
+/** @} */
+
+/**
+ * @name Message Parsing
+ * @{
+ */
+
+/**
+ * Get netfilter subsystem id from message
+ * @arg nlh    netlink messsage header
+ */
+uint8_t nfnlmsg_subsys(struct nlmsghdr *nlh)
+{
+       return NFNL_SUBSYS_ID(nlh->nlmsg_type);
+}
+
+/**
+ * Get netfilter message type from message
+ * @arg nlh    netlink messsage header
+ */
+uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
+{
+       return NFNL_MSG_TYPE(nlh->nlmsg_type);
+}
+
+/**
+ * Get netfilter family from message
+ * @arg nlh    netlink messsage header
+ */
+uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
+{
+       struct nfgenmsg *nfg = nlmsg_data(nlh);
+
+       return nfg->nfgen_family;
+}
+
+/**
+ * Get netfilter resource id from message
+ * @arg nlh    netlink messsage header
+ */
+uint16_t nfnlmsg_res_id(struct nlmsghdr *nlh)
+{
+       struct nfgenmsg *nfg = nlmsg_data(nlh);
+
+       return ntohs(nfg->res_id);
+}
+
+/** @} */
+
+/**
+ * @name Message Building
+ * @{
+ */
+
+static int nfnlmsg_append(struct nl_msg *msg, uint8_t family, uint16_t res_id)
+{
+       struct nfgenmsg *nfg;
+
+       nfg = nlmsg_reserve(msg, sizeof(*nfg), NLMSG_ALIGNTO);
+       if (nfg == NULL)
+               return -NLE_NOMEM;
+
+       nfg->nfgen_family = family;
+       nfg->version = NFNETLINK_V0;
+       nfg->res_id = htons(res_id);
+       NL_DBG(2, "msg %p: Added nfnetlink header family=%d res_id=%d\n",
+              msg, family, res_id);
+       return 0;
+}
+
+/**
+ * Allocate a new netfilter netlink message
+ * @arg subsys_id      nfnetlink subsystem
+ * @arg type           nfnetlink message type
+ * @arg flags          message flags
+ * @arg family         nfnetlink address family
+ * @arg res_id         nfnetlink resource id
+ *
+ * @return Newly allocated netlink message or NULL.
+ */
+struct nl_msg *nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags,
+                                   uint8_t family, uint16_t res_id)
+{
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc_simple(NFNLMSG_TYPE(subsys_id, type), flags);
+       if (msg == NULL)
+               return NULL;
+
+       if (nfnlmsg_append(msg, family, res_id) < 0)
+               goto nla_put_failure;
+
+       return msg;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return NULL;
+}
+
+/**
+ * Add netlink and netfilter netlink headers to netlink message
+ * @arg msg            netlink message
+ * @arg pid            netlink process id
+ * @arg seq            sequence number of message
+ * @arg subsys_id      nfnetlink subsystem
+ * @arg type           nfnetlink message type
+ * @arg flags          message flags
+ * @arg family         nfnetlink address family
+ * @arg res_id         nfnetlink resource id
+ */
+int nfnlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq,
+               uint8_t subsys_id, uint8_t type, int flags, uint8_t family,
+               uint16_t res_id)
+{
+       struct nlmsghdr *nlh;
+
+       nlh = nlmsg_put(msg, pid, seq, NFNLMSG_TYPE(subsys_id, type), 0, flags);
+       if (nlh == NULL)
+               return -NLE_MSGSIZE;
+
+       return nfnlmsg_append(msg, family, res_id);
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/netfilter/queue.c b/lib/netfilter/queue.c
new file mode 100644 (file)
index 0000000..5655647
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * lib/netfilter/queue.c       Netfilter Queue
+ *
+ *     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) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup queue Queue
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue.h>
+
+struct nl_sock *nfnl_queue_socket_alloc(void)
+{
+       struct nl_sock *nlsk;
+
+       nlsk = nl_socket_alloc();
+       if (nlsk)
+               nl_socket_disable_auto_ack(nlsk);
+       return nlsk;
+}
+
+static int send_queue_request(struct nl_sock *sk, struct nl_msg *msg)
+{
+       int err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/**
+ * @name Queue Commands
+ * @{
+ */
+
+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;
+
+       msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
+                                  family, queuenum);
+       if (msg == NULL)
+               return -NLE_NOMEM;
+
+       cmd.pf = htons(family);
+       cmd._pad = 0;
+       cmd.command = command;
+       if (nla_put(msg, NFQA_CFG_CMD, sizeof(cmd), &cmd) < 0)
+               goto nla_put_failure;
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+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, result);
+}
+
+int nfnl_queue_pf_bind(struct nl_sock *nlh, uint8_t pf)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_queue_build_pf_bind(pf, &msg)) < 0)
+               return err;
+
+       return send_queue_request(nlh, msg);
+}
+
+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, result);
+}
+
+int nfnl_queue_pf_unbind(struct nl_sock *nlh, uint8_t pf)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_queue_build_pf_unbind(pf, &msg)) < 0)
+               return err;
+
+       return send_queue_request(nlh, msg);
+}
+
+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 -NLE_MISSING_ATTR;
+
+       msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_CONFIG, 0,
+                                  0, nfnl_queue_get_group(queue));
+       if (msg == NULL)
+               return -NLE_NOMEM;
+
+       if (nfnl_queue_test_maxlen(queue) &&
+           nla_put_u32(msg, NFQA_CFG_QUEUE_MAXLEN,
+                       htonl(nfnl_queue_get_maxlen(queue))) < 0)
+               goto nla_put_failure;
+
+       /* This sucks, the nfnetlink_queue interface always expects both
+        * parameters to be present. Needs to be done properly.
+        */
+       if (nfnl_queue_test_copy_mode(queue)) {
+               struct nfqnl_msg_config_params params;
+
+               switch (nfnl_queue_get_copy_mode(queue)) {
+               case NFNL_QUEUE_COPY_NONE:
+                       params.copy_mode = NFQNL_COPY_NONE;
+                       break;
+               case NFNL_QUEUE_COPY_META:
+                       params.copy_mode = NFQNL_COPY_META;
+                       break;
+               case NFNL_QUEUE_COPY_PACKET:
+                       params.copy_mode = NFQNL_COPY_PACKET;
+                       break;
+               }
+               params.copy_range = htonl(nfnl_queue_get_copy_range(queue));
+
+               if (nla_put(msg, NFQA_CFG_PARAMS, sizeof(params), &params) < 0)
+                       goto nla_put_failure;
+       }
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+int nfnl_queue_build_create_request(const struct nfnl_queue *queue,
+                                   struct nl_msg **result)
+{
+       struct nfqnl_msg_config_cmd cmd;
+       int err;
+
+       if ((err = nfnl_queue_build_request(queue, result)) < 0)
+               return err;
+
+       cmd.pf = 0;
+       cmd._pad = 0;
+       cmd.command = NFQNL_CFG_CMD_BIND;
+
+       NLA_PUT(*result, NFQA_CFG_CMD, sizeof(cmd), &cmd);
+
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(*result);
+       return -NLE_MSGSIZE;
+}
+
+int nfnl_queue_create(struct nl_sock *nlh, const struct nfnl_queue *queue)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_queue_build_create_request(queue, &msg)) < 0)
+               return err;
+
+       return send_queue_request(nlh, msg);
+}
+
+int nfnl_queue_build_change_request(const struct nfnl_queue *queue,
+                                   struct nl_msg **result)
+{
+       return nfnl_queue_build_request(queue, result);
+}
+
+int nfnl_queue_change(struct nl_sock *nlh, const struct nfnl_queue *queue)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_queue_build_change_request(queue, &msg)) < 0)
+               return err;
+
+       return send_queue_request(nlh, msg);
+}
+
+int nfnl_queue_build_delete_request(const struct nfnl_queue *queue,
+                                   struct nl_msg **result)
+{
+       if (!nfnl_queue_test_group(queue))
+               return -NLE_MISSING_ATTR;
+
+       return build_queue_cmd_request(0, nfnl_queue_get_group(queue),
+                                      NFQNL_CFG_CMD_UNBIND, result);
+}
+
+int nfnl_queue_delete(struct nl_sock *nlh, const struct nfnl_queue *queue)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = nfnl_queue_build_delete_request(queue, &msg)) < 0)
+               return err;
+
+       return send_queue_request(nlh, msg);
+}
+
+/** @} */
+
+static struct nl_cache_ops nfnl_queue_ops = {
+       .co_name                = "netfilter/queue",
+       .co_obj_ops             = &queue_obj_ops,
+       .co_msgtypes            = {
+               END_OF_MSGTYPES_LIST,
+       },
+};
+
+static void __init nfnl_queue_init(void)
+{
+       nl_cache_mngt_register(&nfnl_queue_ops);
+}
+
+static void __exit nfnl_queue_exit(void)
+{
+       nl_cache_mngt_unregister(&nfnl_queue_ops);
+}
+
+/** @} */
diff --git a/lib/netfilter/queue_msg.c b/lib/netfilter/queue_msg.c
new file mode 100644 (file)
index 0000000..95d8ad3
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * lib/netfilter/queue_msg.c   Netfilter Queue Messages
+ *
+ *     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) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2010       Karl Hiramoto <karl@hiramoto.org>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup queue Queue
+ * @brief
+ * @{
+ */
+
+#include <sys/types.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue_msg.h>
+#include <byteswap.h>
+
+static struct nl_cache_ops nfnl_queue_msg_ops;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+       return x;
+}
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+static uint64_t ntohll(uint64_t x)
+{
+       return bswap_64(x);
+}
+#endif
+
+static struct nla_policy queue_policy[NFQA_MAX+1] = {
+       [NFQA_PACKET_HDR]               = {
+               .minlen = sizeof(struct nfqnl_msg_packet_hdr),
+       },
+       [NFQA_VERDICT_HDR]              = {
+               .minlen = sizeof(struct nfqnl_msg_verdict_hdr),
+       },
+       [NFQA_MARK]                     = { .type = NLA_U32 },
+       [NFQA_TIMESTAMP]                = {
+               .minlen = sizeof(struct nfqnl_msg_packet_timestamp),
+       },
+       [NFQA_IFINDEX_INDEV]            = { .type = NLA_U32 },
+       [NFQA_IFINDEX_OUTDEV]           = { .type = NLA_U32 },
+       [NFQA_IFINDEX_PHYSINDEV]        = { .type = NLA_U32 },
+       [NFQA_IFINDEX_PHYSOUTDEV]       = { .type = NLA_U32 },
+       [NFQA_HWADDR]                   = {
+               .minlen = sizeof(struct nfqnl_msg_packet_hw),
+       },
+};
+
+int nfnlmsg_queue_msg_parse(struct nlmsghdr *nlh,
+                           struct nfnl_queue_msg **result)
+{
+       struct nfnl_queue_msg *msg;
+       struct nlattr *tb[NFQA_MAX+1];
+       struct nlattr *attr;
+       int err;
+
+       msg = nfnl_queue_msg_alloc();
+       if (!msg)
+               return -NLE_NOMEM;
+
+       msg->ce_msgtype = nlh->nlmsg_type;
+
+       err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, NFQA_MAX,
+                         queue_policy);
+       if (err < 0)
+               goto errout;
+
+       nfnl_queue_msg_set_group(msg, nfnlmsg_res_id(nlh));
+       nfnl_queue_msg_set_family(msg, nfnlmsg_family(nlh));
+
+       attr = tb[NFQA_PACKET_HDR];
+       if (attr) {
+               struct nfqnl_msg_packet_hdr *hdr = nla_data(attr);
+
+               nfnl_queue_msg_set_packetid(msg, ntohl(hdr->packet_id));
+               if (hdr->hw_protocol)
+                       nfnl_queue_msg_set_hwproto(msg, hdr->hw_protocol);
+               nfnl_queue_msg_set_hook(msg, hdr->hook);
+       }
+
+       attr = tb[NFQA_MARK];
+       if (attr)
+               nfnl_queue_msg_set_mark(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFQA_TIMESTAMP];
+       if (attr) {
+               struct nfqnl_msg_packet_timestamp *timestamp = nla_data(attr);
+               struct timeval tv;
+
+               tv.tv_sec = ntohll(timestamp->sec);
+               tv.tv_usec = ntohll(timestamp->usec);
+               nfnl_queue_msg_set_timestamp(msg, &tv);
+       }
+
+       attr = tb[NFQA_IFINDEX_INDEV];
+       if (attr)
+               nfnl_queue_msg_set_indev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFQA_IFINDEX_OUTDEV];
+       if (attr)
+               nfnl_queue_msg_set_outdev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFQA_IFINDEX_PHYSINDEV];
+       if (attr)
+               nfnl_queue_msg_set_physindev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFQA_IFINDEX_PHYSOUTDEV];
+       if (attr)
+               nfnl_queue_msg_set_physoutdev(msg, ntohl(nla_get_u32(attr)));
+
+       attr = tb[NFQA_HWADDR];
+       if (attr) {
+               struct nfqnl_msg_packet_hw *hw = nla_data(attr);
+
+               nfnl_queue_msg_set_hwaddr(msg, hw->hw_addr,
+                                         ntohs(hw->hw_addrlen));
+       }
+
+       attr = tb[NFQA_PAYLOAD];
+       if (attr) {
+               err = nfnl_queue_msg_set_payload(msg, nla_data(attr),
+                                                nla_len(attr));
+               if (err < 0)
+                       goto errout;
+       }
+
+       *result = msg;
+       return 0;
+
+errout:
+       nfnl_queue_msg_put(msg);
+       return err;
+}
+
+static int queue_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                           struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct nfnl_queue_msg *msg;
+       int err;
+
+       if ((err = nfnlmsg_queue_msg_parse(nlh, &msg)) < 0)
+               goto errout;
+
+       err = pp->pp_cb((struct nl_object *) msg, pp);
+errout:
+       nfnl_queue_msg_put(msg);
+       return err;
+}
+
+/** @} */
+
+struct nl_msg *nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *msg)
+{
+       struct nl_msg *nlmsg;
+       struct nfqnl_msg_verdict_hdr verdict;
+
+       nlmsg = nfnlmsg_alloc_simple(NFNL_SUBSYS_QUEUE, NFQNL_MSG_VERDICT, 0,
+                                    nfnl_queue_msg_get_family(msg),
+                                    nfnl_queue_msg_get_group(msg));
+       if (nlmsg == NULL)
+               return NULL;
+
+       verdict.id = htonl(nfnl_queue_msg_get_packetid(msg));
+       verdict.verdict = htonl(nfnl_queue_msg_get_verdict(msg));
+       if (nla_put(nlmsg, NFQA_VERDICT_HDR, sizeof(verdict), &verdict) < 0)
+               goto nla_put_failure;
+
+       if (nfnl_queue_msg_test_mark(msg) &&
+           nla_put_u32(nlmsg, NFQA_MARK,
+                       ntohl(nfnl_queue_msg_get_mark(msg))) < 0)
+               goto nla_put_failure;
+
+       return nlmsg;
+
+nla_put_failure:
+       nlmsg_free(nlmsg);
+       return NULL;
+}
+
+/**
+* Send a message verdict/mark
+* @arg nlh            netlink messsage header
+* @arg msg            queue msg
+* @return 0 on OK or error code
+*/
+int nfnl_queue_msg_send_verdict(struct nl_sock *nlh,
+                               const struct nfnl_queue_msg *msg)
+{
+       struct nl_msg *nlmsg;
+       int err;
+
+       nlmsg = nfnl_queue_msg_build_verdict(msg);
+       if (nlmsg == NULL)
+               return -NLE_NOMEM;
+
+       err = nl_send_auto_complete(nlh, nlmsg);
+       nlmsg_free(nlmsg);
+       if (err < 0)
+               return err;
+       return wait_for_ack(nlh);
+}
+
+/**
+* Send a message verdict including the payload
+* @arg nlh            netlink messsage header
+* @arg msg            queue msg
+* @arg payload_data   packet payload data
+* @arg payload_len    payload length
+* @return 0 on OK or error code
+*/
+int nfnl_queue_msg_send_verdict_payload(struct nl_sock *nlh,
+                               const struct nfnl_queue_msg *msg,
+                               const void *payload_data, unsigned payload_len)
+{
+       struct nl_msg *nlmsg;
+       int err;
+       struct iovec iov[3];
+       struct nlattr nla;
+
+       nlmsg = nfnl_queue_msg_build_verdict(msg);
+       if (nlmsg == NULL)
+               return -NLE_NOMEM;
+
+       memset(iov, 0, sizeof(iov));
+
+       iov[0].iov_base = (void *) nlmsg_hdr(nlmsg);
+       iov[0].iov_len = nlmsg_hdr(nlmsg)->nlmsg_len;
+
+       nla.nla_type = NFQA_PAYLOAD;
+       nla.nla_len = payload_len + sizeof(nla);
+       nlmsg_hdr(nlmsg)->nlmsg_len += nla.nla_len;
+
+       iov[1].iov_base = (void *) &nla;
+       iov[1].iov_len = sizeof(nla);
+
+       iov[2].iov_base = (void *) payload_data;
+       iov[2].iov_len = NLA_ALIGN(payload_len);
+
+       nl_complete_msg(nlh, nlmsg);
+       err = nl_send_iovec(nlh, nlmsg, iov, 3);
+
+       nlmsg_free(nlmsg);
+       if (err < 0)
+               return err;
+       return wait_for_ack(nlh);
+}
+
+#define NFNLMSG_QUEUE_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_QUEUE, (type))
+static struct nl_cache_ops nfnl_queue_msg_ops = {
+       .co_name                = "netfilter/queue_msg",
+       .co_hdrsize             = NFNL_HDRLEN,
+       .co_msgtypes            = {
+               { NFNLMSG_QUEUE_TYPE(NFQNL_MSG_PACKET), NL_ACT_NEW, "new" },
+               END_OF_MSGTYPES_LIST,
+       },
+       .co_protocol            = NETLINK_NETFILTER,
+       .co_msg_parser          = queue_msg_parser,
+       .co_obj_ops             = &queue_msg_obj_ops,
+};
+
+static void __init nfnl_msg_queue_init(void)
+{
+       nl_cache_mngt_register(&nfnl_queue_msg_ops);
+}
+
+static void __exit nfnl_queue_msg_exit(void)
+{
+       nl_cache_mngt_unregister(&nfnl_queue_msg_ops);
+}
+
+/** @} */
diff --git a/lib/netfilter/queue_msg_obj.c b/lib/netfilter/queue_msg_obj.c
new file mode 100644 (file)
index 0000000..8085f1b
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ * lib/netfilter/queue_msg_obj.c       Netfilter Queue Message Object
+ *
+ *     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) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/netfilter.h>
+#include <netlink/netfilter/queue_msg.h>
+#include <linux/netfilter.h>
+
+/** @cond SKIP */
+#define QUEUE_MSG_ATTR_GROUP           (1UL << 0)
+#define QUEUE_MSG_ATTR_FAMILY          (1UL << 1)
+#define QUEUE_MSG_ATTR_PACKETID                (1UL << 2)
+#define QUEUE_MSG_ATTR_HWPROTO         (1UL << 3)
+#define QUEUE_MSG_ATTR_HOOK            (1UL << 4)
+#define QUEUE_MSG_ATTR_MARK            (1UL << 5)
+#define QUEUE_MSG_ATTR_TIMESTAMP       (1UL << 6)
+#define QUEUE_MSG_ATTR_INDEV           (1UL << 7)
+#define QUEUE_MSG_ATTR_OUTDEV          (1UL << 8)
+#define QUEUE_MSG_ATTR_PHYSINDEV       (1UL << 9)
+#define QUEUE_MSG_ATTR_PHYSOUTDEV      (1UL << 10)
+#define QUEUE_MSG_ATTR_HWADDR          (1UL << 11)
+#define QUEUE_MSG_ATTR_PAYLOAD         (1UL << 12)
+#define QUEUE_MSG_ATTR_VERDICT         (1UL << 13)
+/** @endcond */
+
+static void nfnl_queue_msg_free_data(struct nl_object *c)
+{
+       struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) c;
+
+       if (msg == NULL)
+               return;
+
+       free(msg->queue_msg_payload);
+}
+
+static int nfnl_queue_msg_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct nfnl_queue_msg *dst = (struct nfnl_queue_msg *) _dst;
+       struct nfnl_queue_msg *src = (struct nfnl_queue_msg *) _src;
+       int err;
+
+       if (src->queue_msg_payload) {
+               err = nfnl_queue_msg_set_payload(dst, src->queue_msg_payload,
+                                                src->queue_msg_payload_len);
+               if (err < 0)
+                       goto errout;
+       }
+
+       return 0;
+errout:
+       return err;
+}
+
+static void nfnl_queue_msg_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) a;
+       struct nl_cache *link_cache;
+       char buf[64];
+
+       link_cache = nl_cache_mngt_require_safe("route/link");
+
+       nl_new_line(p);
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_GROUP)
+               nl_dump(p, "GROUP=%u ", msg->queue_msg_group);
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_INDEV) {
+               if (link_cache)
+                       nl_dump(p, "IN=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->queue_msg_indev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "IN=%d ", msg->queue_msg_indev);
+       }
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV) {
+               if (link_cache)
+                       nl_dump(p, "PHYSIN=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->queue_msg_physindev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "IN=%d ", msg->queue_msg_physindev);
+       }
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV) {
+               if (link_cache)
+                       nl_dump(p, "OUT=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->queue_msg_outdev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "OUT=%d ", msg->queue_msg_outdev);
+       }
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV) {
+               if (link_cache)
+                       nl_dump(p, "PHYSOUT=%s ",
+                               rtnl_link_i2name(link_cache,
+                                                msg->queue_msg_physoutdev,
+                                                buf, sizeof(buf)));
+               else
+                       nl_dump(p, "PHYSOUT=%d ", msg->queue_msg_physoutdev);
+       }
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_HWADDR) {
+               int i;
+
+               nl_dump(p, "MAC");
+               for (i = 0; i < msg->queue_msg_hwaddr_len; i++)
+                       nl_dump(p, "%c%02x", i?':':'=',
+                               msg->queue_msg_hwaddr[i]);
+               nl_dump(p, " ");
+       }
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
+               nl_dump(p, "FAMILY=%s ",
+                       nl_af2str(msg->queue_msg_family, buf, sizeof(buf)));
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO)
+               nl_dump(p, "HWPROTO=%s ",
+                       nl_ether_proto2str(ntohs(msg->queue_msg_hwproto),
+                                          buf, sizeof(buf)));
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_HOOK)
+               nl_dump(p, "HOOK=%s ",
+                       nfnl_inet_hook2str(msg->queue_msg_hook,
+                                          buf, sizeof(buf)));
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_MARK)
+               nl_dump(p, "MARK=%d ", msg->queue_msg_mark);
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)
+               nl_dump(p, "PAYLOADLEN=%d ", msg->queue_msg_payload_len);
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_PACKETID)
+               nl_dump(p, "PACKETID=%u ", msg->queue_msg_packetid);
+
+       if (msg->ce_mask & QUEUE_MSG_ATTR_VERDICT)
+               nl_dump(p, "VERDICT=%s ",
+                       nfnl_verdict2str(msg->queue_msg_verdict,
+                                        buf, sizeof(buf)));
+
+       nl_dump(p, "\n");
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_queue_msg *nfnl_queue_msg_alloc(void)
+{
+       return (struct nfnl_queue_msg *) nl_object_alloc(&queue_msg_obj_ops);
+}
+
+void nfnl_queue_msg_get(struct nfnl_queue_msg *msg)
+{
+       nl_object_get((struct nl_object *) msg);
+}
+
+void nfnl_queue_msg_put(struct nfnl_queue_msg *msg)
+{
+       nl_object_put((struct nl_object *) msg);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_queue_msg_set_group(struct nfnl_queue_msg *msg, uint16_t group)
+{
+       msg->queue_msg_group = group;
+       msg->ce_mask |= QUEUE_MSG_ATTR_GROUP;
+}
+
+int nfnl_queue_msg_test_group(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_GROUP);
+}
+
+uint16_t nfnl_queue_msg_get_group(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_group;
+}
+
+/**
+* Set the protocol family
+* @arg msg         NF queue message
+* @arg family      AF_XXX  address family  example: AF_INET, AF_UNIX, etc
+*/
+void nfnl_queue_msg_set_family(struct nfnl_queue_msg *msg, uint8_t family)
+{
+       msg->queue_msg_family = family;
+       msg->ce_mask |= QUEUE_MSG_ATTR_FAMILY;
+}
+
+int nfnl_queue_msg_test_family(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_FAMILY);
+}
+
+uint8_t nfnl_queue_msg_get_family(const struct nfnl_queue_msg *msg)
+{
+       if (msg->ce_mask & QUEUE_MSG_ATTR_FAMILY)
+               return msg->queue_msg_family;
+       else
+               return AF_UNSPEC;
+}
+
+void nfnl_queue_msg_set_packetid(struct nfnl_queue_msg *msg, uint32_t packetid)
+{
+       msg->queue_msg_packetid = packetid;
+       msg->ce_mask |= QUEUE_MSG_ATTR_PACKETID;
+}
+
+int nfnl_queue_msg_test_packetid(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_PACKETID);
+}
+
+uint32_t nfnl_queue_msg_get_packetid(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_packetid;
+}
+
+void nfnl_queue_msg_set_hwproto(struct nfnl_queue_msg *msg, uint16_t hwproto)
+{
+       msg->queue_msg_hwproto = hwproto;
+       msg->ce_mask |= QUEUE_MSG_ATTR_HWPROTO;
+}
+
+int nfnl_queue_msg_test_hwproto(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWPROTO);
+}
+
+uint16_t nfnl_queue_msg_get_hwproto(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_hwproto;
+}
+
+void nfnl_queue_msg_set_hook(struct nfnl_queue_msg *msg, uint8_t hook)
+{
+       msg->queue_msg_hook = hook;
+       msg->ce_mask |= QUEUE_MSG_ATTR_HOOK;
+}
+
+int nfnl_queue_msg_test_hook(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_HOOK);
+}
+
+uint8_t nfnl_queue_msg_get_hook(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_hook;
+}
+
+void nfnl_queue_msg_set_mark(struct nfnl_queue_msg *msg, uint32_t mark)
+{
+       msg->queue_msg_mark = mark;
+       msg->ce_mask |= QUEUE_MSG_ATTR_MARK;
+}
+
+int nfnl_queue_msg_test_mark(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_MARK);
+}
+
+uint32_t nfnl_queue_msg_get_mark(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_mark;
+}
+
+void nfnl_queue_msg_set_timestamp(struct nfnl_queue_msg *msg,
+                                 struct timeval *tv)
+{
+       msg->queue_msg_timestamp.tv_sec = tv->tv_sec;
+       msg->queue_msg_timestamp.tv_usec = tv->tv_usec;
+       msg->ce_mask |= QUEUE_MSG_ATTR_TIMESTAMP;
+}
+
+int nfnl_queue_msg_test_timestamp(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP);
+}
+
+const struct timeval *nfnl_queue_msg_get_timestamp(const struct nfnl_queue_msg *msg)
+{
+       if (!(msg->ce_mask & QUEUE_MSG_ATTR_TIMESTAMP))
+               return NULL;
+       return &msg->queue_msg_timestamp;
+}
+
+void nfnl_queue_msg_set_indev(struct nfnl_queue_msg *msg, uint32_t indev)
+{
+       msg->queue_msg_indev = indev;
+       msg->ce_mask |= QUEUE_MSG_ATTR_INDEV;
+}
+
+int nfnl_queue_msg_test_indev(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_INDEV);
+}
+
+uint32_t nfnl_queue_msg_get_indev(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_indev;
+}
+
+void nfnl_queue_msg_set_outdev(struct nfnl_queue_msg *msg, uint32_t outdev)
+{
+       msg->queue_msg_outdev = outdev;
+       msg->ce_mask |= QUEUE_MSG_ATTR_OUTDEV;
+}
+
+int nfnl_queue_msg_test_outdev(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_OUTDEV);
+}
+
+uint32_t nfnl_queue_msg_get_outdev(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_outdev;
+}
+
+void nfnl_queue_msg_set_physindev(struct nfnl_queue_msg *msg,
+                                 uint32_t physindev)
+{
+       msg->queue_msg_physindev = physindev;
+       msg->ce_mask |= QUEUE_MSG_ATTR_PHYSINDEV;
+}
+
+int nfnl_queue_msg_test_physindev(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSINDEV);
+}
+
+uint32_t nfnl_queue_msg_get_physindev(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_physindev;
+}
+
+void nfnl_queue_msg_set_physoutdev(struct nfnl_queue_msg *msg,
+                                  uint32_t physoutdev)
+{
+       msg->queue_msg_physoutdev = physoutdev;
+       msg->ce_mask |= QUEUE_MSG_ATTR_PHYSOUTDEV;
+}
+
+int nfnl_queue_msg_test_physoutdev(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_PHYSOUTDEV);
+}
+
+uint32_t nfnl_queue_msg_get_physoutdev(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_physoutdev;
+}
+
+void nfnl_queue_msg_set_hwaddr(struct nfnl_queue_msg *msg, uint8_t *hwaddr,
+                              int len)
+{
+       if (len > sizeof(msg->queue_msg_hwaddr))
+               len = sizeof(msg->queue_msg_hwaddr);
+
+       msg->queue_msg_hwaddr_len = len;
+       memcpy(msg->queue_msg_hwaddr, hwaddr, len);
+       msg->ce_mask |= QUEUE_MSG_ATTR_HWADDR;
+}
+
+int nfnl_queue_msg_test_hwaddr(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR);
+}
+
+const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg,
+                                        int *len)
+{
+       if (!(msg->ce_mask & QUEUE_MSG_ATTR_HWADDR)) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = msg->queue_msg_hwaddr_len;
+       return msg->queue_msg_hwaddr;
+}
+
+int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload,
+                              int len)
+{
+       free(msg->queue_msg_payload);
+       msg->queue_msg_payload = malloc(len);
+       if (!msg->queue_msg_payload)
+               return -NLE_NOMEM;
+
+       memcpy(msg->queue_msg_payload, payload, len);
+       msg->queue_msg_payload_len = len;
+       msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD;
+       return 0;
+}
+
+int nfnl_queue_msg_test_payload(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD);
+}
+
+const void *nfnl_queue_msg_get_payload(const struct nfnl_queue_msg *msg, int *len)
+{
+       if (!(msg->ce_mask & QUEUE_MSG_ATTR_PAYLOAD)) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = msg->queue_msg_payload_len;
+       return msg->queue_msg_payload;
+}
+
+/**
+* Return the number of items matching a filter in the cache
+* @arg msg        queue msg
+* @arg verdict    NF_DROP, NF_ACCEPT, NF_REPEAT, etc
+*/
+void nfnl_queue_msg_set_verdict(struct nfnl_queue_msg *msg,
+                               unsigned int verdict)
+{
+       msg->queue_msg_verdict = verdict;
+       msg->ce_mask |= QUEUE_MSG_ATTR_VERDICT;
+}
+
+int nfnl_queue_msg_test_verdict(const struct nfnl_queue_msg *msg)
+{
+       return !!(msg->ce_mask & QUEUE_MSG_ATTR_VERDICT);
+}
+
+unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg)
+{
+       return msg->queue_msg_verdict;
+}
+
+static const struct trans_tbl nfnl_queue_msg_attrs[] = {
+       __ADD(QUEUE_MSG_ATTR_GROUP,             group)
+       __ADD(QUEUE_MSG_ATTR_FAMILY,            family)
+       __ADD(QUEUE_MSG_ATTR_PACKETID,          packetid)
+       __ADD(QUEUE_MSG_ATTR_HWPROTO,           hwproto)
+       __ADD(QUEUE_MSG_ATTR_HOOK,              hook)
+       __ADD(QUEUE_MSG_ATTR_MARK,              mark)
+       __ADD(QUEUE_MSG_ATTR_TIMESTAMP,         timestamp)
+       __ADD(QUEUE_MSG_ATTR_INDEV,             indev)
+       __ADD(QUEUE_MSG_ATTR_OUTDEV,            outdev)
+       __ADD(QUEUE_MSG_ATTR_PHYSINDEV,         physindev)
+       __ADD(QUEUE_MSG_ATTR_PHYSOUTDEV,        physoutdev)
+       __ADD(QUEUE_MSG_ATTR_HWADDR,            hwaddr)
+       __ADD(QUEUE_MSG_ATTR_PAYLOAD,           payload)
+       __ADD(QUEUE_MSG_ATTR_VERDICT,           verdict)
+};
+
+static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, nfnl_queue_msg_attrs,
+                          ARRAY_SIZE(nfnl_queue_msg_attrs));
+}
+
+/** @} */
+
+struct nl_object_ops queue_msg_obj_ops = {
+       .oo_name                = "netfilter/queuemsg",
+       .oo_size                = sizeof(struct nfnl_queue_msg),
+       .oo_free_data           = nfnl_queue_msg_free_data,
+       .oo_clone               = nfnl_queue_msg_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = nfnl_queue_msg_dump,
+           [NL_DUMP_DETAILS]   = nfnl_queue_msg_dump,
+           [NL_DUMP_STATS]     = nfnl_queue_msg_dump,
+       },
+       .oo_attrs2str           = nfnl_queue_msg_attrs2str,
+};
+
+/** @} */
diff --git a/lib/netfilter/queue_obj.c b/lib/netfilter/queue_obj.c
new file mode 100644 (file)
index 0000000..5edcc68
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * lib/netfilter/queue_obj.c   Netfilter Queue
+ *
+ *     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) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ */
+
+/**
+ * @ingroup nfnl
+ * @defgroup queue Queue
+ * @brief
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue.h>
+
+/** @cond SKIP */
+#define QUEUE_ATTR_GROUP               (1UL << 0)
+#define QUEUE_ATTR_MAXLEN              (1UL << 1)
+#define QUEUE_ATTR_COPY_MODE           (1UL << 2)
+#define QUEUE_ATTR_COPY_RANGE          (1UL << 3)
+/** @endcond */
+
+
+static void nfnl_queue_dump(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct nfnl_queue *queue = (struct nfnl_queue *) a;
+       char buf[64];
+
+       nl_new_line(p);
+
+       if (queue->ce_mask & QUEUE_ATTR_GROUP)
+               nl_dump(p, "group=%u ", queue->queue_group);
+
+       if (queue->ce_mask & QUEUE_ATTR_MAXLEN)
+               nl_dump(p, "maxlen=%u ", queue->queue_maxlen);
+
+       if (queue->ce_mask & QUEUE_ATTR_COPY_MODE)
+               nl_dump(p, "copy_mode=%s ",
+                       nfnl_queue_copy_mode2str(queue->queue_copy_mode,
+                                                buf, sizeof(buf)));
+
+       if (queue->ce_mask & QUEUE_ATTR_COPY_RANGE)
+               nl_dump(p, "copy_range=%u ", queue->queue_copy_range);
+
+       nl_dump(p, "\n");
+}
+
+static const struct trans_tbl copy_modes[] = {
+       __ADD(NFNL_QUEUE_COPY_NONE,     none)
+       __ADD(NFNL_QUEUE_COPY_META,     meta)
+       __ADD(NFNL_QUEUE_COPY_PACKET,   packet)
+};
+
+char *nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode copy_mode, char *buf,
+                              size_t len)
+{
+       return __type2str(copy_mode, buf, len, copy_modes,
+                          ARRAY_SIZE(copy_modes));
+}
+
+enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *name)
+{
+       return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct nfnl_queue *nfnl_queue_alloc(void)
+{
+       return (struct nfnl_queue *) nl_object_alloc(&queue_obj_ops);
+}
+
+void nfnl_queue_get(struct nfnl_queue *queue)
+{
+       nl_object_get((struct nl_object *) queue);
+}
+
+void nfnl_queue_put(struct nfnl_queue *queue)
+{
+       nl_object_put((struct nl_object *) queue);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void nfnl_queue_set_group(struct nfnl_queue *queue, uint16_t group)
+{
+       queue->queue_group = group;
+       queue->ce_mask |= QUEUE_ATTR_GROUP;
+}
+
+int nfnl_queue_test_group(const struct nfnl_queue *queue)
+{
+       return !!(queue->ce_mask & QUEUE_ATTR_GROUP);
+}
+
+uint16_t nfnl_queue_get_group(const struct nfnl_queue *queue)
+{
+       return queue->queue_group;
+}
+
+void nfnl_queue_set_maxlen(struct nfnl_queue *queue, uint32_t maxlen)
+{
+       queue->queue_maxlen = maxlen;
+       queue->ce_mask |= QUEUE_ATTR_MAXLEN;
+}
+
+int nfnl_queue_test_maxlen(const struct nfnl_queue *queue)
+{
+       return !!(queue->ce_mask & QUEUE_ATTR_MAXLEN);
+}
+
+uint32_t nfnl_queue_get_maxlen(const struct nfnl_queue *queue)
+{
+       return queue->queue_maxlen;
+}
+
+void nfnl_queue_set_copy_mode(struct nfnl_queue *queue, enum nfnl_queue_copy_mode mode)
+{
+       queue->queue_copy_mode = mode;
+       queue->ce_mask |= QUEUE_ATTR_COPY_MODE;
+}
+
+int nfnl_queue_test_copy_mode(const struct nfnl_queue *queue)
+{
+       return !!(queue->ce_mask & QUEUE_ATTR_COPY_MODE);
+}
+
+enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queue *queue)
+{
+       return queue->queue_copy_mode;
+}
+
+void nfnl_queue_set_copy_range(struct nfnl_queue *queue, uint32_t copy_range)
+{
+       queue->queue_copy_range = copy_range;
+       queue->ce_mask |= QUEUE_ATTR_COPY_RANGE;
+}
+
+int nfnl_queue_test_copy_range(const struct nfnl_queue *queue)
+{
+       return !!(queue->ce_mask & QUEUE_ATTR_COPY_RANGE);
+}
+
+uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *queue)
+{
+       return queue->queue_copy_range;
+}
+
+static int nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b,
+                             uint32_t attrs, int flags)
+{
+       struct nfnl_queue *a = (struct nfnl_queue *) _a;
+       struct nfnl_queue *b = (struct nfnl_queue *) _b;
+       int diff = 0;
+
+#define NFNL_QUEUE_DIFF(ATTR, EXPR) \
+       ATTR_DIFF(attrs, QUEUE_ATTR_##ATTR, a, b, EXPR)
+#define NFNL_QUEUE_DIFF_VAL(ATTR, FIELD) \
+       NFNL_QUEUE_DIFF(ATTR, a->FIELD != b->FIELD)
+
+       diff |= NFNL_QUEUE_DIFF_VAL(GROUP,      queue_group);
+       diff |= NFNL_QUEUE_DIFF_VAL(MAXLEN,     queue_maxlen);
+       diff |= NFNL_QUEUE_DIFF_VAL(COPY_MODE,  queue_copy_mode);
+       diff |= NFNL_QUEUE_DIFF_VAL(COPY_RANGE, queue_copy_range);
+
+#undef NFNL_QUEUE_DIFF
+#undef NFNL_QUEUE_DIFF_VAL
+
+       return diff;
+}
+
+static const struct trans_tbl nfnl_queue_attrs[] = {
+       __ADD(QUEUE_ATTR_GROUP,         group)
+       __ADD(QUEUE_ATTR_MAXLEN,        maxlen)
+       __ADD(QUEUE_ATTR_COPY_MODE,     copy_mode)
+       __ADD(QUEUE_ATTR_COPY_RANGE,    copy_range)
+};
+
+static char *nfnl_queue_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, nfnl_queue_attrs,
+                          ARRAY_SIZE(nfnl_queue_attrs));
+}
+
+/** @} */
+
+struct nl_object_ops queue_obj_ops = {
+       .oo_name                = "netfilter/queue",
+       .oo_size                = sizeof(struct nfnl_queue),
+       .oo_dump = {
+           [NL_DUMP_LINE]      = nfnl_queue_dump,
+           [NL_DUMP_DETAILS]   = nfnl_queue_dump,
+           [NL_DUMP_STATS]     = nfnl_queue_dump,
+       },
+       .oo_compare             = nfnl_queue_compare,
+       .oo_attrs2str           = nfnl_queue_attrs2str,
+       .oo_id_attrs            = QUEUE_ATTR_GROUP,
+};
+
+/** @} */
diff --git a/lib/nl.c b/lib/nl.c
new file mode 100644 (file)
index 0000000..565747a
--- /dev/null
+++ b/lib/nl.c
@@ -0,0 +1,1124 @@
+/*
+ * lib/nl.c            Core Netlink Interface
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @defgroup core Core Library (libnl)
+ *
+ * Socket handling, connection management, sending and receiving of data,
+ * message construction and parsing, object caching system, ...
+ *
+ * This is the API reference of the core library. It is not meant as a guide
+ * but as a reference. Please refer to the core library guide for detailed
+ * documentation on the library architecture and examples:
+ *
+ * * @ref_asciidoc{core,_,Netlink Core Library Development Guide}
+ *
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+/**
+ * @defgroup core_types Data Types
+ *
+ * Core library data types
+ * @{
+ * @}
+ *
+ * @defgroup send_recv Send & Receive Data
+ *
+ * Connection management, sending & receiving of data
+ *
+ * Related sections in the development guide:
+ * - @core_doc{core_send_recv, Sending & Receiving}
+ * - @core_doc{core_sockets, Sockets}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/netlink.h>
+ * ~~~~
+ */
+
+/**
+ * @name Connection Management
+ * @{
+ */
+
+/**
+ * Create file descriptor and bind socket.
+ * @arg sk             Netlink socket (required)
+ * @arg protocol       Netlink protocol to use (required)
+ *
+ * Creates a new Netlink socket using `socket()` and binds the socket to the
+ * protocol and local port specified in the `sk` socket object. Fails if
+ * the socket is already connected.
+ *
+ * @note If available, the `close-on-exec` (`SOCK_CLOEXEC`) feature is enabled
+ *       automatically on the new file descriptor. This causes the socket to
+ *       be closed automatically if any of the `exec` family functions succeed.
+ *       This is essential for multi threaded programs.
+ *
+ * @see nl_socket_alloc()
+ * @see nl_close()
+ *
+ * @return 0 on success or a negative error code.
+ *
+ * @retval -NLE_BAD_SOCK Socket is already connected
+ */
+int nl_connect(struct nl_sock *sk, int protocol)
+{
+       int err, flags = 0;
+       socklen_t addrlen;
+
+#ifdef SOCK_CLOEXEC
+       flags |= SOCK_CLOEXEC;
+#endif
+
+        if (sk->s_fd != -1)
+                return -NLE_BAD_SOCK;
+
+       sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
+       if (sk->s_fd < 0) {
+               err = -nl_syserr2nlerr(errno);
+               goto errout;
+       }
+
+       if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
+               err = nl_socket_set_buffer_size(sk, 0, 0);
+               if (err < 0)
+                       goto errout;
+       }
+
+       err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
+                  sizeof(sk->s_local));
+       if (err < 0) {
+               err = -nl_syserr2nlerr(errno);
+               goto errout;
+       }
+
+       addrlen = sizeof(sk->s_local);
+       err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local,
+                         &addrlen);
+       if (err < 0) {
+               err = -nl_syserr2nlerr(errno);
+               goto errout;
+       }
+
+       if (addrlen != sizeof(sk->s_local)) {
+               err = -NLE_NOADDR;
+               goto errout;
+       }
+
+       if (sk->s_local.nl_family != AF_NETLINK) {
+               err = -NLE_AF_NOSUPPORT;
+               goto errout;
+       }
+
+       sk->s_proto = protocol;
+
+       return 0;
+errout:
+        if (sk->s_fd != -1) {
+               close(sk->s_fd);
+               sk->s_fd = -1;
+        }
+
+       return err;
+}
+
+/**
+ * Close Netlink socket
+ * @arg sk             Netlink socket (required)
+ *
+ * Closes the Netlink socket using `close()`.
+ *
+ * @note The socket is closed automatically if a `struct nl_sock` object is
+ *       freed using `nl_socket_free()`.
+ *
+ * @see nl_connect()
+ */
+void nl_close(struct nl_sock *sk)
+{
+       if (sk->s_fd >= 0) {
+               close(sk->s_fd);
+               sk->s_fd = -1;
+       }
+
+       sk->s_proto = 0;
+}
+
+/** @} */
+
+/**
+ * @name Send
+ * @{
+ */
+
+/**
+ * Transmit raw data over Netlink socket.
+ * @arg sk             Netlink socket (required)
+ * @arg buf            Buffer carrying data to send (required)
+ * @arg size           Size of buffer (required)
+ *
+ * Transmits "raw" data over the specified Netlink socket. Unlike the other
+ * transmit functions it does not modify the data in any way. It directly
+ * passes the buffer \c buf of \c size to sendto().
+ *
+ * The message is addressed to the peer as specified in the socket by either
+ * the nl_socket_set_peer_port() or nl_socket_set_peer_groups() function.
+ *
+ * @note Because there is no indication on the message boundaries of the data
+ *       being sent, the \c NL_CB_MSG_OUT callback handler will not be invoked
+ *       for data that is being sent using this function.
+ *
+ * @see nl_socket_set_peer_port()
+ * @see nl_socket_set_peer_groups()
+ * @see nl_sendmsg()
+ *
+ * @return Number of bytes sent or a negative error code.
+ */
+int nl_sendto(struct nl_sock *sk, void *buf, size_t size)
+{
+       int ret;
+
+       if (!buf)
+               return -NLE_INVAL;
+
+       if (sk->s_fd < 0)
+               return -NLE_BAD_SOCK;
+
+       ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *)
+                    &sk->s_peer, sizeof(sk->s_peer));
+       if (ret < 0)
+               return -nl_syserr2nlerr(errno);
+
+       return ret;
+}
+
+/**
+ * Transmit Netlink message using sendmsg()
+ * @arg sk             Netlink socket (required)
+ * @arg msg            Netlink message to be sent (required)
+ * @arg hdr            sendmsg() message header (required)
+ *
+ * Transmits the message specified in \c hdr over the Netlink socket using the
+ * sendmsg() system call.
+ *
+ * @attention
+ * The `msg` argument will *not* be used to derive the message payload that
+ * is being sent out. The `msg` argument is *only* passed on to the
+ * `NL_CB_MSG_OUT` callback. The caller is responsible to initialize the
+ * `hdr` struct properly and have it point to the message payload and
+ * socket address.
+ *
+ * @note
+ * This function uses `nlmsg_set_src()` to modify the `msg` argument prior to
+ * invoking the `NL_CB_MSG_OUT` callback to provide the local port number.
+ *
+ * @callback This function triggers the `NL_CB_MSG_OUT` callback.
+ *
+ * @attention
+ * Think twice before using this function. It provides a low level access to
+ * the Netlink socket. Among other limitations, it does not add credentials
+ * even if enabled or respect the destination address specified in the `msg`
+ * object.
+ *
+ * @see nl_socket_set_local_port()
+ * @see nl_send_auto()
+ * @see nl_send_iovec()
+ *
+ * @return Number of bytes sent on success or a negative error code.
+ *
+ * @lowlevel
+ */
+int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
+{
+       struct nl_cb *cb;
+       int ret;
+
+       if (sk->s_fd < 0)
+               return -NLE_BAD_SOCK;
+
+       nlmsg_set_src(msg, &sk->s_local);
+
+       cb = sk->s_cb;
+       if (cb->cb_set[NL_CB_MSG_OUT])
+               if ((ret = nl_cb_call(cb, NL_CB_MSG_OUT, msg)) != NL_OK)
+                       return ret;
+
+       ret = sendmsg(sk->s_fd, hdr, 0);
+       if (ret < 0)
+               return -nl_syserr2nlerr(errno);
+
+       NL_DBG(4, "sent %d bytes\n", ret);
+       return ret;
+}
+
+
+/**
+ * Transmit Netlink message (taking IO vector)
+ * @arg sk             Netlink socket (required)
+ * @arg msg            Netlink message to be sent (required)
+ * @arg iov            IO vector to be sent (required)
+ * @arg iovlen         Number of struct iovec to be sent (required)
+ *
+ * This function is identical to nl_send() except that instead of taking a
+ * `struct nl_msg` object it takes an IO vector. Please see the description
+ * of `nl_send()`.
+ *
+ * @callback This function triggers the `NL_CB_MSG_OUT` callback.
+ *
+ * @see nl_send()
+ *
+ * @return Number of bytes sent on success or a negative error code.
+ *
+ * @lowlevel
+ */
+int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen)
+{
+       struct sockaddr_nl *dst;
+       struct ucred *creds;
+       struct msghdr hdr = {
+               .msg_name = (void *) &sk->s_peer,
+               .msg_namelen = sizeof(struct sockaddr_nl),
+               .msg_iov = iov,
+               .msg_iovlen = iovlen,
+       };
+
+       /* Overwrite destination if specified in the message itself, defaults
+        * to the peer address of the socket.
+        */
+       dst = nlmsg_get_dst(msg);
+       if (dst->nl_family == AF_NETLINK)
+               hdr.msg_name = dst;
+
+       /* Add credentials if present. */
+       creds = nlmsg_get_creds(msg);
+       if (creds != NULL) {
+               char buf[CMSG_SPACE(sizeof(struct ucred))];
+               struct cmsghdr *cmsg;
+
+               hdr.msg_control = buf;
+               hdr.msg_controllen = sizeof(buf);
+
+               cmsg = CMSG_FIRSTHDR(&hdr);
+               cmsg->cmsg_level = SOL_SOCKET;
+               cmsg->cmsg_type = SCM_CREDENTIALS;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+               memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
+       }
+
+       return nl_sendmsg(sk, msg, &hdr);
+}
+
+/**
+ * Transmit Netlink message
+ * @arg sk             Netlink socket (required)
+ * @arg msg            Netlink message (required)
+ *
+ * Transmits the Netlink message `msg` over the Netlink socket using the
+ * `sendmsg()` system call. This function is based on `nl_send_iovec()` but
+ * takes care of initializing a `struct iovec` based on the `msg` object.
+ *
+ * The message is addressed to the peer as specified in the socket by either
+ * the nl_socket_set_peer_port() or nl_socket_set_peer_groups() function.
+ * The peer address can be overwritten by specifying an address in the `msg`
+ * object using nlmsg_set_dst().
+ *
+ * If present in the `msg`, credentials set by the nlmsg_set_creds() function
+ * are added to the control buffer of the message.
+ *
+ * @par Overwriting Capability:
+ * Calls to this function can be overwritten by providing an alternative using
+ * the nl_cb_overwrite_send() function.
+ *
+ * @callback This function triggers the `NL_CB_MSG_OUT` callback.
+ *
+ * @attention
+ * Unlike `nl_send_auto()`, this function does *not* finalize the message in
+ * terms of automatically adding needed flags or filling out port numbers.
+ *
+ * @see nl_send_auto()
+ * @see nl_send_iovec()
+ * @see nl_socket_set_peer_port()
+ * @see nl_socket_set_peer_groups()
+ * @see nlmsg_set_dst()
+ * @see nlmsg_set_creds()
+ * @see nl_cb_overwrite_send()
+ *
+ * @return Number of bytes sent on success or a negative error code.
+*/
+int nl_send(struct nl_sock *sk, struct nl_msg *msg)
+{
+       struct nl_cb *cb = sk->s_cb;
+
+       if (cb->cb_send_ow)
+               return cb->cb_send_ow(sk, msg);
+       else {
+               struct iovec iov = {
+                       .iov_base = (void *) nlmsg_hdr(msg),
+                       .iov_len = nlmsg_hdr(msg)->nlmsg_len,
+               };
+
+               return nl_send_iovec(sk, msg, &iov, 1);
+       }
+}
+
+/**
+ * Finalize Netlink message
+ * @arg sk             Netlink socket (required)
+ * @arg msg            Netlink message (required)
+ *
+ * This function finalizes a Netlink message by completing the message with
+ * desirable flags and values depending on the socket configuration.
+ *
+ *  - If not yet filled out, the source address of the message (`nlmsg_pid`)
+ *    will be set to the local port number of the socket.
+ *  - If not yet specified, the next available sequence number is assigned
+ *    to the message (`nlmsg_seq`).
+ *  - If not yet specified, the protocol field of the message will be set to
+ *    the protocol field of the socket.
+ *  - The `NLM_F_REQUEST` Netlink message flag will be set.
+ *  - The `NLM_F_ACK` flag will be set if Auto-ACK mode is enabled on the
+ *    socket.
+ */
+void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg)
+{
+       struct nlmsghdr *nlh;
+
+       nlh = nlmsg_hdr(msg);
+       if (nlh->nlmsg_pid == NL_AUTO_PORT)
+               nlh->nlmsg_pid = sk->s_local.nl_pid;
+
+       if (nlh->nlmsg_seq == NL_AUTO_SEQ)
+               nlh->nlmsg_seq = sk->s_seq_next++;
+
+       if (msg->nm_protocol == -1)
+               msg->nm_protocol = sk->s_proto;
+
+       nlh->nlmsg_flags |= NLM_F_REQUEST;
+
+       if (!(sk->s_flags & NL_NO_AUTO_ACK))
+               nlh->nlmsg_flags |= NLM_F_ACK;
+}
+
+/**
+ * Finalize and transmit Netlink message
+ * @arg sk             Netlink socket (required)
+ * @arg msg            Netlink message (required)
+ *
+ * Finalizes the message by passing it to `nl_complete_msg()` and transmits it
+ * by passing it to `nl_send()`.
+ *
+ * @callback This function triggers the `NL_CB_MSG_OUT` callback.
+ *
+ * @see nl_complete_msg()
+ * @see nl_send()
+ *
+ * @return Number of bytes sent or a negative error code.
+ */
+int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
+{
+       nl_complete_msg(sk, msg);
+
+       return nl_send(sk, msg);
+}
+
+/**
+ * Finalize and transmit Netlink message and wait for ACK or error message
+ * @arg sk             Netlink socket (required)
+ * @arg msg            Netlink message (required)
+ *
+ * Passes the `msg` to `nl_send_auto()` to finalize and transmit it. Frees the
+ * message and waits (sleeps) for the ACK or error message to be received.
+ *
+ * @attention
+ * Disabling Auto-ACK (nl_socket_disable_auto_ack()) will cause this function
+ * to return immediately after transmitting the message. However, the peer may
+ * still be returning an error message in response to the request. It is the
+ * responsibility of the caller to handle such messages.
+ *
+ * @callback This function triggers the `NL_CB_MSG_OUT` callback.
+ *
+ * @attention
+ * This function frees the `msg` object after transmitting it by calling
+ * `nlmsg_free()`.
+ *
+ * @see nl_send_auto().
+ * @see nl_wait_for_ack()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_send_sync(struct nl_sock *sk, struct nl_msg *msg)
+{
+       int err;
+
+       err = nl_send_auto(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/**
+ * Construct and transmit a Netlink message
+ * @arg sk             Netlink socket (required)
+ * @arg type           Netlink message type (required)
+ * @arg flags          Netlink message flags (optional)
+ * @arg buf            Data buffer (optional)
+ * @arg size           Size of data buffer (optional)
+ *
+ * Allocates a new Netlink message based on `type` and `flags`. If `buf`
+ * points to payload of length `size` that payload will be appended to the
+ * message.
+ *
+ * Sends out the message using `nl_send_auto()` and frees the message
+ * afterwards.
+ *
+ * @see nl_send_auto()
+ *
+ * @return Number of characters sent on success or a negative error code.
+ * @retval -NLE_NOMEM Unable to allocate Netlink message
+ */
+int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf,
+                  size_t size)
+{
+       int err;
+       struct nl_msg *msg;
+
+       msg = nlmsg_alloc_simple(type, flags);
+       if (!msg)
+               return -NLE_NOMEM;
+
+       if (buf && size) {
+               err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
+               if (err < 0)
+                       goto errout;
+       }
+
+       err = nl_send_auto(sk, msg);
+errout:
+       nlmsg_free(msg);
+
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Receive
+ * @{
+ */
+
+/**
+ * Receive data from netlink socket
+ * @arg sk             Netlink socket (required)
+ * @arg nla            Netlink socket structure to hold address of peer (required)
+ * @arg buf            Destination pointer for message content (required)
+ * @arg creds          Destination pointer for credentials (optional)
+ *
+ * Receives data from a connected netlink socket using recvmsg() and returns
+ * the number of bytes read. The read data is stored in a newly allocated
+ * buffer that is assigned to \c *buf. The peer's netlink address will be
+ * stored in \c *nla.
+ *
+ * This function blocks until data is available to be read unless the socket
+ * has been put into non-blocking mode using nl_socket_set_nonblocking() in
+ * which case this function will return immediately with a return value of 0.
+ *
+ * The buffer size used when reading from the netlink socket and thus limiting
+ * the maximum size of a netlink message that can be read defaults to the size
+ * of a memory page (getpagesize()). The buffer size can be modified on a per
+ * socket level using the function nl_socket_set_msg_buf_size().
+ *
+ * If message peeking is enabled using nl_socket_enable_msg_peek() the size of
+ * the message to be read will be determined using the MSG_PEEK flag prior to
+ * performing the actual read. This leads to an additional recvmsg() call for
+ * every read operation which has performance implications and is not
+ * recommended for high throughput protocols.
+ *
+ * An eventual interruption of the recvmsg() system call is automatically
+ * handled by retrying the operation.
+ *
+ * If receiving of credentials has been enabled using the function
+ * nl_socket_set_passcred(), this function will allocate a new struct ucred
+ * filled with the received credentials and assign it to \c *creds. The caller
+ * is responsible for freeing the buffer.
+ *
+ * @note The caller is responsible to free the returned data buffer and if
+ *       enabled, the credentials buffer.
+ *
+ * @see nl_socket_set_nonblocking()
+ * @see nl_socket_set_msg_buf_size()
+ * @see nl_socket_enable_msg_peek()
+ * @see nl_socket_set_passcred()
+ *
+ * @return Number of bytes read, 0 on EOF, 0 on no data event (non-blocking
+ *         mode), or a negative error code.
+ */
+int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
+           unsigned char **buf, struct ucred **creds)
+{
+       ssize_t n;
+       int flags = 0;
+       static int page_size = 0;
+       struct iovec iov;
+       struct msghdr msg = {
+               .msg_name = (void *) nla,
+               .msg_namelen = sizeof(struct sockaddr_nl),
+               .msg_iov = &iov,
+               .msg_iovlen = 1,
+       };
+       struct ucred* tmpcreds = NULL;
+       int retval = 0;
+
+       if (!buf || !nla)
+               return -NLE_INVAL;
+
+       if (sk->s_flags & NL_MSG_PEEK)
+               flags |= MSG_PEEK | MSG_TRUNC;
+
+       if (page_size == 0)
+               page_size = getpagesize() * 4;
+
+       iov.iov_len = sk->s_bufsize ? : page_size;
+       iov.iov_base = malloc(iov.iov_len);
+
+       if (!iov.iov_base) {
+               retval = -NLE_NOMEM;
+               goto abort;
+       }
+
+       if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
+               msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
+               msg.msg_control = malloc(msg.msg_controllen);
+               if (!msg.msg_control) {
+                       retval = -NLE_NOMEM;
+                       goto abort;
+               }
+       }
+retry:
+
+       n = recvmsg(sk->s_fd, &msg, flags);
+       if (!n) {
+               retval = 0;
+               goto abort;
+       }
+       if (n < 0) {
+               if (errno == EINTR) {
+                       NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
+                       goto retry;
+               }
+               retval = -nl_syserr2nlerr(errno);
+               goto abort;
+       }
+
+       if (msg.msg_flags & MSG_CTRUNC) {
+               void *tmp;
+               msg.msg_controllen *= 2;
+               tmp = realloc(msg.msg_control, msg.msg_controllen);
+               if (!tmp) {
+                       retval = -NLE_NOMEM;
+                       goto abort;
+               }
+               msg.msg_control = tmp;
+               goto retry;
+       }
+
+       if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
+               void *tmp;
+               /* Provided buffer is not long enough, enlarge it
+                * to size of n (which should be total length of the message)
+                * and try again. */
+               iov.iov_len = n;
+               tmp = realloc(iov.iov_base, iov.iov_len);
+               if (!tmp) {
+                       retval = -NLE_NOMEM;
+                       goto abort;
+               }
+               iov.iov_base = tmp;
+               flags = 0;
+               goto retry;
+       }
+
+        if (flags != 0) {
+               /* Buffer is big enough, do the actual reading */
+               flags = 0;
+               goto retry;
+       }
+
+       if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
+               retval =  -NLE_NOADDR;
+               goto abort;
+       }
+
+       if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
+               struct cmsghdr *cmsg;
+
+               for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+                       if (cmsg->cmsg_level != SOL_SOCKET)
+                               continue;
+                       if (cmsg->cmsg_type != SCM_CREDENTIALS)
+                               continue;
+                       tmpcreds = malloc(sizeof(*tmpcreds));
+                       if (!tmpcreds) {
+                               retval = -NLE_NOMEM;
+                               goto abort;
+                       }
+                       memcpy(tmpcreds, CMSG_DATA(cmsg), sizeof(*tmpcreds));
+                       break;
+               }
+       }
+
+       retval = n;
+abort:
+       free(msg.msg_control);
+
+       if (retval <= 0) {
+               free(iov.iov_base);
+               iov.iov_base = NULL;
+               free(tmpcreds);
+               tmpcreds = NULL;
+       } else
+               *buf = iov.iov_base;
+
+       if (creds)
+               *creds = tmpcreds;
+
+       return retval;
+}
+
+/** @cond SKIP */
+#define NL_CB_CALL(cb, type, msg) \
+do { \
+       err = nl_cb_call(cb, type, msg); \
+       switch (err) { \
+       case NL_OK: \
+               err = 0; \
+               break; \
+       case NL_SKIP: \
+               goto skip; \
+       case NL_STOP: \
+               goto stop; \
+       default: \
+               goto out; \
+       } \
+} while (0)
+/** @endcond */
+
+static int recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+       int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0;
+       unsigned char *buf = NULL;
+       struct nlmsghdr *hdr;
+
+       /*
+       nla is passed on to not only to nl_recv() but may also be passed
+       to a function pointer provided by the caller which may or may not
+       initialize the variable. Thomas Graf.
+       */
+       struct sockaddr_nl nla = {0};
+       struct nl_msg *msg = NULL;
+       struct ucred *creds = NULL;
+
+continue_reading:
+       NL_DBG(3, "Attempting to read from %p\n", sk);
+       if (cb->cb_recv_ow)
+               n = cb->cb_recv_ow(sk, &nla, &buf, &creds);
+       else
+               n = nl_recv(sk, &nla, &buf, &creds);
+
+       if (n <= 0)
+               return n;
+
+       NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n);
+
+       hdr = (struct nlmsghdr *) buf;
+       while (nlmsg_ok(hdr, n)) {
+               NL_DBG(3, "recvmsgs(%p): Processing valid message...\n", sk);
+
+               nlmsg_free(msg);
+               msg = nlmsg_convert(hdr);
+               if (!msg) {
+                       err = -NLE_NOMEM;
+                       goto out;
+               }
+
+               nlmsg_set_proto(msg, sk->s_proto);
+               nlmsg_set_src(msg, &nla);
+               if (creds)
+                       nlmsg_set_creds(msg, creds);
+
+               nrecv++;
+
+               /* Raw callback is the first, it gives the most control
+                * to the user and he can do his very own parsing. */
+               if (cb->cb_set[NL_CB_MSG_IN])
+                       NL_CB_CALL(cb, NL_CB_MSG_IN, msg);
+
+               /* Sequence number checking. The check may be done by
+                * the user, otherwise a very simple check is applied
+                * enforcing strict ordering */
+               if (cb->cb_set[NL_CB_SEQ_CHECK]) {
+                       NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg);
+
+               /* Only do sequence checking if auto-ack mode is enabled */
+               } else if (!(sk->s_flags & NL_NO_AUTO_ACK)) {
+                       if (hdr->nlmsg_seq != sk->s_seq_expect) {
+                               if (cb->cb_set[NL_CB_INVALID])
+                                       NL_CB_CALL(cb, NL_CB_INVALID, msg);
+                               else {
+                                       err = -NLE_SEQ_MISMATCH;
+                                       goto out;
+                               }
+                       }
+               }
+
+               if (hdr->nlmsg_type == NLMSG_DONE ||
+                   hdr->nlmsg_type == NLMSG_ERROR ||
+                   hdr->nlmsg_type == NLMSG_NOOP ||
+                   hdr->nlmsg_type == NLMSG_OVERRUN) {
+                       /* We can't check for !NLM_F_MULTI since some netlink
+                        * users in the kernel are broken. */
+                       sk->s_seq_expect++;
+                       NL_DBG(3, "recvmsgs(%p): Increased expected " \
+                              "sequence number to %d\n",
+                              sk, sk->s_seq_expect);
+               }
+
+               if (hdr->nlmsg_flags & NLM_F_MULTI)
+                       multipart = 1;
+
+               if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
+                       if (cb->cb_set[NL_CB_DUMP_INTR])
+                               NL_CB_CALL(cb, NL_CB_DUMP_INTR, msg);
+                       else {
+                               /*
+                                * We have to continue reading to clear
+                                * all messages until a NLMSG_DONE is
+                                * received and report the inconsistency.
+                                */
+                               interrupted = 1;
+                       }
+               }
+       
+               /* Other side wishes to see an ack for this message */
+               if (hdr->nlmsg_flags & NLM_F_ACK) {
+                       if (cb->cb_set[NL_CB_SEND_ACK])
+                               NL_CB_CALL(cb, NL_CB_SEND_ACK, msg);
+                       else {
+                               /* FIXME: implement */
+                       }
+               }
+
+               /* messages terminates a multpart message, this is
+                * usually the end of a message and therefore we slip
+                * out of the loop by default. the user may overrule
+                * this action by skipping this packet. */
+               if (hdr->nlmsg_type == NLMSG_DONE) {
+                       multipart = 0;
+                       if (cb->cb_set[NL_CB_FINISH])
+                               NL_CB_CALL(cb, NL_CB_FINISH, msg);
+               }
+
+               /* Message to be ignored, the default action is to
+                * skip this message if no callback is specified. The
+                * user may overrule this action by returning
+                * NL_PROCEED. */
+               else if (hdr->nlmsg_type == NLMSG_NOOP) {
+                       if (cb->cb_set[NL_CB_SKIPPED])
+                               NL_CB_CALL(cb, NL_CB_SKIPPED, msg);
+                       else
+                               goto skip;
+               }
+
+               /* Data got lost, report back to user. The default action is to
+                * quit parsing. The user may overrule this action by retuning
+                * NL_SKIP or NL_PROCEED (dangerous) */
+               else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
+                       if (cb->cb_set[NL_CB_OVERRUN])
+                               NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
+                       else {
+                               err = -NLE_MSG_OVERFLOW;
+                               goto out;
+                       }
+               }
+
+               /* Message carries a nlmsgerr */
+               else if (hdr->nlmsg_type == NLMSG_ERROR) {
+                       struct nlmsgerr *e = nlmsg_data(hdr);
+
+                       if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) {
+                               /* Truncated error message, the default action
+                                * is to stop parsing. The user may overrule
+                                * this action by returning NL_SKIP or
+                                * NL_PROCEED (dangerous) */
+                               if (cb->cb_set[NL_CB_INVALID])
+                                       NL_CB_CALL(cb, NL_CB_INVALID, msg);
+                               else {
+                                       err = -NLE_MSG_TRUNC;
+                                       goto out;
+                               }
+                       } else if (e->error) {
+                               /* Error message reported back from kernel. */
+                               if (cb->cb_err) {
+                                       err = cb->cb_err(&nla, e,
+                                                          cb->cb_err_arg);
+                                       if (err < 0)
+                                               goto out;
+                                       else if (err == NL_SKIP)
+                                               goto skip;
+                                       else if (err == NL_STOP) {
+                                               err = -nl_syserr2nlerr(e->error);
+                                               goto out;
+                                       }
+                               } else {
+                                       err = -nl_syserr2nlerr(e->error);
+                                       goto out;
+                               }
+                       } else if (cb->cb_set[NL_CB_ACK])
+                               NL_CB_CALL(cb, NL_CB_ACK, msg);
+               } else {
+                       /* Valid message (not checking for MULTIPART bit to
+                        * get along with broken kernels. NL_SKIP has no
+                        * effect on this.  */
+                       if (cb->cb_set[NL_CB_VALID])
+                               NL_CB_CALL(cb, NL_CB_VALID, msg);
+               }
+skip:
+               err = 0;
+               hdr = nlmsg_next(hdr, &n);
+       }
+       
+       nlmsg_free(msg);
+       free(buf);
+       free(creds);
+       buf = NULL;
+       msg = NULL;
+       creds = NULL;
+
+       if (multipart) {
+               /* Multipart message not yet complete, continue reading */
+               goto continue_reading;
+       }
+stop:
+       err = 0;
+out:
+       nlmsg_free(msg);
+       free(buf);
+       free(creds);
+
+       if (interrupted)
+               err = -NLE_DUMP_INTR;
+
+       if (!err)
+               err = nrecv;
+
+       return err;
+}
+
+/**
+ * Receive a set of messages from a netlink socket and report parsed messages
+ * @arg sk             Netlink socket.
+ * @arg cb             set of callbacks to control behaviour.
+ *
+ * This function is identical to nl_recvmsgs() to the point that it will
+ * return the number of parsed messages instead of 0 on success.
+ *
+ * @see nl_recvmsgs()
+ *
+ * @return Number of received messages or a negative error code from nl_recv().
+ */
+int nl_recvmsgs_report(struct nl_sock *sk, struct nl_cb *cb)
+{
+       if (cb->cb_recvmsgs_ow)
+               return cb->cb_recvmsgs_ow(sk, cb);
+       else
+               return recvmsgs(sk, cb);
+}
+
+/**
+ * Receive a set of messages from a netlink socket.
+ * @arg sk             Netlink socket.
+ * @arg cb             set of callbacks to control behaviour.
+ *
+ * Repeatedly calls nl_recv() or the respective replacement if provided
+ * by the application (see nl_cb_overwrite_recv()) and parses the
+ * received data as netlink messages. Stops reading if one of the
+ * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code.
+ *
+ * A non-blocking sockets causes the function to return immediately if
+ * no data is available.
+ *
+ * @see nl_recvmsgs_report()
+ *
+ * @return 0 on success or a negative error code from nl_recv().
+ */
+int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+       int err;
+
+       if ((err = nl_recvmsgs_report(sk, cb)) > 0)
+               err = 0;
+
+       return err;
+}
+
+/**
+ * Receive a set of message from a netlink socket using handlers in nl_sock.
+ * @arg sk             Netlink socket.
+ *
+ * Calls nl_recvmsgs() with the handlers configured in the netlink socket.
+ */
+int nl_recvmsgs_default(struct nl_sock *sk)
+{
+       return nl_recvmsgs(sk, sk->s_cb);
+
+}
+
+static int ack_wait_handler(struct nl_msg *msg, void *arg)
+{
+       return NL_STOP;
+}
+
+/**
+ * Wait for ACK.
+ * @arg sk             Netlink socket.
+ * @pre The netlink socket must be in blocking state.
+ *
+ * Waits until an ACK is received for the latest not yet acknowledged
+ * netlink message.
+ */
+int nl_wait_for_ack(struct nl_sock *sk)
+{
+       int err;
+       struct nl_cb *cb;
+
+       cb = nl_cb_clone(sk->s_cb);
+       if (cb == NULL)
+               return -NLE_NOMEM;
+
+       nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
+       err = nl_recvmsgs(sk, cb);
+       nl_cb_put(cb);
+
+       return err;
+}
+
+/** @cond SKIP */
+struct pickup_param
+{
+       int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+                     struct nlmsghdr *, struct nl_parser_param *);
+       struct nl_object *result;
+};
+
+static int __store_answer(struct nl_object *obj, struct nl_parser_param *p)
+{
+       struct pickup_param *pp = p->pp_arg;
+       /*
+        * the parser will put() the object at the end, expecting the cache
+        * to take the reference.
+        */
+       nl_object_get(obj);
+       pp->result =  obj;
+
+       return 0;
+}
+
+static int __pickup_answer(struct nl_msg *msg, void *arg)
+{
+       struct pickup_param *pp = arg;
+       struct nl_parser_param parse_arg = {
+               .pp_cb = __store_answer,
+               .pp_arg = pp,
+       };
+
+       return pp->parser(NULL, &msg->nm_src, msg->nm_nlh, &parse_arg);
+}
+
+/** @endcond */
+
+/**
+ * Pickup netlink answer, parse is and return object
+ * @arg sk             Netlink socket
+ * @arg parser         Parser function to parse answer
+ * @arg result         Result pointer to return parsed object
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_pickup(struct nl_sock *sk,
+             int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+                           struct nlmsghdr *, struct nl_parser_param *),
+             struct nl_object **result)
+{
+       struct nl_cb *cb;
+       int err;
+       struct pickup_param pp = {
+               .parser = parser,
+       };
+
+       cb = nl_cb_clone(sk->s_cb);
+       if (cb == NULL)
+               return -NLE_NOMEM;
+
+       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __pickup_answer, &pp);
+
+       err = nl_recvmsgs(sk, cb);
+       if (err < 0)
+               goto errout;
+
+       *result = pp.result;
+errout:
+       nl_cb_put(cb);
+
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Deprecated
+ * @{
+ */
+
+/**
+ * @deprecated Please use nl_complete_msg()
+ */
+void nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
+{
+       nl_complete_msg(sk, msg);
+}
+
+/**
+ * @deprecated Please use nl_send_auto()
+ */
+int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
+{
+       return nl_send_auto(sk, msg);
+}
+
+
+/** @} */
+
+/** @} */
+
+/** @} */
diff --git a/lib/object.c b/lib/object.c
new file mode 100644 (file)
index 0000000..b1ebe51
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * lib/object.c                Generic Cacheable Object
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core_types
+ * @defgroup object Object (Cacheable)
+ *
+ * Generic object data type, for inheritance purposes to implement cacheable
+ * data types.
+ *
+ * Related sections in the development guide:
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/object.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/utils.h>
+
+static inline struct nl_object_ops *obj_ops(struct nl_object *obj)
+{
+       if (!obj->ce_ops)
+               BUG();
+
+       return obj->ce_ops;
+}
+
+/**
+ * @name Object Creation/Deletion
+ * @{
+ */
+
+/**
+ * Allocate a new object of kind specified by the operations handle
+ * @arg ops            cache operations handle
+ * @return The new object or NULL
+ */
+struct nl_object *nl_object_alloc(struct nl_object_ops *ops)
+{
+       struct nl_object *new;
+
+       if (ops->oo_size < sizeof(*new))
+               BUG();
+
+       new = calloc(1, ops->oo_size);
+       if (!new)
+               return NULL;
+
+       new->ce_refcnt = 1;
+       nl_init_list_head(&new->ce_list);
+
+       new->ce_ops = ops;
+       if (ops->oo_constructor)
+               ops->oo_constructor(new);
+
+       NL_DBG(4, "Allocated new object %p\n", new);
+
+       return new;
+}
+
+/**
+ * Allocate new object of kind specified by the name
+ * @arg kind           name of object type
+ * @arg result         Result pointer
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_object_alloc_name(const char *kind, struct nl_object **result)
+{
+       struct nl_cache_ops *ops;
+
+       ops = nl_cache_ops_lookup_safe(kind);
+       if (!ops)
+               return -NLE_OPNOTSUPP;
+
+       *result = nl_object_alloc(ops->co_obj_ops);
+       nl_cache_ops_put(ops);
+       if (!*result)
+               return -NLE_NOMEM;
+
+       return 0;
+}
+
+struct nl_derived_object {
+       NLHDR_COMMON
+       char data;
+};
+
+/**
+ * Allocate a new object and copy all data from an existing object
+ * @arg obj            object to inherite data from
+ * @return The new object or NULL.
+ */
+struct nl_object *nl_object_clone(struct nl_object *obj)
+{
+       struct nl_object *new;
+       struct nl_object_ops *ops = obj_ops(obj);
+       int doff = offsetof(struct nl_derived_object, data);
+       int size;
+
+       new = nl_object_alloc(ops);
+       if (!new)
+               return NULL;
+
+       size = ops->oo_size - doff;
+       if (size < 0)
+               BUG();
+
+       new->ce_ops = obj->ce_ops;
+       new->ce_msgtype = obj->ce_msgtype;
+       new->ce_mask = obj->ce_mask;
+
+       if (size)
+               memcpy((void *)new + doff, (void *)obj + doff, size);
+
+       if (ops->oo_clone) {
+               if (ops->oo_clone(new, obj) < 0) {
+                       nl_object_free(new);
+                       return NULL;
+               }
+       } else if (size && ops->oo_free_data)
+               BUG();
+
+       return new;
+}
+
+/**
+ * Merge a cacheable object
+ * @arg dst            object to be merged into
+ * @arg src            new object to be merged into dst
+ *
+ * @return 0 or a negative error code.
+ */
+int nl_object_update(struct nl_object *dst, struct nl_object *src)
+{
+       struct nl_object_ops *ops = obj_ops(dst);
+
+       if (ops->oo_update)
+               return ops->oo_update(dst, src);
+
+       return -NLE_OPNOTSUPP;
+}
+
+/**
+ * Free a cacheable object
+ * @arg obj            object to free
+ *
+ * @return 0 or a negative error code.
+ */
+void nl_object_free(struct nl_object *obj)
+{
+       struct nl_object_ops *ops;
+
+       if (!obj)
+               return;
+
+       ops = obj_ops(obj);
+
+       if (obj->ce_refcnt > 0)
+               NL_DBG(1, "Warning: Freeing object in use...\n");
+
+       if (obj->ce_cache)
+               nl_cache_remove(obj);
+
+       if (ops->oo_free_data)
+               ops->oo_free_data(obj);
+
+       free(obj);
+
+       NL_DBG(4, "Freed object %p\n", obj);
+}
+
+/** @} */
+
+/**
+ * @name Reference Management
+ * @{
+ */
+
+/**
+ * Acquire a reference on a object
+ * @arg obj            object to acquire reference from
+ */
+void nl_object_get(struct nl_object *obj)
+{
+       obj->ce_refcnt++;
+       NL_DBG(4, "New reference to object %p, total %d\n",
+              obj, obj->ce_refcnt);
+}
+
+/**
+ * Release a reference from an object
+ * @arg obj            object to release reference from
+ */
+void nl_object_put(struct nl_object *obj)
+{
+       if (!obj)
+               return;
+
+       obj->ce_refcnt--;
+       NL_DBG(4, "Returned object reference %p, %d remaining\n",
+              obj, obj->ce_refcnt);
+
+       if (obj->ce_refcnt < 0)
+               BUG();
+
+       if (obj->ce_refcnt <= 0)
+               nl_object_free(obj);
+}
+
+/**
+ * Check whether this object is used by multiple users
+ * @arg obj            object to check
+ * @return true or false
+ */
+int nl_object_shared(struct nl_object *obj)
+{
+       return obj->ce_refcnt > 1;
+}
+
+/** @} */
+
+/**
+ * @name Marks
+ * @{
+ */
+
+/**
+ * Add mark to object
+ * @arg obj            Object to mark
+ */
+void nl_object_mark(struct nl_object *obj)
+{
+       obj->ce_flags |= NL_OBJ_MARK;
+}
+
+/**
+ * Remove mark from object
+ * @arg obj            Object to unmark
+ */
+void nl_object_unmark(struct nl_object *obj)
+{
+       obj->ce_flags &= ~NL_OBJ_MARK;
+}
+
+/**
+ * Return true if object is marked
+ * @arg obj            Object to check
+ * @return true if object is marked, otherwise false
+ */
+int nl_object_is_marked(struct nl_object *obj)
+{
+       return (obj->ce_flags & NL_OBJ_MARK);
+}
+
+/** @} */
+
+/**
+ * @name Utillities
+ * @{
+ */
+
+/**
+ * Dump this object according to the specified parameters
+ * @arg obj            object to dump
+ * @arg params         dumping parameters
+ */
+void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params)
+{
+       if (params->dp_buf)
+               memset(params->dp_buf, 0, params->dp_buflen);
+
+       dump_from_ops(obj, params);
+}
+
+void nl_object_dump_buf(struct nl_object *obj, char *buf, size_t len)
+{
+        struct nl_dump_params dp = {
+                .dp_buf = buf,
+                .dp_buflen = len,
+        };
+
+        return nl_object_dump(obj, &dp);
+}
+
+/**
+ * Check if the identifiers of two objects are identical 
+ * @arg a              an object
+ * @arg b              another object of same type
+ *
+ * @return true if both objects have equal identifiers, otherwise false.
+ */
+int nl_object_identical(struct nl_object *a, struct nl_object *b)
+{
+       struct nl_object_ops *ops = obj_ops(a);
+       uint32_t req_attrs;
+
+       /* Both objects must be of same type */
+       if (ops != obj_ops(b))
+               return 0;
+
+       if (ops->oo_id_attrs_get) {
+               int req_attrs_a = ops->oo_id_attrs_get(a);
+               int req_attrs_b = ops->oo_id_attrs_get(b);
+               if (req_attrs_a != req_attrs_b)
+                       return 0;
+               req_attrs = req_attrs_a;
+       } else {
+               req_attrs = ops->oo_id_attrs;
+       }
+       if (req_attrs == 0xFFFFFFFF)
+               req_attrs = a->ce_mask & b->ce_mask;
+
+       /* Both objects must provide all required attributes to uniquely
+        * identify an object */
+       if ((a->ce_mask & req_attrs) != req_attrs ||
+           (b->ce_mask & req_attrs) != req_attrs)
+               return 0;
+
+       /* Can't judge unless we can compare */
+       if (ops->oo_compare == NULL)
+               return 0;
+
+       return !(ops->oo_compare(a, b, req_attrs, 0));
+}
+
+/**
+ * Compute bitmask representing difference in attribute values
+ * @arg a              an object
+ * @arg b              another object of same type
+ *
+ * The bitmask returned is specific to an object type, each bit set represents
+ * an attribute which mismatches in either of the two objects. Unavailability
+ * of an attribute in one object and presence in the other is regarded a
+ * mismatch as well.
+ *
+ * @return Bitmask describing differences or 0 if they are completely identical.
+ */
+uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
+{
+       struct nl_object_ops *ops = obj_ops(a);
+
+       if (ops != obj_ops(b) || ops->oo_compare == NULL)
+               return UINT_MAX;
+
+       return ops->oo_compare(a, b, ~0, 0);
+}
+
+/**
+ * Match a filter against an object
+ * @arg obj            object to check
+ * @arg filter         object of same type acting as filter
+ *
+ * @return 1 if the object matches the filter or 0
+ *           if no filter procedure is available or if the
+ *           filter does not match.
+ */
+int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
+{
+       struct nl_object_ops *ops = obj_ops(obj);
+
+       if (ops != obj_ops(filter) || ops->oo_compare == NULL)
+               return 0;
+       
+       return !(ops->oo_compare(obj, filter, filter->ce_mask,
+                                LOOSE_COMPARISON));
+}
+
+/**
+ * Convert bitmask of attributes to a character string
+ * @arg obj            object of same type as attribute bitmask
+ * @arg attrs          bitmask of attribute types
+ * @arg buf            destination buffer
+ * @arg len            length of destination buffer
+ *
+ * Converts the bitmask of attribute types into a list of attribute
+ * names separated by comas.
+ *
+ * @return destination buffer.
+ */
+char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs,
+                         char *buf, size_t len)
+{
+       struct nl_object_ops *ops = obj_ops(obj);
+
+       if (ops->oo_attrs2str != NULL)
+               return ops->oo_attrs2str(attrs, buf, len);
+       else {
+               memset(buf, 0, len);
+               return buf;
+       }
+}
+
+/**
+ * Return list of attributes present in an object
+ * @arg obj            an object
+ * @arg buf            destination buffer
+ * @arg len            length of destination buffer
+ *
+ * @return destination buffer.
+ */
+char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
+{
+       return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
+}
+
+/**
+ * Generate object hash key
+ * @arg obj            the object
+ * @arg hashkey                destination buffer to be used for key stream
+ * @arg hashtbl_sz     hash table size
+ *
+ * @return hash key in destination buffer
+ */
+void nl_object_keygen(struct nl_object *obj, uint32_t *hashkey,
+                     uint32_t hashtbl_sz)
+{
+       struct nl_object_ops *ops = obj_ops(obj);
+
+       if (ops->oo_keygen)
+               ops->oo_keygen(obj, hashkey, hashtbl_sz);
+       else
+               *hashkey = 0;
+
+       return;
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+/**
+ * Return number of references held
+ * @arg obj            object
+ *
+ * @return The number of references held to this object
+ */
+int nl_object_get_refcnt(struct nl_object *obj)
+{
+       return obj->ce_refcnt;
+}
+
+/**
+ * Return cache the object is associated with
+ * @arg obj            object
+ *
+ * @note The returned pointer is not protected with a reference counter,
+ *       it is your responsibility.
+ *
+ * @return Pointer to cache or NULL if not associated with a cache.
+ */
+struct nl_cache *nl_object_get_cache(struct nl_object *obj)
+{
+       return obj->ce_cache;
+}
+
+/**
+ * Return the object's type
+ * @arg obj            object
+ *
+ * FIXME: link to list of object types
+ *
+ * @return Name of the object type
+ */
+const char *nl_object_get_type(const struct nl_object *obj)
+{
+       if (!obj->ce_ops)
+               BUG();
+
+       return obj->ce_ops->oo_name;
+}
+
+/**
+ * Return the netlink message type the object was derived from
+ * @arg obj            object
+ *
+ * @return Netlink message type or 0.
+ */
+int nl_object_get_msgtype(const struct nl_object *obj)
+{
+       return obj->ce_msgtype;
+}
+
+/**
+ * Return object operations structure
+ * @arg obj            object
+ *
+ * @return Pointer to the object operations structure
+ */
+struct nl_object_ops *nl_object_get_ops(const struct nl_object *obj)
+{
+       return obj->ce_ops;
+}
+
+/**
+ * Return object id attribute mask
+ * @arg obj            object
+ *
+ * @return object id attribute mask
+ */
+uint32_t nl_object_get_id_attrs(struct nl_object *obj)
+{
+       struct nl_object_ops *ops = obj_ops(obj);
+       uint32_t id_attrs;
+
+       if (!ops)
+               return 0;
+
+       if (ops->oo_id_attrs_get)
+               id_attrs = ops->oo_id_attrs_get(obj);
+       else
+               id_attrs = ops->oo_id_attrs;
+
+       return id_attrs;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/route/addr.c b/lib/route/addr.c
new file mode 100644 (file)
index 0000000..71fca94
--- /dev/null
@@ -0,0 +1,1120 @@
+/*
+ * lib/route/addr.c            Addresses
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2006 Baruch Even <baruch@ev-en.org>,
+ *                         Mediatrix Telecom, inc. <ericb@mediatrix.com>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup rtaddr Addresses
+ * @brief
+ *
+ * @note The maximum size of an address label is IFNAMSIZ.
+ *
+ * @note The address may not contain a prefix length if the peer address
+ *       has been specified already.
+ *
+ * @par 1) Address Addition
+ * @code
+ * // Allocate an empty address object to be filled out with the attributes
+ * // of the new address.
+ * struct rtnl_addr *addr = rtnl_addr_alloc();
+ *
+ * // Fill out the mandatory attributes of the new address. Setting the
+ * // local address will automatically set the address family and the
+ * // prefix length to the correct values.
+ * rtnl_addr_set_ifindex(addr, ifindex);
+ * rtnl_addr_set_local(addr, local_addr);
+ *
+ * // The label of the address can be specified, currently only supported
+ * // by IPv4 and DECnet.
+ * rtnl_addr_set_label(addr, "mylabel");
+ *
+ * // The peer address can be specified if necessary, in either case a peer
+ * // address will be sent to the kernel in order to fullfil the interface
+ * // requirements. If none is set, it will equal the local address.
+ * // Note: Real peer addresses are only supported by IPv4 for now.
+ * rtnl_addr_set_peer(addr, peer_addr);
+ *
+ * // In case you want to have the address have a scope other than global
+ * // it may be overwritten using rtnl_addr_set_scope(). The scope currently
+ * // cannot be set for IPv6 addresses.
+ * rtnl_addr_set_scope(addr, rtnl_str2scope("site"));
+ *
+ * // Broadcast address may be specified using the relevant
+ * // functions, the address family will be verified if one of the other
+ * // addresses has been set already. Currently only works for IPv4.
+ * rtnl_addr_set_broadcast(addr, broadcast_addr);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_addr_build_add_request() to be
+ * // sent out using nl_send_auto_complete().
+ * rtnl_addr_add(sk, addr, 0);
+ *
+ * // Free the memory
+ * rtnl_addr_put(addr);
+ * @endcode
+ *
+ * @par 2) Address Deletion
+ * @code
+ * // Allocate an empty address object to be filled out with the attributes
+ * // matching the address to be deleted. Alternatively a fully equipped
+ * // address object out of a cache can be used instead.
+ * struct rtnl_addr *addr = rtnl_addr_alloc();
+ *
+ * // The only mandatory parameter besides the address family is the interface
+ * // index the address is on, i.e. leaving out all other parameters will
+ * // result in all addresses of the specified address family interface tuple
+ * // to be deleted.
+ * rtnl_addr_set_ifindex(addr, ifindex);
+ *
+ * // Specyfing the address family manually is only required if neither the
+ * // local nor peer address have been specified.
+ * rtnl_addr_set_family(addr, AF_INET);
+ *
+ * // Specyfing the local address is optional but the best choice to delete
+ * // specific addresses.
+ * rtnl_addr_set_local(addr, local_addr);
+ *
+ * // The label of the address can be specified, currently only supported
+ * // by IPv4 and DECnet.
+ * rtnl_addr_set_label(addr, "mylabel");
+ *
+ * // The peer address can be specified if necessary, in either case a peer
+ * // address will be sent to the kernel in order to fullfil the interface
+ * // requirements. If none is set, it will equal the local address.
+ * // Note: Real peer addresses are only supported by IPv4 for now.
+ * rtnl_addr_set_peer(addr, peer_addr);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_addr_build_delete_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_addr_delete(sk, addr, 0);
+ *
+ * // Free the memory
+ * rtnl_addr_put(addr);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/route.h>
+#include <netlink/route/link.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define ADDR_ATTR_FAMILY       0x0001
+#define ADDR_ATTR_PREFIXLEN    0x0002
+#define ADDR_ATTR_FLAGS                0x0004
+#define ADDR_ATTR_SCOPE                0x0008
+#define ADDR_ATTR_IFINDEX      0x0010
+#define ADDR_ATTR_LABEL                0x0020
+#define ADDR_ATTR_CACHEINFO    0x0040
+#define ADDR_ATTR_PEER         0x0080
+#define ADDR_ATTR_LOCAL                0x0100
+#define ADDR_ATTR_BROADCAST    0x0200
+#define ADDR_ATTR_MULTICAST    0x0400
+#define ADDR_ATTR_ANYCAST      0x0800
+
+static struct nl_cache_ops rtnl_addr_ops;
+static struct nl_object_ops addr_obj_ops;
+/** @endcond */
+
+static void addr_constructor(struct nl_object *obj)
+{
+       struct rtnl_addr *addr = nl_object_priv(obj);
+
+       addr->a_scope = RT_SCOPE_NOWHERE;
+}
+
+static void addr_free_data(struct nl_object *obj)
+{
+       struct rtnl_addr *addr = nl_object_priv(obj);
+
+       if (!addr)
+               return;
+
+       nl_addr_put(addr->a_peer);
+       nl_addr_put(addr->a_local);
+       nl_addr_put(addr->a_bcast);
+       nl_addr_put(addr->a_multicast);
+       nl_addr_put(addr->a_anycast);
+       rtnl_link_put(addr->a_link);
+}
+
+static int addr_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct rtnl_addr *dst = nl_object_priv(_dst);
+       struct rtnl_addr *src = nl_object_priv(_src);
+
+       if (src->a_link) {
+               nl_object_get(OBJ_CAST(src->a_link));
+               dst->a_link = src->a_link;
+       }
+
+       if (src->a_peer)
+               if (!(dst->a_peer = nl_addr_clone(src->a_peer)))
+                       return -NLE_NOMEM;
+       
+       if (src->a_local)
+               if (!(dst->a_local = nl_addr_clone(src->a_local)))
+                       return -NLE_NOMEM;
+
+       if (src->a_bcast)
+               if (!(dst->a_bcast = nl_addr_clone(src->a_bcast)))
+                       return -NLE_NOMEM;
+
+       if (src->a_multicast)
+               if (!(dst->a_multicast = nl_addr_clone(src->a_multicast)))
+                       return -NLE_NOMEM;
+
+       if (src->a_anycast)
+               if (!(dst->a_anycast = nl_addr_clone(src->a_anycast)))
+                       return -NLE_NOMEM;
+
+       return 0;
+}
+
+static struct nla_policy addr_policy[IFA_MAX+1] = {
+       [IFA_LABEL]     = { .type = NLA_STRING,
+                           .maxlen = IFNAMSIZ },
+       [IFA_CACHEINFO] = { .minlen = sizeof(struct ifa_cacheinfo) },
+};
+
+static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                          struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct rtnl_addr *addr;
+       struct ifaddrmsg *ifa;
+       struct nlattr *tb[IFA_MAX+1];
+       int err, family;
+       struct nl_cache *link_cache;
+       struct nl_addr *plen_addr = NULL;
+
+       addr = rtnl_addr_alloc();
+       if (!addr)
+               return -NLE_NOMEM;
+
+       addr->ce_msgtype = nlh->nlmsg_type;
+
+       err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, addr_policy);
+       if (err < 0)
+               goto errout;
+
+       ifa = nlmsg_data(nlh);
+       addr->a_family = family = ifa->ifa_family;
+       addr->a_prefixlen = ifa->ifa_prefixlen;
+       addr->a_flags = ifa->ifa_flags;
+       addr->a_scope = ifa->ifa_scope;
+       addr->a_ifindex = ifa->ifa_index;
+
+       addr->ce_mask = (ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN |
+                        ADDR_ATTR_FLAGS | ADDR_ATTR_SCOPE | ADDR_ATTR_IFINDEX);
+
+       if (tb[IFA_LABEL]) {
+               nla_strlcpy(addr->a_label, tb[IFA_LABEL], IFNAMSIZ);
+               addr->ce_mask |= ADDR_ATTR_LABEL;
+       }
+
+       /* IPv6 only */
+       if (tb[IFA_CACHEINFO]) {
+               struct ifa_cacheinfo *ca;
+               
+               ca = nla_data(tb[IFA_CACHEINFO]);
+               addr->a_cacheinfo.aci_prefered = ca->ifa_prefered;
+               addr->a_cacheinfo.aci_valid = ca->ifa_valid;
+               addr->a_cacheinfo.aci_cstamp = ca->cstamp;
+               addr->a_cacheinfo.aci_tstamp = ca->tstamp;
+               addr->ce_mask |= ADDR_ATTR_CACHEINFO;
+       }
+
+       if (tb[IFA_LOCAL]) {
+               addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family);
+               if (!addr->a_local)
+                       goto errout_nomem;
+               addr->ce_mask |= ADDR_ATTR_LOCAL;
+               plen_addr = addr->a_local;
+       }
+
+       if (tb[IFA_ADDRESS]) {
+               struct nl_addr *a;
+
+               a = nl_addr_alloc_attr(tb[IFA_ADDRESS], family);
+               if (!a)
+                       goto errout_nomem;
+
+               /* IPv6 sends the local address as IFA_ADDRESS with
+                * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
+                * with IFA_ADDRESS being the peer address if they differ */
+               if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
+                       nl_addr_put(addr->a_local);
+                       addr->a_local = a;
+                       addr->ce_mask |= ADDR_ATTR_LOCAL;
+               } else {
+                       addr->a_peer = a;
+                       addr->ce_mask |= ADDR_ATTR_PEER;
+               }
+
+               plen_addr = a;
+       }
+
+       if (plen_addr)
+               nl_addr_set_prefixlen(plen_addr, addr->a_prefixlen);
+
+       /* IPv4 only */
+       if (tb[IFA_BROADCAST]) {
+               addr->a_bcast = nl_addr_alloc_attr(tb[IFA_BROADCAST], family);
+               if (!addr->a_bcast)
+                       goto errout_nomem;
+
+               addr->ce_mask |= ADDR_ATTR_BROADCAST;
+       }
+
+       /* IPv6 only */
+       if (tb[IFA_MULTICAST]) {
+               addr->a_multicast = nl_addr_alloc_attr(tb[IFA_MULTICAST],
+                                                      family);
+               if (!addr->a_multicast)
+                       goto errout_nomem;
+
+               addr->ce_mask |= ADDR_ATTR_MULTICAST;
+       }
+
+       /* IPv6 only */
+       if (tb[IFA_ANYCAST]) {
+               addr->a_anycast = nl_addr_alloc_attr(tb[IFA_ANYCAST],
+                                                      family);
+               if (!addr->a_anycast)
+                       goto errout_nomem;
+
+               addr->ce_mask |= ADDR_ATTR_ANYCAST;
+       }
+
+       if ((link_cache = __nl_cache_mngt_require("route/link"))) {
+               struct rtnl_link *link;
+
+               if ((link = rtnl_link_get(link_cache, addr->a_ifindex))) {
+                       rtnl_addr_set_link(addr, link);
+
+                       /* rtnl_addr_set_link incs refcnt */
+                       rtnl_link_put(link);
+               }
+       }
+
+       err = pp->pp_cb((struct nl_object *) addr, pp);
+errout:
+       rtnl_addr_put(addr);
+
+       return err;
+
+errout_nomem:
+       err = -NLE_NOMEM;
+       goto errout;
+}
+
+static int addr_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+       return nl_rtgen_request(sk, RTM_GETADDR, AF_UNSPEC, NLM_F_DUMP);
+}
+
+static void addr_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_addr *addr = (struct rtnl_addr *) obj;
+       struct nl_cache *link_cache;
+       char buf[128];
+
+       link_cache = nl_cache_mngt_require_safe("route/link");
+
+       if (addr->ce_mask & ADDR_ATTR_LOCAL)
+               nl_dump_line(p, "%s",
+                       nl_addr2str(addr->a_local, buf, sizeof(buf)));
+       else
+               nl_dump_line(p, "none");
+
+       if (addr->ce_mask & ADDR_ATTR_PEER)
+               nl_dump(p, " peer %s",
+                       nl_addr2str(addr->a_peer, buf, sizeof(buf)));
+
+       nl_dump(p, " %s ", nl_af2str(addr->a_family, buf, sizeof(buf)));
+
+       if (link_cache)
+               nl_dump(p, "dev %s ",
+                       rtnl_link_i2name(link_cache, addr->a_ifindex,
+                                        buf, sizeof(buf)));
+       else
+               nl_dump(p, "dev %d ", addr->a_ifindex);
+
+       nl_dump(p, "scope %s",
+               rtnl_scope2str(addr->a_scope, buf, sizeof(buf)));
+
+       rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf));
+       if (buf[0])
+               nl_dump(p, " <%s>", buf);
+
+       nl_dump(p, "\n");
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+static void addr_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_addr *addr = (struct rtnl_addr *) obj;
+       char buf[128];
+
+       addr_dump_line(obj, p);
+
+       if (addr->ce_mask & (ADDR_ATTR_LABEL | ADDR_ATTR_BROADCAST |
+                            ADDR_ATTR_MULTICAST)) {
+               nl_dump_line(p, "  ");
+
+               if (addr->ce_mask & ADDR_ATTR_LABEL)
+                       nl_dump(p, " label %s", addr->a_label);
+
+               if (addr->ce_mask & ADDR_ATTR_BROADCAST)
+                       nl_dump(p, " broadcast %s",
+                               nl_addr2str(addr->a_bcast, buf, sizeof(buf)));
+
+               if (addr->ce_mask & ADDR_ATTR_MULTICAST)
+                       nl_dump(p, " multicast %s",
+                               nl_addr2str(addr->a_multicast, buf,
+                                             sizeof(buf)));
+
+               if (addr->ce_mask & ADDR_ATTR_ANYCAST)
+                       nl_dump(p, " anycast %s",
+                               nl_addr2str(addr->a_anycast, buf,
+                                             sizeof(buf)));
+
+               nl_dump(p, "\n");
+       }
+
+       if (addr->ce_mask & ADDR_ATTR_CACHEINFO) {
+               struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo;
+
+               nl_dump_line(p, "   valid-lifetime %s",
+                            ci->aci_valid == 0xFFFFFFFFU ? "forever" :
+                            nl_msec2str(ci->aci_valid * 1000,
+                                          buf, sizeof(buf)));
+
+               nl_dump(p, " preferred-lifetime %s\n",
+                       ci->aci_prefered == 0xFFFFFFFFU ? "forever" :
+                       nl_msec2str(ci->aci_prefered * 1000,
+                                     buf, sizeof(buf)));
+
+               nl_dump_line(p, "   created boot-time+%s ",
+                            nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10,
+                                          buf, sizeof(buf)));
+                   
+               nl_dump(p, "last-updated boot-time+%s\n",
+                       nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10,
+                                     buf, sizeof(buf)));
+       }
+}
+
+static void addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+       addr_dump_details(obj, p);
+}
+
+static int addr_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       struct rtnl_addr *a = (struct rtnl_addr *) _a;
+       struct rtnl_addr *b = (struct rtnl_addr *) _b;
+       int diff = 0;
+
+#define ADDR_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ADDR_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= ADDR_DIFF(IFINDEX,      a->a_ifindex != b->a_ifindex);
+       diff |= ADDR_DIFF(FAMILY,       a->a_family != b->a_family);
+       diff |= ADDR_DIFF(SCOPE,        a->a_scope != b->a_scope);
+       diff |= ADDR_DIFF(LABEL,        strcmp(a->a_label, b->a_label));
+       diff |= ADDR_DIFF(PEER,         nl_addr_cmp(a->a_peer, b->a_peer));
+       diff |= ADDR_DIFF(LOCAL,        nl_addr_cmp(a->a_local, b->a_local));
+       diff |= ADDR_DIFF(MULTICAST,    nl_addr_cmp(a->a_multicast,
+                                                   b->a_multicast));
+       diff |= ADDR_DIFF(BROADCAST,    nl_addr_cmp(a->a_bcast, b->a_bcast));
+       diff |= ADDR_DIFF(ANYCAST,      nl_addr_cmp(a->a_anycast, b->a_anycast));
+
+       if (flags & LOOSE_COMPARISON)
+               diff |= ADDR_DIFF(FLAGS,
+                                 (a->a_flags ^ b->a_flags) & b->a_flag_mask);
+       else
+               diff |= ADDR_DIFF(FLAGS, a->a_flags != b->a_flags);
+
+#undef ADDR_DIFF
+
+       return diff;
+}
+
+static const struct trans_tbl addr_attrs[] = {
+       __ADD(ADDR_ATTR_FAMILY, family)
+       __ADD(ADDR_ATTR_PREFIXLEN, prefixlen)
+       __ADD(ADDR_ATTR_FLAGS, flags)
+       __ADD(ADDR_ATTR_SCOPE, scope)
+       __ADD(ADDR_ATTR_IFINDEX, ifindex)
+       __ADD(ADDR_ATTR_LABEL, label)
+       __ADD(ADDR_ATTR_CACHEINFO, cacheinfo)
+       __ADD(ADDR_ATTR_PEER, peer)
+       __ADD(ADDR_ATTR_LOCAL, local)
+       __ADD(ADDR_ATTR_BROADCAST, broadcast)
+       __ADD(ADDR_ATTR_MULTICAST, multicast)
+};
+
+static char *addr_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, addr_attrs,
+                          ARRAY_SIZE(addr_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_addr *rtnl_addr_alloc(void)
+{
+       return (struct rtnl_addr *) nl_object_alloc(&addr_obj_ops);
+}
+
+void rtnl_addr_put(struct rtnl_addr *addr)
+{
+       nl_object_put((struct nl_object *) addr);
+}
+
+/** @} */
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+int rtnl_addr_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+       return nl_cache_alloc_and_fill(&rtnl_addr_ops, sk, result);
+}
+
+/**
+ * Search address in cache
+ * @arg cache          Address cache
+ * @arg ifindex                Interface index of address
+ * @arg addr           Local address part
+ *
+ * Searches address cache previously allocated with rtnl_addr_alloc_cache()
+ * for an address with a matching local address.
+ *
+ * The reference counter is incremented before returning the address, therefore
+ * the reference must be given back with rtnl_addr_put() after usage.
+ *
+ * @return Address object or NULL if no match was found.
+ */
+struct rtnl_addr *rtnl_addr_get(struct nl_cache *cache, int ifindex,
+                               struct nl_addr *addr)
+{
+       struct rtnl_addr *a;
+
+       if (cache->c_ops != &rtnl_addr_ops)
+               return NULL;
+
+       nl_list_for_each_entry(a, &cache->c_items, ce_list) {
+               if (ifindex && a->a_ifindex != ifindex)
+                       continue;
+
+               if (a->ce_mask & ADDR_ATTR_LOCAL &&
+                   !nl_addr_cmp(a->a_local, addr)) {
+                       nl_object_get((struct nl_object *) a);
+                       return a;
+               }
+       }
+
+       return NULL;
+}
+
+/** @} */
+
+static int build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags,
+                         struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct ifaddrmsg am = {
+               .ifa_family = tmpl->a_family,
+               .ifa_index = tmpl->a_ifindex,
+               .ifa_prefixlen = tmpl->a_prefixlen,
+       };
+
+       if (tmpl->ce_mask & ADDR_ATTR_SCOPE)
+               am.ifa_scope = tmpl->a_scope;
+       else {
+               /* compatibility hack */
+               if (tmpl->a_family == AF_INET &&
+                   tmpl->ce_mask & ADDR_ATTR_LOCAL &&
+                   *((char *) nl_addr_get_binary_addr(tmpl->a_local)) == 127)
+                       am.ifa_scope = RT_SCOPE_HOST;
+               else
+                       am.ifa_scope = RT_SCOPE_UNIVERSE;
+       }
+
+       msg = nlmsg_alloc_simple(cmd, flags);
+       if (!msg)
+               return -NLE_NOMEM;
+
+       if (nlmsg_append(msg, &am, sizeof(am), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       if (tmpl->ce_mask & ADDR_ATTR_LOCAL)
+               NLA_PUT_ADDR(msg, IFA_LOCAL, tmpl->a_local);
+
+       if (tmpl->ce_mask & ADDR_ATTR_PEER)
+               NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_peer);
+       else if (tmpl->ce_mask & ADDR_ATTR_LOCAL)
+               NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_local);
+
+       if (tmpl->ce_mask & ADDR_ATTR_LABEL)
+               NLA_PUT_STRING(msg, IFA_LABEL, tmpl->a_label);
+
+       if (tmpl->ce_mask & ADDR_ATTR_BROADCAST)
+               NLA_PUT_ADDR(msg, IFA_BROADCAST, tmpl->a_bcast);
+
+       if (tmpl->ce_mask & ADDR_ATTR_CACHEINFO) {
+               struct ifa_cacheinfo ca = {
+                       .ifa_valid = tmpl->a_cacheinfo.aci_valid,
+                       .ifa_prefered = tmpl->a_cacheinfo.aci_prefered,
+               };
+
+               NLA_PUT(msg, IFA_CACHEINFO, sizeof(ca), &ca);
+       }
+
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Addition
+ * @{
+ */
+
+/**
+ * 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
+ * all relevant fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed.
+ *
+ * Minimal required attributes:
+ *   - interface index (rtnl_addr_set_ifindex())
+ *   - local address (rtnl_addr_set_local())
+ *
+ * The scope will default to universe except for loopback addresses in
+ * which case a host scope is used if not specified otherwise.
+ *
+ * @note Free the memory after usage using nlmsg_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags,
+                               struct nl_msg **result)
+{
+       uint32_t required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY |
+                      ADDR_ATTR_PREFIXLEN | ADDR_ATTR_LOCAL;
+
+       if ((addr->ce_mask & required) != required)
+               return -NLE_MISSING_ATTR;
+       
+       return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags, result);
+}
+
+/**
+ * Request addition of new address
+ * @arg sk             Netlink socket.
+ * @arg addr           Address object representing the new address.
+ * @arg flags          Additional netlink message flags.
+ *
+ * Builds a netlink message by calling rtnl_addr_build_add_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @see rtnl_addr_build_add_request()
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_addr_add(struct nl_sock *sk, struct rtnl_addr *addr, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_addr_build_add_request(addr, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Deletion
+ * @{
+ */
+
+/**
+ * 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
+ * fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed.
+ *
+ * Minimal required attributes:
+ *   - interface index (rtnl_addr_set_ifindex())
+ *   - address family (rtnl_addr_set_family())
+ *
+ * Optional attributes:
+ *   - local address (rtnl_addr_set_local())
+ *   - label (rtnl_addr_set_label(), IPv4/DECnet only)
+ *   - peer address (rtnl_addr_set_peer(), IPv4 only)
+ *
+ * @note Free the memory after usage using nlmsg_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_addr_build_delete_request(struct rtnl_addr *addr, int flags,
+                                  struct nl_msg **result)
+{
+       uint32_t required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY;
+
+       if ((addr->ce_mask & required) != required)
+               return -NLE_MISSING_ATTR;
+
+       return build_addr_msg(addr, RTM_DELADDR, flags, result);
+}
+
+/**
+ * Request deletion of an address
+ * @arg sk             Netlink socket.
+ * @arg addr           Address object to be deleted.
+ * @arg flags          Additional netlink message flags.
+ *
+ * Builds a netlink message by calling rtnl_addr_build_delete_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @see rtnl_addr_build_delete_request();
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_addr_delete(struct nl_sock *sk, struct rtnl_addr *addr, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_addr_build_delete_request(addr, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+int rtnl_addr_set_label(struct rtnl_addr *addr, const char *label)
+{
+       if (strlen(label) > sizeof(addr->a_label) - 1)
+               return -NLE_RANGE;
+
+       strcpy(addr->a_label, label);
+       addr->ce_mask |= ADDR_ATTR_LABEL;
+
+       return 0;
+}
+
+char *rtnl_addr_get_label(struct rtnl_addr *addr)
+{
+       if (addr->ce_mask & ADDR_ATTR_LABEL)
+               return addr->a_label;
+       else
+               return NULL;
+}
+
+void rtnl_addr_set_ifindex(struct rtnl_addr *addr, int ifindex)
+{
+       addr->a_ifindex = ifindex;
+       addr->ce_mask |= ADDR_ATTR_IFINDEX;
+}
+
+int rtnl_addr_get_ifindex(struct rtnl_addr *addr)
+{
+       return addr->a_ifindex;
+}
+
+void rtnl_addr_set_link(struct rtnl_addr *addr, struct rtnl_link *link)
+{
+       rtnl_link_put(addr->a_link);
+
+       if (!link)
+               return;
+
+       nl_object_get(OBJ_CAST(link));
+       addr->a_link = link;
+       addr->a_ifindex = link->l_index;
+       addr->ce_mask |= ADDR_ATTR_IFINDEX;
+}
+
+struct rtnl_link *rtnl_addr_get_link(struct rtnl_addr *addr)
+{
+       if (addr->a_link) {
+               nl_object_get(OBJ_CAST(addr->a_link));
+               return addr->a_link;
+       }
+
+       return NULL;
+}
+
+void rtnl_addr_set_family(struct rtnl_addr *addr, int family)
+{
+       addr->a_family = family;
+       addr->ce_mask |= ADDR_ATTR_FAMILY;
+}
+
+int rtnl_addr_get_family(struct rtnl_addr *addr)
+{
+       return addr->a_family;
+}
+
+/**
+ * Set the prefix length / netmask
+ * @arg addr           Address
+ * @arg prefixlen      Length of prefix (netmask)
+ *
+ * Modifies the length of the prefix. If the address object contains a peer
+ * address the prefix length will apply to it, otherwise the prefix length
+ * will apply to the local address of the address.
+ *
+ * If the address object contains a peer or local address the corresponding
+ * `struct nl_addr` will be updated with the new prefix length.
+ *
+ * @note Specifying a length of 0 will remove the prefix length alltogether.
+ *
+ * @see rtnl_addr_get_prefixlen()
+ */
+void rtnl_addr_set_prefixlen(struct rtnl_addr *addr, int prefixlen)
+{
+       addr->a_prefixlen = prefixlen;
+
+       if (prefixlen)
+               addr->ce_mask |= ADDR_ATTR_PREFIXLEN;
+       else
+               addr->ce_mask &= ~ADDR_ATTR_PREFIXLEN;
+
+       /*
+        * The prefix length always applies to the peer address if
+        * a peer address is present.
+        */
+       if (addr->a_peer)
+               nl_addr_set_prefixlen(addr->a_peer, prefixlen);
+       else if (addr->a_local)
+               nl_addr_set_prefixlen(addr->a_local, prefixlen);
+}
+
+int rtnl_addr_get_prefixlen(struct rtnl_addr *addr)
+{
+       return addr->a_prefixlen;
+}
+
+void rtnl_addr_set_scope(struct rtnl_addr *addr, int scope)
+{
+       addr->a_scope = scope;
+       addr->ce_mask |= ADDR_ATTR_SCOPE;
+}
+
+int rtnl_addr_get_scope(struct rtnl_addr *addr)
+{
+       return addr->a_scope;
+}
+
+void rtnl_addr_set_flags(struct rtnl_addr *addr, unsigned int flags)
+{
+       addr->a_flag_mask |= flags;
+       addr->a_flags |= flags;
+       addr->ce_mask |= ADDR_ATTR_FLAGS;
+}
+
+void rtnl_addr_unset_flags(struct rtnl_addr *addr, unsigned int flags)
+{
+       addr->a_flag_mask |= flags;
+       addr->a_flags &= ~flags;
+       addr->ce_mask |= ADDR_ATTR_FLAGS;
+}
+
+unsigned int rtnl_addr_get_flags(struct rtnl_addr *addr)
+{
+       return addr->a_flags;
+}
+
+static inline int __assign_addr(struct rtnl_addr *addr, struct nl_addr **pos,
+                               struct nl_addr *new, int flag)
+{
+       if (new) {
+               if (addr->ce_mask & ADDR_ATTR_FAMILY) {
+                       if (new->a_family != addr->a_family)
+                               return -NLE_AF_MISMATCH;
+               } else
+                       addr->a_family = new->a_family;
+
+               if (*pos)
+                       nl_addr_put(*pos);
+
+               *pos = nl_addr_get(new);
+               addr->ce_mask |= (flag | ADDR_ATTR_FAMILY);
+       } else {
+               if (*pos)
+                       nl_addr_put(*pos);
+
+               *pos = NULL;
+               addr->ce_mask &= ~flag;
+       }
+
+       return 0;
+}
+
+int rtnl_addr_set_local(struct rtnl_addr *addr, struct nl_addr *local)
+{
+       int err;
+
+       /* Prohibit local address with prefix length if peer address is present */
+       if ((addr->ce_mask & ADDR_ATTR_PEER) && local &&
+           nl_addr_get_prefixlen(local))
+               return -NLE_INVAL;
+
+       err = __assign_addr(addr, &addr->a_local, local, ADDR_ATTR_LOCAL);
+       if (err < 0)
+               return err;
+
+       /* Never overwrite the prefix length if a peer address is present */
+       if (!(addr->ce_mask & ADDR_ATTR_PEER))
+               rtnl_addr_set_prefixlen(addr, local ? nl_addr_get_prefixlen(local) : 0);
+
+       return 0;
+}
+
+struct nl_addr *rtnl_addr_get_local(struct rtnl_addr *addr)
+{
+       return addr->a_local;
+}
+
+int rtnl_addr_set_peer(struct rtnl_addr *addr, struct nl_addr *peer)
+{
+       int err;
+
+       if (peer && peer->a_family != AF_INET)
+               return -NLE_AF_NOSUPPORT;
+
+       err = __assign_addr(addr, &addr->a_peer, peer, ADDR_ATTR_PEER);
+       if (err < 0)
+               return err;
+
+       rtnl_addr_set_prefixlen(addr, peer ? nl_addr_get_prefixlen(peer) : 0);
+
+       return 0;
+}
+
+struct nl_addr *rtnl_addr_get_peer(struct rtnl_addr *addr)
+{
+       return addr->a_peer;
+}
+
+int rtnl_addr_set_broadcast(struct rtnl_addr *addr, struct nl_addr *bcast)
+{
+       if (bcast && bcast->a_family != AF_INET)
+               return -NLE_AF_NOSUPPORT;
+
+       return __assign_addr(addr, &addr->a_bcast, bcast, ADDR_ATTR_BROADCAST);
+}
+
+struct nl_addr *rtnl_addr_get_broadcast(struct rtnl_addr *addr)
+{
+       return addr->a_bcast;
+}
+
+int rtnl_addr_set_multicast(struct rtnl_addr *addr, struct nl_addr *multicast)
+{
+       if (multicast && multicast->a_family != AF_INET6)
+               return -NLE_AF_NOSUPPORT;
+
+       return __assign_addr(addr, &addr->a_multicast, multicast,
+                            ADDR_ATTR_MULTICAST);
+}
+
+struct nl_addr *rtnl_addr_get_multicast(struct rtnl_addr *addr)
+{
+       return addr->a_multicast;
+}
+
+int rtnl_addr_set_anycast(struct rtnl_addr *addr, struct nl_addr *anycast)
+{
+       if (anycast && anycast->a_family != AF_INET6)
+               return -NLE_AF_NOSUPPORT;
+
+       return __assign_addr(addr, &addr->a_anycast, anycast,
+                            ADDR_ATTR_ANYCAST);
+}
+
+struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *addr)
+{
+       return addr->a_anycast;
+}
+
+uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *addr)
+{
+       if (addr->ce_mask & ADDR_ATTR_CACHEINFO)
+               return addr->a_cacheinfo.aci_valid;
+       else
+               return 0xFFFFFFFFU;
+}
+
+void rtnl_addr_set_valid_lifetime(struct rtnl_addr *addr, uint32_t lifetime)
+{
+       addr->a_cacheinfo.aci_valid = lifetime;
+       addr->ce_mask |= ADDR_ATTR_CACHEINFO;
+}
+
+uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *addr)
+{
+       if (addr->ce_mask & ADDR_ATTR_CACHEINFO)
+               return addr->a_cacheinfo.aci_prefered;
+       else
+               return 0xFFFFFFFFU;
+}
+
+void rtnl_addr_set_preferred_lifetime(struct rtnl_addr *addr, uint32_t lifetime)
+{
+       addr->a_cacheinfo.aci_prefered = lifetime;
+       addr->ce_mask |= ADDR_ATTR_CACHEINFO;
+}
+
+uint32_t rtnl_addr_get_create_time(struct rtnl_addr *addr)
+{
+       return addr->a_cacheinfo.aci_cstamp;
+}
+
+uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *addr)
+{
+       return addr->a_cacheinfo.aci_tstamp;
+}
+
+/** @} */
+
+/**
+ * @name Flags Translations
+ * @{
+ */
+
+static const struct trans_tbl addr_flags[] = {
+       __ADD(IFA_F_SECONDARY, secondary)
+       __ADD(IFA_F_NODAD, nodad)
+       __ADD(IFA_F_OPTIMISTIC, optimistic)
+       __ADD(IFA_F_HOMEADDRESS, homeaddress)
+       __ADD(IFA_F_DEPRECATED, deprecated)
+       __ADD(IFA_F_TENTATIVE, tentative)
+       __ADD(IFA_F_PERMANENT, permanent)
+};
+
+char *rtnl_addr_flags2str(int flags, char *buf, size_t size)
+{
+       return __flags2str(flags, buf, size, addr_flags,
+                          ARRAY_SIZE(addr_flags));
+}
+
+int rtnl_addr_str2flags(const char *name)
+{
+       return __str2flags(name, addr_flags, ARRAY_SIZE(addr_flags));
+}
+
+/** @} */
+
+static struct nl_object_ops addr_obj_ops = {
+       .oo_name                = "route/addr",
+       .oo_size                = sizeof(struct rtnl_addr),
+       .oo_constructor         = addr_constructor,
+       .oo_free_data           = addr_free_data,
+       .oo_clone               = addr_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = addr_dump_line,
+           [NL_DUMP_DETAILS]   = addr_dump_details,
+           [NL_DUMP_STATS]     = addr_dump_stats,
+       },
+       .oo_compare             = addr_compare,
+       .oo_attrs2str           = addr_attrs2str,
+       .oo_id_attrs            = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+                                  ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN),
+};
+
+static struct nl_af_group addr_groups[] = {
+       { AF_INET,      RTNLGRP_IPV4_IFADDR },
+       { AF_INET6,     RTNLGRP_IPV6_IFADDR },
+       { END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_addr_ops = {
+       .co_name                = "route/addr",
+       .co_hdrsize             = sizeof(struct ifaddrmsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWADDR, NL_ACT_NEW, "new" },
+                                       { RTM_DELADDR, NL_ACT_DEL, "del" },
+                                       { RTM_GETADDR, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_groups              = addr_groups,
+       .co_request_update      = addr_request_update,
+       .co_msg_parser          = addr_msg_parser,
+       .co_obj_ops             = &addr_obj_ops,
+};
+
+static void __init addr_init(void)
+{
+       nl_cache_mngt_register(&rtnl_addr_ops);
+}
+
+static void __exit addr_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_addr_ops);
+}
+
+/** @} */
diff --git a/lib/route/class.c b/lib/route/class.c
new file mode 100644 (file)
index 0000000..050f42a
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * lib/route/class.c            Traffic Classes
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup class Traffic Classes
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/class.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/classifier.h>
+#include <netlink/utils.h>
+
+static struct nl_cache_ops rtnl_class_ops;
+static struct nl_object_ops class_obj_ops;
+
+static void class_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
+{
+       struct rtnl_class *class = (struct rtnl_class *) tc;
+       char buf[32];
+
+       if (class->c_info)
+               nl_dump(p, "child-qdisc %s ",
+                       rtnl_tc_handle2str(class->c_info, buf, sizeof(buf)));
+}
+
+
+static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                           struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct rtnl_class *class;
+       int err;
+
+       if (!(class = rtnl_class_alloc()))
+               return -NLE_NOMEM;
+
+       if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(class))) < 0)
+               goto errout;
+
+       err = pp->pp_cb(OBJ_CAST(class), pp);
+errout:
+       rtnl_class_put(class);
+
+       return err;
+}
+
+static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+       struct tcmsg tchdr = {
+               .tcm_family = AF_UNSPEC,
+               .tcm_ifindex = cache->c_iarg1,
+       };
+
+       return nl_send_simple(sk, RTM_GETTCLASS, NLM_F_DUMP, &tchdr,
+                             sizeof(tchdr));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_class *rtnl_class_alloc(void)
+{
+       struct rtnl_tc *tc;
+
+       tc = TC_CAST(nl_object_alloc(&class_obj_ops));
+       if (tc)
+               tc->tc_type = RTNL_TC_TYPE_CLASS;
+
+       return (struct rtnl_class *) tc;
+}
+
+void rtnl_class_put(struct rtnl_class *class)
+{
+       nl_object_put((struct nl_object *) class);
+}
+
+/** @} */
+
+
+/**
+ * @name Addition/Modification/Deletion
+ * @{
+ */
+
+static int class_build(struct rtnl_class *class, int type, int flags,
+                      struct nl_msg **result)
+{
+       uint32_t needed = TCA_ATTR_PARENT | TCA_ATTR_HANDLE;
+
+       if ((class->ce_mask & needed) == needed &&
+           TC_H_MAJ(class->c_parent) && TC_H_MAJ(class->c_handle) &&
+           TC_H_MAJ(class->c_parent) != TC_H_MAJ(class->c_handle)) {
+               APPBUG("TC_H_MAJ(parent) must match TC_H_MAJ(handle)");
+               return -NLE_INVAL;
+       }
+
+       return rtnl_tc_msg_build(TC_CAST(class), type, flags, result);
+}
+
+/**
+ * Build a netlink message requesting the addition of a traffic class
+ * @arg class          Traffic class to add 
+ * @arg flags          Additional netlink message flags
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_class_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
+ *
+ * @see rtnl_class_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
+                                struct nl_msg **result)
+{
+       return class_build(class, RTM_NEWTCLASS, flags, result);
+}
+
+/**
+ * Add/Update traffic class
+ * @arg sk             Netlink socket
+ * @arg class          Traffic class to add 
+ * @arg flags          Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWTCLASS netlink message requesting the addition
+ * of a new traffic class and sends the message to the kernel. The
+ * configuration of the traffic class is derived from the attributes
+ * of the specified traffic class.
+ *
+ * The following flags may be specified:
+ *  - \c NLM_F_CREATE:  Create traffic class if it does not exist,
+ *                      otherwise -NLE_OBJ_NOTFOUND is returned.
+ *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a traffic class with
+ *                      matching handle exists already.
+ *
+ * Existing traffic classes with matching handles will be updated,
+ * unless the flag \c NLM_F_EXCL is specified. If no matching traffic
+ * class exists, it will be created if the flag \c NLM_F_CREATE is set,
+ * otherwise the error -NLE_OBJ_NOTFOUND is returned. 
+ *
+ * If the parent qdisc does not support classes, the error
+ * \c NLE_OPNOTSUPP is returned.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the deletion of a traffic class
+ * @arg class          Traffic class to delete
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_class_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_class_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_build_delete_request(struct rtnl_class *class, struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct tcmsg tchdr;
+       uint32_t required = TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE;
+
+       if ((class->ce_mask & required) != required) {
+               APPBUG("ifindex and handle must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       if (!(msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0)))
+               return -NLE_NOMEM;
+
+       memset(&tchdr, 0, sizeof(tchdr));
+       tchdr.tcm_family = AF_UNSPEC;
+       tchdr.tcm_ifindex = class->c_ifindex;
+       tchdr.tcm_handle = class->c_handle;
+
+       if (class->ce_mask & TCA_ATTR_PARENT)
+               tchdr.tcm_parent = class->c_parent;
+
+       if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
+               nlmsg_free(msg);
+               return -NLE_MSGSIZE;
+       }
+
+       *result = msg;
+       return 0;
+}
+
+/**
+ * Delete traffic class
+ * @arg sk             Netlink socket
+ * @arg class          Traffic class to delete
+ *
+ * Builds a \c RTM_DELTCLASS netlink message requesting the deletion
+ * of a traffic class and sends the message to the kernel.
+ *
+ * The message is constructed out of the following attributes:
+ * - \c ifindex and \c handle (required)
+ * - \c parent (optional, must match if provided)
+ *
+ * All other class attributes including all class type specific
+ * attributes are ignored.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Leaf Qdisc
+ * @{
+ */
+
+/**
+ * Lookup the leaf qdisc of a traffic class
+ * @arg class          the parent traffic class
+ * @arg cache          a qdisc cache allocated using rtnl_qdisc_alloc_cache()
+ *
+ * @return Matching Qdisc or NULL if the traffic class has no leaf qdisc
+ */
+struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
+                                        struct nl_cache *cache)
+{
+       struct rtnl_qdisc *leaf;
+
+       if (!class->c_info)
+               return NULL;
+
+       leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex,
+                                       class->c_handle);
+       if (!leaf || leaf->q_handle != class->c_info)
+               return NULL;
+
+       return leaf;
+}
+
+/** @} */
+
+/**
+ * @name Cache Related Functions
+ * @{
+ */
+
+/**
+ * Allocate a cache and fill it with all configured traffic classes
+ * @arg sk             Netlink socket
+ * @arg ifindex                Interface index of the network device
+ * @arg result         Pointer to store the created cache
+ *
+ * Allocates a new traffic class cache and fills it with a list of all
+ * configured traffic classes on a specific network device. Release the
+ * cache with nl_cache_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
+                          struct nl_cache **result)
+{
+       struct nl_cache * cache;
+       int err;
+
+       if (!ifindex) {
+               APPBUG("ifindex must be specified");
+               return -NLE_INVAL;
+       }
+       
+       if (!(cache = nl_cache_alloc(&rtnl_class_ops)))
+               return -NLE_NOMEM;
+
+       cache->c_iarg1 = ifindex;
+       
+       if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+               nl_cache_free(cache);
+               return err;
+       }
+
+       *result = cache;
+       return 0;
+}
+
+/**
+ * Search traffic class by interface index and handle
+ * @arg cache          Traffic class cache
+ * @arg ifindex                Interface index
+ * @arg handle         ID of traffic class
+ *
+ * Searches a traffic class cache previously allocated with
+ * rtnl_class_alloc_cache() and searches for a traffi class matching
+ * the interface index and handle.
+ *
+ * The reference counter is incremented before returning the traffic
+ * class, therefore the reference must be given back with rtnl_class_put()
+ * after usage.
+ *
+ * @return Traffic class or NULL if no match was found.
+ */
+struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
+                                 uint32_t handle)
+{
+       struct rtnl_class *class;
+       
+       if (cache->c_ops != &rtnl_class_ops)
+               return NULL;
+
+       nl_list_for_each_entry(class, &cache->c_items, ce_list) {
+               if (class->c_handle == handle && class->c_ifindex == ifindex) {
+                       nl_object_get((struct nl_object *) class);
+                       return class;
+               }
+       }
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Deprecated Functions
+ * @{
+ */
+
+/**
+ * Call a callback for each child of a class
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
+                             void (*cb)(struct nl_object *, void *), void *arg)
+{
+       struct rtnl_class *filter;
+       
+       filter = rtnl_class_alloc();
+       if (!filter)
+               return;
+
+       rtnl_tc_set_parent(TC_CAST(filter), class->c_handle);
+       rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex);
+       rtnl_tc_set_kind(TC_CAST(filter), class->c_kind);
+
+       nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
+       rtnl_class_put(filter);
+}
+
+/**
+ * Call a callback for each classifier attached to the class
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
+                           void (*cb)(struct nl_object *, void *), void *arg)
+{
+       struct rtnl_cls *filter;
+
+       filter = rtnl_cls_alloc();
+       if (!filter)
+               return;
+
+       rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex);
+       rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent);
+
+       nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
+       rtnl_cls_put(filter);
+}
+
+/** @} */
+
+static struct rtnl_tc_type_ops class_ops = {
+       .tt_type                = RTNL_TC_TYPE_CLASS,
+       .tt_dump_prefix         = "class",
+       .tt_dump = {
+           [NL_DUMP_DETAILS]   = class_dump_details,
+       },
+};
+
+static struct nl_object_ops class_obj_ops = {
+       .oo_name                = "route/class",
+       .oo_size                = sizeof(struct rtnl_class),
+       .oo_free_data           = rtnl_tc_free_data,
+       .oo_clone               = rtnl_tc_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = rtnl_tc_dump_line,
+           [NL_DUMP_DETAILS]   = rtnl_tc_dump_details,
+           [NL_DUMP_STATS]     = rtnl_tc_dump_stats,
+       },
+       .oo_compare             = rtnl_tc_compare,
+       .oo_id_attrs            = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
+};
+
+static struct nl_cache_ops rtnl_class_ops = {
+       .co_name                = "route/class",
+       .co_hdrsize             = sizeof(struct tcmsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWTCLASS, NL_ACT_NEW, "new" },
+                                       { RTM_DELTCLASS, NL_ACT_DEL, "del" },
+                                       { RTM_GETTCLASS, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_request_update      = &class_request_update,
+       .co_msg_parser          = &class_msg_parser,
+       .co_obj_ops             = &class_obj_ops,
+};
+
+static void __init class_init(void)
+{
+       rtnl_tc_type_register(&class_ops);
+       nl_cache_mngt_register(&rtnl_class_ops);
+}
+
+static void __exit class_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_class_ops);
+       rtnl_tc_type_unregister(&class_ops);
+}
+
+/** @} */
diff --git a/lib/route/classid.c b/lib/route/classid.c
new file mode 100644 (file)
index 0000000..f2d3a01
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * lib/route/classid.c       ClassID Management
+ *
+ *     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) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup classid ClassID Management
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/tc.h>
+
+struct classid_map
+{
+       uint32_t                classid;
+       char *                  name;
+       struct nl_list_head     name_list;
+};
+
+#define CLASSID_NAME_HT_SIZ 256
+
+static struct nl_list_head tbl_name[CLASSID_NAME_HT_SIZ];
+
+static void *id_root = NULL;
+
+static int compare_id(const void *pa, const void *pb)
+{
+       const struct classid_map *ma = pa;
+       const struct classid_map *mb = pb;
+
+       if (ma->classid < mb->classid)
+               return -1;
+
+       if (ma->classid > mb->classid)
+               return 1;
+
+       return 0;
+}
+
+/* djb2 */
+static unsigned int classid_tbl_hash(const char *str)
+{
+       unsigned long hash = 5381;
+       int c;
+
+       while ((c = *str++))
+               hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+       return hash % CLASSID_NAME_HT_SIZ;
+}
+
+static int classid_lookup(const char *name, uint32_t *result)
+{
+       struct classid_map *map;
+       int n = classid_tbl_hash(name);
+
+       nl_list_for_each_entry(map, &tbl_name[n], name_list) {
+               if (!strcasecmp(map->name, name)) {
+                       *result = map->classid;
+                       return 0;
+               }
+       }
+
+       return -NLE_OBJ_NOTFOUND;
+}
+
+static char *name_lookup(const uint32_t classid)
+{
+       void *res;
+       struct classid_map cm = {
+               .classid = classid,
+               .name = "search entry",
+       };
+
+       if ((res = tfind(&cm, &id_root, &compare_id)))
+               return (*(struct classid_map **) res)->name;
+
+       return NULL;
+}
+
+/**
+ * @name Traffic Control Handle Translations
+ * @{
+ */
+
+/**
+ * Convert a traffic control handle to a character string (Reentrant).
+ * @arg handle         traffic control handle
+ * @arg buf            destination buffer
+ * @arg len            buffer length
+ *
+ * Converts a tarffic control handle to a character string in the
+ * form of \c MAJ:MIN and stores it in the specified destination buffer.
+ *
+ * @return The destination buffer or the type encoded in hexidecimal
+ *         form if no match was found.
+ */
+char *rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
+{
+       if (TC_H_ROOT == handle)
+               snprintf(buf, len, "root");
+       else if (TC_H_UNSPEC == handle)
+               snprintf(buf, len, "none");
+       else if (TC_H_INGRESS == handle)
+               snprintf(buf, len, "ingress");
+       else {
+               char *name;
+
+               if ((name = name_lookup(handle)))
+                       snprintf(buf, len, "%s", name);
+               else if (0 == TC_H_MAJ(handle))
+                       snprintf(buf, len, ":%x", TC_H_MIN(handle));
+               else if (0 == TC_H_MIN(handle))
+                       snprintf(buf, len, "%x:", TC_H_MAJ(handle) >> 16);
+               else
+                       snprintf(buf, len, "%x:%x",
+                               TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
+       }
+
+       return buf;
+}
+
+/**
+ * Convert a charactering strint to a traffic control handle
+ * @arg str            traffic control handle as character string
+ * @arg res            destination buffer
+ *
+ * Converts the provided character string specifying a traffic
+ * control handle to the corresponding numeric value.
+ *
+ * The handle must be provided in one of the following formats:
+ *  - NAME
+ *  - root
+ *  - none
+ *  - MAJ:
+ *  - :MIN
+ *  - NAME:MIN
+ *  - MAJ:MIN
+ *  - MAJMIN
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_tc_str2handle(const char *str, uint32_t *res)
+{
+       char *colon, *end;
+       uint32_t h;
+       int err;
+
+       if (!strcasecmp(str, "root")) {
+               *res = TC_H_ROOT;
+               return 0;
+       }
+
+       if (!strcasecmp(str, "none")) {
+               *res = TC_H_UNSPEC;
+               return 0;
+       }
+
+       if (!strcasecmp(str, "ingress")) {
+               *res = TC_H_INGRESS;
+               return 0;
+       }
+
+       h = strtoul(str, &colon, 16);
+
+       /* MAJ is not a number */
+       if (colon == str) {
+not_a_number:
+               if (*colon == ':') {
+                       /* :YYYY */
+                       h = 0;
+               } else {
+                       size_t len;
+                       char name[64] = { 0 };
+
+                       if (!(colon = strpbrk(str, ":"))) {
+                               /* NAME */
+                               return classid_lookup(str, res);
+                       } else {
+                               /* NAME:YYYY */
+                               len = colon - str;
+                               if (len >= sizeof(name))
+                                       return -NLE_INVAL;
+
+                               memcpy(name, str, len);
+
+                               if ((err = classid_lookup(name, &h)) < 0)
+                                       return err;
+
+                               /* Name must point to a qdisc alias */
+                               if (TC_H_MIN(h))
+                                       return -NLE_INVAL;
+
+                               /* NAME: is not allowed */
+                               if (colon[1] == '\0')
+                                       return -NLE_INVAL;
+
+                               goto update;
+                       }
+               }
+       }
+
+       if (':' == *colon) {
+               /* check if we would lose bits */
+               if (TC_H_MAJ(h))
+                       return -NLE_RANGE;
+               h <<= 16;
+
+               if ('\0' == colon[1]) {
+                       /* XXXX: */
+                       *res = h;
+               } else {
+                       /* XXXX:YYYY */
+                       uint32_t l;
+
+update:
+                       l = strtoul(colon+1, &end, 16);
+
+                       /* check if we overlap with major part */
+                       if (TC_H_MAJ(l))
+                               return -NLE_RANGE;
+
+                       if ('\0' != *end)
+                               return -NLE_INVAL;
+
+                       *res = (h | l);
+               }
+       } else if ('\0' == *colon) {
+               /* XXXXYYYY */
+               *res = h;
+       } else
+               goto not_a_number;
+
+       return 0;
+}
+
+static void free_nothing(void *arg)
+{
+}
+
+static void classid_map_free(struct classid_map *map)
+{
+       if (!map)
+               return;
+
+       free(map->name);
+       free(map);
+}
+
+static void clear_hashtable(void)
+{
+       int i;
+
+       for (i = 0; i < CLASSID_NAME_HT_SIZ; i++) {
+               struct classid_map *map, *n;
+
+               nl_list_for_each_entry_safe(map, n, &tbl_name[i], name_list)
+                       classid_map_free(map);
+
+               nl_init_list_head(&tbl_name[i]);
+
+       }
+
+       if (id_root) {
+               tdestroy(&id_root, &free_nothing);
+               id_root = NULL;
+       }
+}
+
+static int classid_map_add(uint32_t classid, const char *name)
+{
+       struct classid_map *map;
+       int n;
+
+       if (!(map = calloc(1, sizeof(*map))))
+               return -NLE_NOMEM;
+
+       map->classid = classid;
+       map->name = strdup(name);
+
+       n = classid_tbl_hash(map->name);
+       nl_list_add_tail(&map->name_list, &tbl_name[n]);
+
+       if (!tsearch((void *) map, &id_root, &compare_id)) {
+               classid_map_free(map);
+               return -NLE_NOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ * (Re-)read classid file
+ *
+ * Rereads the contents of the classid file (typically found at the location
+ * /etc/libnl/classid) and refreshes the classid maps.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_tc_read_classid_file(void)
+{
+       static time_t last_read;
+       struct stat st;
+       char buf[256], *path;
+       FILE *fd;
+       int err;
+
+       if (build_sysconf_path(&path, "classid") < 0)
+               return -NLE_NOMEM;
+
+       /* if stat fails, just (re-)read the file */
+       if (stat(path, &st) == 0) {
+               /* Don't re-read file if file is unchanged */
+               if (last_read == st.st_mtime) {
+                       err = 0;
+                       goto errout;
+               }
+       }
+
+       if (!(fd = fopen(path, "r"))) {
+               err = -nl_syserr2nlerr(errno);
+               goto errout;
+       }
+
+       clear_hashtable();
+
+       while (fgets(buf, sizeof(buf), fd)) {
+               uint32_t classid;
+               char *ptr, *tok;
+
+               /* ignore comments and empty lines */
+               if (*buf == '#' || *buf == '\n' || *buf == '\r')
+                       continue;
+
+               /* token 1 */
+               if (!(tok = strtok_r(buf, " \t", &ptr))) {
+                       err = -NLE_INVAL;
+                       goto errout_close;
+               }
+
+               if ((err = rtnl_tc_str2handle(tok, &classid)) < 0)
+                       goto errout_close;
+
+               if (!(tok = strtok_r(NULL, " \t\n\r#", &ptr))) {
+                       err = -NLE_INVAL;
+                       goto errout_close;
+               }
+
+               if ((err = classid_map_add(classid, tok)) < 0)
+                       goto errout_close;
+       }
+
+       err = 0;
+       last_read = st.st_mtime;
+
+errout_close:
+       fclose(fd);
+errout:
+       free(path);
+
+       return err;
+
+}
+
+int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent)
+{
+       static uint32_t base = 0x4000 << 16;
+       uint32_t classid;
+       char *path;
+       FILE *fd;
+       int err = 0;
+
+       if (parent == TC_H_ROOT || parent == TC_H_INGRESS) {
+               do {
+                       base += (1 << 16);
+                       if (base == TC_H_MAJ(TC_H_ROOT))
+                               base = 0x4000 << 16;
+               } while (name_lookup(base));
+
+               classid = base;
+       } else {
+               classid = TC_H_MAJ(parent);
+               do {
+                       if (TC_H_MIN(++classid) == TC_H_MIN(TC_H_ROOT))
+                               return -NLE_RANGE;
+               } while (name_lookup(classid));
+       }
+
+       NL_DBG(2, "Generated new classid %#x\n", classid);
+
+       if (build_sysconf_path(&path, "classid") < 0)
+               return -NLE_NOMEM;
+
+       if (!(fd = fopen(path, "a"))) {
+               err = -nl_syserr2nlerr(errno);
+               goto errout;
+       }
+
+       fprintf(fd, "%x:", TC_H_MAJ(classid) >> 16);
+       if (TC_H_MIN(classid))
+               fprintf(fd, "%x", TC_H_MIN(classid));
+       fprintf(fd, "\t\t\t%s\n", name);
+
+       fclose(fd);
+
+       if ((err = classid_map_add(classid, name)) < 0) {
+               /*
+                * Error adding classid map, re-read classid file is best
+                * option here. It is likely to fail as well but better
+                * than nothing, entry was added to the file already anyway.
+                */
+               rtnl_tc_read_classid_file();
+       }
+
+       *result = classid;
+       err = 0;
+errout:
+       free(path);
+
+       return err;
+}
+
+/** @} */
+
+static void __init classid_init(void)
+{
+       int err, i;
+
+       for (i = 0; i < CLASSID_NAME_HT_SIZ; i++)
+               nl_init_list_head(&tbl_name[i]);
+
+       if ((err = rtnl_tc_read_classid_file()) < 0)
+               NL_DBG(1, "Failed to read classid file: %s\n", nl_geterror(err));
+}
+
+static void free_map(void *map) {
+       free(((struct classid_map *)map)->name);
+       free(map);
+};
+
+static void __exit classid_exit(void)
+{
+       tdestroy(id_root, free_map);
+}
+/** @} */
diff --git a/lib/route/cls.c b/lib/route/cls.c
new file mode 100644 (file)
index 0000000..7a809bb
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * lib/route/classifier.c       Classifier
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup cls Classifiers
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/link.h>
+
+/** @cond SKIP */
+#define CLS_ATTR_PRIO          (TCA_ATTR_MAX << 1)
+#define CLS_ATTR_PROTOCOL      (TCA_ATTR_MAX << 2)
+/** @endcond */
+
+static struct nl_object_ops cls_obj_ops;
+static struct nl_cache_ops rtnl_cls_ops;
+
+
+static int cls_build(struct rtnl_cls *cls, int type, int flags,
+                    struct nl_msg **result)
+{
+       int err, prio, proto;
+       struct tcmsg *tchdr;
+       uint32_t required = TCA_ATTR_IFINDEX;
+
+       if ((cls->ce_mask & required) != required) {
+               APPBUG("ifindex must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result);
+       if (err < 0)
+               return err;
+
+       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));
+
+       return 0;
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_cls *rtnl_cls_alloc(void)
+{
+       struct rtnl_tc *tc;
+
+       tc = TC_CAST(nl_object_alloc(&cls_obj_ops));
+       if (tc)
+               tc->tc_type = RTNL_TC_TYPE_CLS;
+
+       return (struct rtnl_cls *) tc;
+}
+
+void rtnl_cls_put(struct rtnl_cls *cls)
+{
+       nl_object_put((struct nl_object *) cls);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio)
+{
+       cls->c_prio = prio;
+       cls->ce_mask |= CLS_ATTR_PRIO;
+}
+
+uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls)
+{
+       if (cls->ce_mask & CLS_ATTR_PRIO)
+               return cls->c_prio;
+       else
+               return 0;
+}
+
+void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol)
+{
+       cls->c_protocol = protocol;
+       cls->ce_mask |= CLS_ATTR_PROTOCOL;
+}
+
+uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
+{
+       if (cls->ce_mask & CLS_ATTR_PROTOCOL)
+               return cls->c_protocol;
+       else
+               return ETH_P_ALL;
+}
+
+/** @} */
+
+
+/**
+ * @name Addition/Modification/Deletion
+ * @{
+ */
+
+/**
+ * Build a netlink message requesting the addition of a classifier
+ * @arg cls            Classifier to add 
+ * @arg flags          Additional netlink message flags
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_cls_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
+ *
+ * @see rtnl_cls_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
+                              struct nl_msg **result)
+{
+       if (!(flags & NLM_F_CREATE) && !(cls->ce_mask & CLS_ATTR_PRIO)) {
+               APPBUG("prio must be specified if not a new classifier");
+               return -NLE_MISSING_ATTR;
+       }
+
+       return cls_build(cls, RTM_NEWTFILTER, flags, result);
+}
+
+/**
+ * Add/Update classifier
+ * @arg sk             Netlink socket
+ * @arg cls            Classifier to add/update
+ * @arg flags          Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWTFILTER netlink message requesting the addition
+ * of a new classifier and sends the message to the kernel. The
+ * configuration of the classifier is derived from the attributes of
+ * the specified traffic class.
+ *
+ * The following flags may be specified:
+ *  - \c NLM_F_CREATE:  Create classifier if it does not exist,
+ *                      otherwise -NLE_OBJ_NOTFOUND is returned.
+ *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a classifier with
+ *                      matching handle exists already.
+ *
+ * Existing classifiers with matching handles will be updated, unless
+ * the flag \c NLM_F_EXCL is specified. If no matching classifier
+ * exists, it will be created if the flag \c NLM_F_CREATE is set,
+ * otherwise the error -NLE_OBJ_NOTFOUND is returned. 
+ *
+ * If the parent qdisc does not support classes, the error
+ * \c NLE_OPNOTSUPP is returned.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/**
+ * 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 0 on success or a negative error code.
+ */
+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, result);
+}
+
+/**
+ * Change a classifier
+ * @arg sk             Netlink socket.
+ * @arg cls            classifier to change
+ * @arg flags          additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_cls_build_change_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been processed.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
+               return err;
+       
+       return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the deletion of a classifier
+ * @arg cls            Classifier to delete
+ * @arg flags          Additional netlink message flags
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_cls_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_cls_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
+                                 struct nl_msg **result)
+{
+       uint32_t required = CLS_ATTR_PRIO;
+
+       if ((cls->ce_mask & required) != required) {
+               APPBUG("prio must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       return cls_build(cls, RTM_DELTFILTER, flags, result);
+}
+
+/**
+ * Delete classifier
+ * @arg sk             Netlink socket
+ * @arg cls            Classifier to delete
+ * @arg flags          Additional netlink message flags
+ *
+ * Builds a \c RTM_DELTFILTER netlink message requesting the deletion
+ * of a classifier and sends the message to the kernel.
+ *
+ * The message is constructed out of the following attributes:
+ * - \c ifindex (required)
+ * - \c prio (required)
+ * - \c protocol (required)
+ * - \c handle (required)
+ * - \c parent (optional, if not specified parent equals root-qdisc)
+ * - \c kind (optional, must match if provided)
+ *
+ * All other classifier attributes including all class type specific
+ * attributes are ignored.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
+               return err;
+       
+       return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Cache Related Functions
+ * @{
+ */
+
+/**
+ * Allocate a cache and fill it with all configured classifiers
+ * @arg sk             Netlink socket
+ * @arg ifindex                Interface index of the network device
+ * @arg parent         Parent qdisc/traffic class class
+ * @arg result         Pointer to store the created cache
+ *
+ * Allocates a new classifier cache and fills it with a list of all
+ * configured classifier attached to the specified parent qdisc/traffic
+ * class on the specified network device. Release the cache with
+ * nl_cache_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent,                      struct nl_cache **result)
+{
+       struct nl_cache * cache;
+       int err;
+       
+       if (!(cache = nl_cache_alloc(&rtnl_cls_ops)))
+               return -NLE_NOMEM;
+
+       cache->c_iarg1 = ifindex;
+       cache->c_iarg2 = parent;
+       
+       if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+               nl_cache_free(cache);
+               return err;
+       }
+
+       *result = cache;
+       return 0;
+}
+
+/** @} */
+
+static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
+{
+       struct rtnl_cls *cls = (struct rtnl_cls *) tc;
+       char buf[32];
+
+       nl_dump(p, " prio %u protocol %s", cls->c_prio,
+               nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf)));
+}
+
+static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                         struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct rtnl_cls *cls;
+       int err;
+
+       if (!(cls = rtnl_cls_alloc()))
+               return -NLE_NOMEM;
+
+       if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0)
+               goto errout;
+
+       cls->c_prio = TC_H_MAJ(cls->c_info) >> 16;
+       cls->c_protocol = ntohs(TC_H_MIN(cls->c_info));
+
+       err = pp->pp_cb(OBJ_CAST(cls), pp);
+errout:
+       rtnl_cls_put(cls);
+
+       return err;
+}
+
+static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+       struct tcmsg tchdr = {
+               .tcm_family = AF_UNSPEC,
+               .tcm_ifindex = cache->c_iarg1,
+               .tcm_parent = cache->c_iarg2,
+       };
+
+       return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr,
+                             sizeof(tchdr));
+}
+
+static struct rtnl_tc_type_ops cls_ops = {
+       .tt_type                = RTNL_TC_TYPE_CLS,
+       .tt_dump_prefix         = "cls",
+       .tt_dump = {
+               [NL_DUMP_LINE]  = cls_dump_line,
+       },
+};
+
+static struct nl_cache_ops rtnl_cls_ops = {
+       .co_name                = "route/cls",
+       .co_hdrsize             = sizeof(struct tcmsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWTFILTER, NL_ACT_NEW, "new" },
+                                       { RTM_DELTFILTER, NL_ACT_DEL, "del" },
+                                       { RTM_GETTFILTER, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_request_update      = cls_request_update,
+       .co_msg_parser          = cls_msg_parser,
+       .co_obj_ops             = &cls_obj_ops,
+};
+
+static struct nl_object_ops cls_obj_ops = {
+       .oo_name                = "route/cls",
+       .oo_size                = sizeof(struct rtnl_cls),
+       .oo_free_data           = rtnl_tc_free_data,
+       .oo_clone               = rtnl_tc_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = rtnl_tc_dump_line,
+           [NL_DUMP_DETAILS]   = rtnl_tc_dump_details,
+           [NL_DUMP_STATS]     = rtnl_tc_dump_stats,
+       },
+       .oo_compare             = rtnl_tc_compare,
+       .oo_id_attrs            = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
+};
+
+static void __init cls_init(void)
+{
+       rtnl_tc_type_register(&cls_ops);
+       nl_cache_mngt_register(&rtnl_cls_ops);
+}
+
+static void __exit cls_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_cls_ops);
+       rtnl_tc_type_unregister(&cls_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/basic.c b/lib/route/cls/basic.c
new file mode 100644 (file)
index 0000000..fb1c382
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * lib/route/cls/basic.c       Basic Classifier
+ *
+ *     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-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_basic Basic Classifier
+ *
+ * @par Introduction
+ * The basic classifier is the simplest form of a classifier. It does
+ * not have any special classification capabilities, instead it can be
+ * used to classify exclusively based on extended matches or to
+ * create a "catch-all" filter.
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/basic.h>
+#include <netlink/route/cls/ematch.h>
+
+struct rtnl_basic
+{
+       uint32_t                        b_target;
+       struct rtnl_ematch_tree *       b_ematch;
+       int                             b_mask;
+};
+
+/** @cond SKIP */
+#define BASIC_ATTR_TARGET      0x001
+#define BASIC_ATTR_EMATCH      0x002
+/** @endcond */
+
+static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = {
+       [TCA_BASIC_CLASSID]     = { .type = NLA_U32 },
+       [TCA_BASIC_EMATCHES]    = { .type = NLA_NESTED },
+};
+
+static int basic_clone(void *_dst, void *_src)
+{
+       return -NLE_OPNOTSUPP;
+}
+
+static void basic_free_data(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_basic *b = data;
+
+       if (!b)
+               return;
+
+       rtnl_ematch_tree_free(b->b_ematch);
+}
+
+static int basic_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_BASIC_MAX + 1];
+       struct rtnl_basic *b = data;
+       int err;
+
+       err = tca_parse(tb, TCA_BASIC_MAX, tc, basic_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_BASIC_CLASSID]) {
+               b->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]);
+               b->b_mask |= BASIC_ATTR_TARGET;
+       }
+
+       if (tb[TCA_BASIC_EMATCHES]) {
+               if ((err = rtnl_ematch_parse_attr(tb[TCA_BASIC_EMATCHES],
+                                            &b->b_ematch)) < 0)
+                       return err;
+
+               if (b->b_ematch)
+                       b->b_mask |= BASIC_ATTR_EMATCH;
+       }
+
+       return 0;
+}
+
+static void basic_dump_line(struct rtnl_tc *tc, void *data,
+                           struct nl_dump_params *p)
+{
+       struct rtnl_basic *b = data;
+       char buf[32];
+
+       if (!b)
+               return;
+
+       if (b->b_mask & BASIC_ATTR_EMATCH)
+               nl_dump(p, " ematch");
+       else
+               nl_dump(p, " match-all");
+
+       if (b->b_mask & BASIC_ATTR_TARGET)
+               nl_dump(p, " target %s",
+                       rtnl_tc_handle2str(b->b_target, buf, sizeof(buf)));
+}
+
+static void basic_dump_details(struct rtnl_tc *tc, void *data,
+                              struct nl_dump_params *p)
+{
+       struct rtnl_basic *b = data;
+
+       if (!b)
+               return;
+
+       if (b->b_mask & BASIC_ATTR_EMATCH) {
+               nl_dump_line(p, "    ematch ");
+               rtnl_ematch_tree_dump(b->b_ematch, p);
+       } else
+               nl_dump(p, "no options.\n");
+}
+
+static int basic_msg_fill(struct rtnl_tc *tc, void *data,
+                         struct nl_msg *msg)
+{
+       struct rtnl_basic *b = data;
+
+       if (!b)
+               return 0;
+
+       if (!(b->b_mask & BASIC_ATTR_TARGET))
+               return -NLE_MISSING_ATTR;
+
+       NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_target);
+
+       if (b->b_mask & BASIC_ATTR_EMATCH &&
+           rtnl_ematch_fill_attr(msg, TCA_BASIC_EMATCHES, b->b_ematch) < 0)
+               goto nla_put_failure;
+       
+       return 0;
+
+nla_put_failure:
+       return -NLE_NOMEM;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target)
+{
+       struct rtnl_basic *b;
+
+       if (!(b = rtnl_tc_data(TC_CAST(cls))))
+               return;
+
+       b->b_target = target;
+       b->b_mask |= BASIC_ATTR_TARGET;
+}
+
+uint32_t rtnl_basic_get_target(struct rtnl_cls *cls)
+{
+       struct rtnl_basic *b;
+
+       if (!(b = rtnl_tc_data(TC_CAST(cls))))
+               return 0;
+
+       return b->b_target;
+}
+
+void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
+{
+       struct rtnl_basic *b;
+
+       if (!(b = rtnl_tc_data(TC_CAST(cls))))
+               return;
+
+       if (b->b_ematch) {
+               rtnl_ematch_tree_free(b->b_ematch);
+               b->b_mask &= ~BASIC_ATTR_EMATCH;
+       }
+
+       b->b_ematch = tree;
+
+       if (tree)
+               b->b_mask |= BASIC_ATTR_EMATCH;
+}
+
+struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls)
+{
+       struct rtnl_basic *b;
+
+       if (!(b = rtnl_tc_data(TC_CAST(cls))))
+               return NULL;
+
+       return b->b_ematch;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops basic_ops = {
+       .to_kind                = "basic",
+       .to_type                = RTNL_TC_TYPE_CLS,
+       .to_size                = sizeof(struct rtnl_basic),
+       .to_msg_parser          = basic_msg_parser,
+       .to_clone               = basic_clone,
+       .to_free_data           = basic_free_data,
+       .to_msg_fill            = basic_msg_fill,
+       .to_dump = {
+           [NL_DUMP_LINE]      = basic_dump_line,
+           [NL_DUMP_DETAILS]   = basic_dump_details,
+       },
+};
+
+static void __init basic_init(void)
+{
+       rtnl_tc_register(&basic_ops);
+}
+
+static void __exit basic_exit(void)
+{
+       rtnl_tc_unregister(&basic_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/cgroup.c b/lib/route/cls/cgroup.c
new file mode 100644 (file)
index 0000000..c5b7561
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * lib/route/cls/cgroup.c      Control Groups Classifier
+ *
+ *     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) 2009-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_cgroup Control Groups Classifier
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/cgroup.h>
+#include <netlink/route/cls/ematch.h>
+
+/** @cond SKIP */
+#define CGROUP_ATTR_EMATCH      0x001
+/** @endcond */
+
+static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = {
+       [TCA_CGROUP_EMATCHES]   = { .type = NLA_NESTED },
+};
+
+static int cgroup_clone(void *dst, void *src)
+{
+       return -NLE_OPNOTSUPP;
+}
+
+static void cgroup_free_data(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_cgroup *c = data;
+
+       if (!c)
+               return;
+
+       rtnl_ematch_tree_free(c->cg_ematch);
+}
+
+static int cgroup_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_CGROUP_MAX + 1];
+       struct rtnl_cgroup *c = data;
+       int err;
+
+       err = tca_parse(tb, TCA_CGROUP_MAX, tc, cgroup_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_CGROUP_EMATCHES]) {
+               if ((err = rtnl_ematch_parse_attr(tb[TCA_CGROUP_EMATCHES],
+                                                 &c->cg_ematch)) < 0)
+                       return err;
+               c->cg_mask |= CGROUP_ATTR_EMATCH;
+       }
+
+#if 0
+       TODO:
+       TCA_CGROUP_ACT,
+       TCA_CGROUP_POLICE,
+#endif
+
+       return 0;
+}
+
+static void cgroup_dump_line(struct rtnl_tc *tc, void *data,
+                            struct nl_dump_params *p)
+{
+       struct rtnl_cgroup *c = data;
+
+       if (!c)
+               return;
+
+       if (c->cg_mask & CGROUP_ATTR_EMATCH)
+               nl_dump(p, " ematch");
+       else
+               nl_dump(p, " match-all");
+}
+
+static void cgroup_dump_details(struct rtnl_tc *tc, void *data,
+                               struct nl_dump_params *p)
+{
+       struct rtnl_cgroup *c = data;
+
+       if (!c)
+               return;
+
+       if (c->cg_mask & CGROUP_ATTR_EMATCH) {
+               nl_dump_line(p, "    ematch ");
+
+               if (c->cg_ematch)
+                       rtnl_ematch_tree_dump(c->cg_ematch, p);
+               else
+                       nl_dump(p, "<no tree>");
+       } else
+               nl_dump(p, "no options");
+}
+
+static int cgroup_fill_msg(struct rtnl_tc *tc, void *data,
+                          struct nl_msg *msg)
+{
+       struct rtnl_cgroup *c = data;
+
+       if (!c)
+               BUG();
+
+       if (!(tc->ce_mask & TCA_ATTR_HANDLE))
+               return -NLE_MISSING_ATTR;
+
+       if (c->cg_mask & CGROUP_ATTR_EMATCH)
+               return rtnl_ematch_fill_attr(msg, TCA_CGROUP_EMATCHES,
+                                            c->cg_ematch);
+
+       return 0;
+}
+
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+void rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
+{
+       struct rtnl_cgroup *c;
+
+       if (!(c = rtnl_tc_data(TC_CAST(cls))))
+               BUG();
+
+       if (c->cg_ematch) {
+               rtnl_ematch_tree_free(c->cg_ematch);
+               c->cg_mask &= ~CGROUP_ATTR_EMATCH;
+       }
+
+       c->cg_ematch = tree;
+
+       if (tree)
+               c->cg_mask |= CGROUP_ATTR_EMATCH;
+}
+
+struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls)
+{
+       struct rtnl_cgroup *c;
+
+       if (!(c = rtnl_tc_data(TC_CAST(cls))))
+               BUG();
+
+       return c->cg_ematch;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops cgroup_ops = {
+       .to_kind                = "cgroup",
+       .to_type                = RTNL_TC_TYPE_CLS,
+       .to_size                = sizeof(struct rtnl_cgroup),
+       .to_clone               = cgroup_clone,
+       .to_msg_parser          = cgroup_msg_parser,
+       .to_free_data           = cgroup_free_data,
+       .to_msg_fill            = cgroup_fill_msg,
+       .to_dump = {
+           [NL_DUMP_LINE]      = cgroup_dump_line,
+           [NL_DUMP_DETAILS]   = cgroup_dump_details,
+       },
+};
+
+static void __init cgroup_init(void)
+{
+       rtnl_tc_register(&cgroup_ops);
+}
+
+static void __exit cgroup_exit(void)
+{
+       rtnl_tc_unregister(&cgroup_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c
new file mode 100644 (file)
index 0000000..89b5067
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * lib/route/cls/ematch.c      Extended Matches
+ *
+ *     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-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup ematch Extended Match
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/cmp.h>
+
+#include "ematch_syntax.h"
+#include "ematch_grammar.h"
+
+/**
+ * @name Module API
+ * @{
+ */
+
+static NL_LIST_HEAD(ematch_ops_list);
+
+/**
+ * Register ematch module
+ * @arg ops            Module operations.
+ *
+ * This function must be called by each ematch module at initialization
+ * time. It registers the calling module as available module.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
+{
+       if (rtnl_ematch_lookup_ops(ops->eo_kind))
+               return -NLE_EXIST;
+
+       NL_DBG(1, "ematch module \"%s\" registered\n", ops->eo_name);
+
+       nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
+
+       return 0;
+}
+
+/**
+ * Lookup ematch module by identification number.
+ * @arg kind           Module kind.
+ *
+ * Searches the list of registered ematch modules for match and returns it.
+ *
+ * @return Module operations or NULL if not found.
+ */
+struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind)
+{
+       struct rtnl_ematch_ops *ops;
+
+       nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
+               if (ops->eo_kind == kind)
+                       return ops;
+
+       return NULL;
+}
+
+/**
+ * Lookup ematch module by name
+ * @arg name           Name of ematch module.
+ *
+ * Searches the list of registered ematch modules for a match and returns it.
+ *
+ * @return Module operations or NULL if not fuond.
+ */
+struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_by_name(const char *name)
+{
+       struct rtnl_ematch_ops *ops;
+
+       nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
+               if (!strcasecmp(ops->eo_name, name))
+                       return ops;
+
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Match
+ */
+
+/**
+ * Allocate ematch object.
+ *
+ * Allocates and initializes an ematch object.
+ *
+ * @return New ematch object or NULL.
+ */
+struct rtnl_ematch *rtnl_ematch_alloc(void)
+{
+       struct rtnl_ematch *e;
+
+       if (!(e = calloc(1, sizeof(*e))))
+               return NULL;
+
+       NL_DBG(2, "allocated ematch %p\n", e);
+
+       NL_INIT_LIST_HEAD(&e->e_list);
+       NL_INIT_LIST_HEAD(&e->e_childs);
+
+       return e;
+}
+
+/**
+ * Add ematch to the end of the parent's list of children.
+ * @arg parent         parent ematch object
+ * @arg child          ematch object to be added to parent
+ *
+ * The parent must be a container ematch.
+ */
+int rtnl_ematch_add_child(struct rtnl_ematch *parent,
+                          struct rtnl_ematch *child)
+{
+       if (parent->e_kind != TCF_EM_CONTAINER)
+               return -NLE_OPNOTSUPP;
+
+       NL_DBG(2, "added ematch %p \"%s\" to container %p\n",
+                 child, child->e_ops->eo_name, parent);
+
+       nl_list_add_tail(&child->e_list, &parent->e_childs);
+
+       return 0;
+}
+
+/**
+ * Remove ematch from the list of ematches it is linked to.
+ * @arg ematch         ematch object
+ */
+void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
+{
+       NL_DBG(2, "unlinked ematch %p from any lists\n", ematch);
+
+       if (!nl_list_empty(&ematch->e_childs))
+               NL_DBG(1, "warning: ematch %p with childs was unlinked\n",
+                         ematch);
+
+       nl_list_del(&ematch->e_list);
+       nl_init_list_head(&ematch->e_list);
+}
+
+void rtnl_ematch_free(struct rtnl_ematch *ematch)
+{
+       NL_DBG(2, "freed ematch %p\n", ematch);
+       rtnl_ematch_unlink(ematch);
+       free(ematch->e_data);
+       free(ematch);
+}
+
+int rtnl_ematch_set_ops(struct rtnl_ematch *ematch, struct rtnl_ematch_ops *ops)
+{
+       if (ematch->e_ops)
+               return -NLE_EXIST;
+
+       ematch->e_ops = ops;
+       ematch->e_kind = ops->eo_kind;
+
+       if (ops->eo_datalen) {
+               ematch->e_data = calloc(1, ops->eo_datalen);
+               if (!ematch->e_data)
+                       return -NLE_NOMEM;
+
+               ematch->e_datalen = ops->eo_datalen;
+       }
+
+       return 0;
+}
+
+int rtnl_ematch_set_kind(struct rtnl_ematch *ematch, uint16_t kind)
+{
+       struct rtnl_ematch_ops *ops;
+
+       if (ematch->e_kind)
+               return -NLE_EXIST;
+
+       ematch->e_kind = kind;
+
+       if ((ops = rtnl_ematch_lookup_ops(kind)))
+               rtnl_ematch_set_ops(ematch, ops);
+
+       return 0;
+}
+
+int rtnl_ematch_set_name(struct rtnl_ematch *ematch, const char *name)
+{
+       struct rtnl_ematch_ops *ops;
+
+       if (ematch->e_kind)
+               return -NLE_EXIST;
+
+       if (!(ops = rtnl_ematch_lookup_ops_by_name(name)))
+               return -NLE_OPNOTSUPP;
+
+       rtnl_ematch_set_ops(ematch, ops);
+
+       return 0;
+}
+
+void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags)
+{
+       ematch->e_flags |= flags;
+}
+
+void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags)
+{
+       ematch->e_flags &= ~flags;
+}
+
+uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch)
+{
+       return ematch->e_flags;
+}
+
+void *rtnl_ematch_data(struct rtnl_ematch *ematch)
+{
+       return ematch->e_data;
+}
+
+/** @} */
+
+/**
+ * @name Tree
+ */
+
+/**
+ * Allocate ematch tree object
+ * @arg progid         program id
+ */
+struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid)
+{
+       struct rtnl_ematch_tree *tree;
+
+       if (!(tree = calloc(1, sizeof(*tree))))
+               return NULL;
+       
+       NL_INIT_LIST_HEAD(&tree->et_list);
+       tree->et_progid = progid;
+
+       NL_DBG(2, "allocated new ematch tree %p, progid=%u\n", tree, progid);
+
+       return tree;
+}
+
+static void free_ematch_list(struct nl_list_head *head)
+{
+       struct rtnl_ematch *pos, *next;
+
+       nl_list_for_each_entry_safe(pos, next, head, e_list) {
+               if (!nl_list_empty(&pos->e_childs))
+                       free_ematch_list(&pos->e_childs);
+               rtnl_ematch_free(pos);
+       }
+}
+
+/**
+ * Free ematch tree object
+ * @arg tree           ematch tree object
+ *
+ * This function frees the ematch tree and all ematches attached to it.
+ */
+void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
+{
+       if (!tree)
+               return;
+
+       free_ematch_list(&tree->et_list);
+       free(tree);
+
+       NL_DBG(2, "Freed ematch tree %p\n", tree);
+}
+
+/**
+ * Add ematch object to the end of the ematch tree
+ * @arg tree           ematch tree object
+ * @arg ematch         ematch object to add
+ */
+void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree,
+                         struct rtnl_ematch *ematch)
+{
+       nl_list_add_tail(&ematch->e_list, &tree->et_list);
+}
+
+static inline uint32_t container_ref(struct rtnl_ematch *ematch)
+{
+       return *((uint32_t *) rtnl_ematch_data(ematch));
+}
+
+static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos,
+                    struct nl_list_head *root)
+{
+       struct rtnl_ematch *ematch;
+       int i;
+
+       for (i = pos; i < nmatches; i++) {
+               ematch = index[i];
+
+               nl_list_add_tail(&ematch->e_list, root);
+
+               if (ematch->e_kind == TCF_EM_CONTAINER)
+                       link_tree(index, nmatches, container_ref(ematch),
+                                 &ematch->e_childs);
+
+               if (!(ematch->e_flags & TCF_EM_REL_MASK))
+                       return 0;
+       }
+
+       /* Last entry in chain can't possibly have no relation */
+       return -NLE_INVAL;
+}
+
+static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
+       [TCA_EMATCH_TREE_HDR]  = { .minlen=sizeof(struct tcf_ematch_tree_hdr) },
+       [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED },
+};
+
+/**
+ * Parse ematch netlink attributes
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result)
+{
+       struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
+       struct tcf_ematch_tree_hdr *thdr;
+       struct rtnl_ematch_tree *tree;
+       struct rtnl_ematch **index;
+       int nmatches = 0, err, remaining;
+
+       NL_DBG(2, "Parsing attribute %p as ematch tree\n", attr);
+
+       err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
+       if (err < 0)
+               return err;
+
+       if (!tb[TCA_EMATCH_TREE_HDR])
+               return -NLE_MISSING_ATTR;
+
+       thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);
+
+       /* Ignore empty trees */
+       if (thdr->nmatches == 0) {
+               NL_DBG(2, "Ignoring empty ematch configuration\n");
+               return 0;
+       }
+
+       if (!tb[TCA_EMATCH_TREE_LIST])
+               return -NLE_MISSING_ATTR;
+
+       NL_DBG(2, "ematch tree found with nmatches=%u, progid=%u\n",
+                 thdr->nmatches, thdr->progid);
+
+       /*
+        * Do some basic sanity checking since we will allocate
+        * index[thdr->nmatches]. Calculate how many ematch headers fit into
+        * the provided data and make sure nmatches does not exceed it.
+        */
+       if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
+                             nla_total_size(sizeof(struct tcf_ematch_hdr))))
+               return -NLE_INVAL;
+
+       if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
+               return -NLE_NOMEM;
+
+       if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
+               struct rtnl_ematch_ops *ops;
+               struct tcf_ematch_hdr *hdr;
+               struct rtnl_ematch *ematch;
+               void *data;
+               size_t len;
+
+               NL_DBG(3, "parsing ematch attribute %d, len=%u\n",
+                         nmatches+1, nla_len(a));
+
+               if (nla_len(a) < sizeof(*hdr)) {
+                       err = -NLE_INVAL;
+                       goto errout;
+               }
+
+               /* Quit as soon as we've parsed more matches than expected */
+               if (nmatches >= thdr->nmatches) {
+                       err = -NLE_RANGE;
+                       goto errout;
+               }
+
+               hdr = nla_data(a);
+               data = nla_data(a) + NLA_ALIGN(sizeof(*hdr));
+               len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
+
+               NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n",
+                         hdr->matchid, hdr->kind, hdr->flags);
+
+               /*
+                * Container matches contain a reference to another sequence
+                * of matches. Ensure that the reference is within boundries.
+                */
+               if (hdr->kind == TCF_EM_CONTAINER &&
+                   *((uint32_t *) data) >= thdr->nmatches) {
+                       err = -NLE_INVAL;
+                       goto errout;
+               }
+
+               if (!(ematch = rtnl_ematch_alloc())) {
+                       err = -NLE_NOMEM;
+                       goto errout;
+               }
+
+               ematch->e_id = hdr->matchid;
+               ematch->e_kind = hdr->kind;
+               ematch->e_flags = hdr->flags;
+
+               if ((ops = rtnl_ematch_lookup_ops(hdr->kind))) {
+                       if (ops->eo_minlen && len < ops->eo_minlen) {
+                               rtnl_ematch_free(ematch);
+                               err = -NLE_INVAL;
+                               goto errout;
+                       }
+
+                       rtnl_ematch_set_ops(ematch, ops);
+
+                       if (ops->eo_parse &&
+                           (err = ops->eo_parse(ematch, data, len)) < 0) {
+                               rtnl_ematch_free(ematch);
+                               goto errout;
+                       }
+               }
+
+               NL_DBG(3, "index[%d] = %p\n", nmatches, ematch);
+               index[nmatches++] = ematch;
+       }
+
+       if (nmatches != thdr->nmatches) {
+               err = -NLE_INVAL;
+               goto errout;
+       }
+
+       err = link_tree(index, nmatches, 0, &tree->et_list);
+       if (err < 0)
+               goto errout;
+
+       free(index);
+       *result = tree;
+
+       return 0;
+
+errout:
+       rtnl_ematch_tree_free(tree);
+       free(index);
+       return err;
+}
+
+static void dump_ematch_sequence(struct nl_list_head *head,
+                                struct nl_dump_params *p)
+{
+       struct rtnl_ematch *match;
+
+       nl_list_for_each_entry(match, head, e_list) {
+               if (match->e_flags & TCF_EM_INVERT)
+                       nl_dump(p, "!");
+
+               if (match->e_kind == TCF_EM_CONTAINER) {
+                       nl_dump(p, "(");
+                       dump_ematch_sequence(&match->e_childs, p);
+                       nl_dump(p, ")");
+               } else if (!match->e_ops) {
+                       nl_dump(p, "[unknown ematch %d]", match->e_kind);
+               } else {
+                       if (match->e_ops->eo_dump)
+                               match->e_ops->eo_dump(match, p);
+                       else
+                               nl_dump(p, "[data]");
+               }
+
+               switch (match->e_flags & TCF_EM_REL_MASK) {
+               case TCF_EM_REL_AND:
+                       nl_dump(p, " AND ");
+                       break;
+               case TCF_EM_REL_OR:
+                       nl_dump(p, " OR ");
+                       break;
+               default:
+                       /* end of first level ematch sequence */
+                       return;
+               }
+       }
+}
+
+void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree,
+                          struct nl_dump_params *p)
+{
+       if (!tree)
+               BUG();
+
+       dump_ematch_sequence(&tree->et_list, p);
+       nl_dump(p, "\n");
+}
+
+static int update_container_index(struct nl_list_head *list, int *index)
+{
+       struct rtnl_ematch *e;
+
+       nl_list_for_each_entry(e, list, e_list)
+               e->e_index = (*index)++;
+
+       nl_list_for_each_entry(e, list, e_list) {
+               if (e->e_kind == TCF_EM_CONTAINER) {
+                       int err;
+
+                       if (nl_list_empty(&e->e_childs))
+                               return -NLE_OBJ_NOTFOUND;
+
+                       *((uint32_t *) e->e_data) = *index;
+
+                       err = update_container_index(&e->e_childs, index);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list)
+{
+       struct rtnl_ematch *e;
+
+       nl_list_for_each_entry(e, list, e_list) {
+               struct tcf_ematch_hdr match = {
+                       .matchid = e->e_id,
+                       .kind = e->e_kind,
+                       .flags = e->e_flags,
+               };
+               struct nlattr *attr;
+               int err = 0;
+
+               if (!(attr = nla_nest_start(msg, e->e_index + 1)))
+                       return -NLE_NOMEM;
+
+               if (nlmsg_append(msg, &match, sizeof(match), 0) < 0)
+                       return -NLE_NOMEM;
+
+               if (e->e_ops->eo_fill)
+                       err = e->e_ops->eo_fill(e, msg);
+               else if (e->e_flags & TCF_EM_SIMPLE)
+                       err = nlmsg_append(msg, e->e_data, 4, 0);
+               else if (e->e_datalen > 0)
+                       err = nlmsg_append(msg, e->e_data, e->e_datalen, 0);
+
+               NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n",
+                         msg, e->e_index, match.matchid, match.kind, match.flags);
+
+               if (err < 0)
+                       return -NLE_NOMEM;
+
+               nla_nest_end(msg, attr);
+       }
+
+       nl_list_for_each_entry(e, list, e_list) {
+               if (e->e_kind == TCF_EM_CONTAINER &&
+                   fill_ematch_sequence(msg, &e->e_childs) < 0)
+                       return -NLE_NOMEM;
+       }
+
+       return 0;
+}
+
+int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid,
+                         struct rtnl_ematch_tree *tree)
+{
+       struct tcf_ematch_tree_hdr thdr = {
+               .progid = tree->et_progid,
+       };
+       struct nlattr *list, *topattr;
+       int err, index = 0;
+
+       /* Assign index number to each ematch to allow for references
+        * to be made while constructing the sequence of matches. */
+       err = update_container_index(&tree->et_list, &index);
+       if (err < 0)
+               return err;
+
+       if (!(topattr = nla_nest_start(msg, attrid)))
+               goto nla_put_failure;
+
+       thdr.nmatches = index;
+       NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr);
+
+       if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST)))
+               goto nla_put_failure;
+
+       if (fill_ematch_sequence(msg, &tree->et_list) < 0)
+               goto nla_put_failure;
+
+       nla_nest_end(msg, list);
+
+       nla_nest_end(msg, topattr);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_NOMEM;
+}
+
+/** @} */
+
+extern int ematch_parse(void *, char **, struct nl_list_head *);
+
+int rtnl_ematch_parse_expr(const char *expr, char **errp,
+                          struct rtnl_ematch_tree **result)
+{
+       struct rtnl_ematch_tree *tree;
+       YY_BUFFER_STATE buf = NULL;
+       yyscan_t scanner = NULL;
+       int err;
+
+       NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr);
+
+       if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID)))
+               return -NLE_FAILURE;
+
+       if ((err = ematch_lex_init(&scanner)) < 0) {
+               err = -NLE_FAILURE;
+               goto errout;
+       }
+
+       buf = ematch__scan_string(expr, scanner);
+
+       if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) {
+               ematch__delete_buffer(buf, scanner);
+               err = -NLE_PARSE_ERR;
+               goto errout;
+       }
+
+       if (scanner)
+               ematch_lex_destroy(scanner);
+
+       *result = tree;
+
+       return 0;
+
+errout:
+       if (scanner)
+               ematch_lex_destroy(scanner);
+
+       rtnl_ematch_tree_free(tree);
+
+       return err;
+}
+
+static const char *layer_txt[] = {
+       [TCF_LAYER_LINK]        = "eth",
+       [TCF_LAYER_NETWORK]     = "ip",
+       [TCF_LAYER_TRANSPORT]   = "tcp",
+};
+
+char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len)
+{
+       snprintf(buf, len, "%s+%u",
+                (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?",
+                offset);
+
+       return buf;
+}
+
+static const char *operand_txt[] = {
+       [TCF_EM_OPND_EQ] = "=",
+       [TCF_EM_OPND_LT] = "<",
+       [TCF_EM_OPND_GT] = ">",
+};
+
+char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len)
+{
+       snprintf(buf, len, "%s",
+               opnd <= ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?");
+
+       return buf;
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch/cmp.c b/lib/route/cls/ematch/cmp.c
new file mode 100644 (file)
index 0000000..2997cdb
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * lib/route/cls/ematch/cmp.c  Simple packet data comparison ematch
+ *
+ *     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-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_cmp Simple packet data comparison
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
+
+void rtnl_ematch_cmp_set(struct rtnl_ematch *e, struct tcf_em_cmp *cfg)
+{
+       memcpy(rtnl_ematch_data(e), cfg, sizeof(*cfg));
+}
+
+struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *e)
+{
+       return rtnl_ematch_data(e);
+}
+
+static int cmp_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+       memcpy(rtnl_ematch_data(e), data, len);
+
+       return 0;
+}
+
+static const char *align_txt[] = {
+       [TCF_EM_ALIGN_U8] = "u8",
+       [TCF_EM_ALIGN_U16] = "u16",
+       [TCF_EM_ALIGN_U32] = "u32"
+};
+
+static const char *layer_txt[] = {
+       [TCF_LAYER_LINK] = "eth",
+       [TCF_LAYER_NETWORK] = "ip",
+       [TCF_LAYER_TRANSPORT] = "tcp"
+};
+
+static const char *operand_txt[] = {
+       [TCF_EM_OPND_EQ] = "=",
+       [TCF_EM_OPND_LT] = "<",
+       [TCF_EM_OPND_GT] = ">",
+};
+
+static void cmp_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+       struct tcf_em_cmp *cmp = rtnl_ematch_data(e);
+
+       if (cmp->flags & TCF_EM_CMP_TRANS)
+               nl_dump(p, "ntoh%c(", (cmp->align == TCF_EM_ALIGN_U32) ? 'l' : 's');
+
+       nl_dump(p, "%s at %s+%u",
+               align_txt[cmp->align], layer_txt[cmp->layer], cmp->off);
+
+       if (cmp->mask)
+               nl_dump(p, " & 0x%x", cmp->mask);
+
+       if (cmp->flags & TCF_EM_CMP_TRANS)
+               nl_dump(p, ")");
+
+       nl_dump(p, " %s %u", operand_txt[cmp->opnd], cmp->val);
+}
+
+static struct rtnl_ematch_ops cmp_ops = {
+       .eo_kind        = TCF_EM_CMP,
+       .eo_name        = "cmp",
+       .eo_minlen      = sizeof(struct tcf_em_cmp),
+       .eo_datalen     = sizeof(struct tcf_em_cmp),
+       .eo_parse       = cmp_parse,
+       .eo_dump        = cmp_dump,
+};
+
+static void __init cmp_init(void)
+{
+       rtnl_ematch_register(&cmp_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch/container.c b/lib/route/cls/ematch/container.c
new file mode 100644 (file)
index 0000000..813391a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * lib/route/cls/ematch/container.c    Container Ematch
+ *
+ *     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-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+
+static int container_parse(struct rtnl_ematch *e, void *data, size_t len __attribute__((unused)))
+{
+       /*
+       The kernel may provide more than 4 bytes of data in the future and we want
+       older libnl versions to be ok with that. We want interfaces to be growable
+       so we only ever enforce a minimum data length and copy as much as we are
+       aware of. Thomas Graf.
+       */
+       memcpy(e->e_data, data, sizeof(uint32_t));
+
+       return 0;
+}
+
+static int container_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+       return nlmsg_append(msg, e->e_data, sizeof(uint32_t), 0);
+}
+
+static struct rtnl_ematch_ops container_ops = {
+       .eo_kind        = TCF_EM_CONTAINER,
+       .eo_name        = "container",
+       .eo_minlen      = sizeof(uint32_t),
+       .eo_datalen     = sizeof(uint32_t),
+       .eo_parse       = container_parse,
+       .eo_fill        = container_fill,
+};
+
+static void __init container_init(void)
+{
+       rtnl_ematch_register(&container_ops);
+}
diff --git a/lib/route/cls/ematch/meta.c b/lib/route/cls/ematch/meta.c
new file mode 100644 (file)
index 0000000..44f11b9
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * lib/route/cls/ematch/meta.c         Metadata Match
+ *
+ *     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) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_meta Metadata Match
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/meta.h>
+
+struct rtnl_meta_value
+{
+       uint8_t                 mv_type;
+       uint8_t                 mv_shift;
+       uint16_t                mv_id;
+       size_t                  mv_len;
+};
+
+struct meta_data
+{
+       struct rtnl_meta_value *        left;
+       struct rtnl_meta_value *        right;
+       uint8_t                         opnd;
+};
+
+static struct rtnl_meta_value *meta_alloc(uint8_t type, uint16_t id,
+                                         uint8_t shift, void *data,
+                                         size_t len)
+{
+       struct rtnl_meta_value *value;
+
+       if (!(value = calloc(1, sizeof(*value) + len)))
+               return NULL;
+
+       value->mv_type = type;
+       value->mv_id = id;
+       value->mv_shift = shift;
+       value->mv_len = len;
+
+       memcpy(value + 1, data, len);
+
+       return value;
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_int(uint64_t value)
+{
+       return meta_alloc(TCF_META_TYPE_INT, TCF_META_ID_VALUE, 0, &value, 8);
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_var(void *data, size_t len)
+{
+       return meta_alloc(TCF_META_TYPE_VAR, TCF_META_ID_VALUE, 0, data, len);
+}
+
+struct rtnl_meta_value *rtnl_meta_value_alloc_id(uint8_t type, uint16_t id,
+                                                uint8_t shift, uint64_t mask)
+{
+       size_t masklen = 0;
+
+       if (id > TCF_META_ID_MAX)
+               return NULL;
+
+       if (mask) {
+               if (type == TCF_META_TYPE_VAR)
+                       return NULL;
+
+               masklen = 8;
+       }
+
+       return meta_alloc(type, id, shift, &mask, masklen);
+}
+
+void rtnl_meta_value_put(struct rtnl_meta_value *mv)
+{
+       free(mv);
+}
+
+void rtnl_ematch_meta_set_lvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
+{
+       struct meta_data *m = rtnl_ematch_data(e);
+       m->left = v;
+}
+
+void rtnl_ematch_meta_set_rvalue(struct rtnl_ematch *e, struct rtnl_meta_value *v)
+{
+       struct meta_data *m = rtnl_ematch_data(e);
+       m->right = v;
+}
+
+void rtnl_ematch_meta_set_operand(struct rtnl_ematch *e, uint8_t opnd)
+{
+       struct meta_data *m = rtnl_ematch_data(e);
+       m->opnd = opnd;
+}
+
+static struct nla_policy meta_policy[TCA_EM_META_MAX+1] = {
+       [TCA_EM_META_HDR]       = { .minlen = sizeof(struct tcf_meta_hdr) },
+       [TCA_EM_META_LVALUE]    = { .minlen = 1, },
+       [TCA_EM_META_RVALUE]    = { .minlen = 1, },
+};
+
+static int meta_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+       struct meta_data *m = rtnl_ematch_data(e);
+       struct nlattr *tb[TCA_EM_META_MAX+1];
+       struct rtnl_meta_value *v;
+       struct tcf_meta_hdr *hdr;
+       void *vdata = NULL;
+       size_t vlen = 0;
+       int err;
+
+       if ((err = nla_parse(tb, TCA_EM_META_MAX, data, len, meta_policy)) < 0)
+               return err;
+
+       if (!tb[TCA_EM_META_HDR])
+               return -NLE_MISSING_ATTR;
+
+       hdr = nla_data(tb[TCA_EM_META_HDR]);
+
+       if (tb[TCA_EM_META_LVALUE]) {
+               vdata = nla_data(tb[TCA_EM_META_LVALUE]);
+               vlen = nla_len(tb[TCA_EM_META_LVALUE]);
+       }
+
+       v = meta_alloc(TCF_META_TYPE(hdr->left.kind),
+                      TCF_META_ID(hdr->left.kind),
+                      hdr->left.shift, vdata, vlen);
+       if (!v)
+               return -NLE_NOMEM;
+
+       m->left = v;
+
+       vlen = 0;
+       if (tb[TCA_EM_META_RVALUE]) {
+               vdata = nla_data(tb[TCA_EM_META_RVALUE]);
+               vlen = nla_len(tb[TCA_EM_META_RVALUE]);
+       }
+
+       v = meta_alloc(TCF_META_TYPE(hdr->right.kind),
+                      TCF_META_ID(hdr->right.kind),
+                      hdr->right.shift, vdata, vlen);
+       if (!v) {
+               rtnl_meta_value_put(m->left);
+               return -NLE_NOMEM;
+       }
+
+       m->right = v;
+       m->opnd = hdr->left.op;
+
+       return 0;
+}
+
+static const struct trans_tbl meta_int[] = {
+       __ADD(TCF_META_ID_RANDOM, random)
+       __ADD(TCF_META_ID_LOADAVG_0, loadavg_0)
+       __ADD(TCF_META_ID_LOADAVG_1, loadavg_1)
+       __ADD(TCF_META_ID_LOADAVG_2, loadavg_2)
+       __ADD(TCF_META_ID_DEV, dev)
+       __ADD(TCF_META_ID_PRIORITY, prio)
+       __ADD(TCF_META_ID_PROTOCOL, proto)
+       __ADD(TCF_META_ID_PKTTYPE, pkttype)
+       __ADD(TCF_META_ID_PKTLEN, pktlen)
+       __ADD(TCF_META_ID_DATALEN, datalen)
+       __ADD(TCF_META_ID_MACLEN, maclen)
+       __ADD(TCF_META_ID_NFMARK, mark)
+       __ADD(TCF_META_ID_TCINDEX, tcindex)
+       __ADD(TCF_META_ID_RTCLASSID, rtclassid)
+       __ADD(TCF_META_ID_RTIIF, rtiif)
+       __ADD(TCF_META_ID_SK_FAMILY, sk_family)
+       __ADD(TCF_META_ID_SK_STATE, sk_state)
+       __ADD(TCF_META_ID_SK_REUSE, sk_reuse)
+       __ADD(TCF_META_ID_SK_REFCNT, sk_refcnt)
+       __ADD(TCF_META_ID_SK_RCVBUF, sk_rcvbuf)
+       __ADD(TCF_META_ID_SK_SNDBUF, sk_sndbuf)
+       __ADD(TCF_META_ID_SK_SHUTDOWN, sk_sutdown)
+       __ADD(TCF_META_ID_SK_PROTO, sk_proto)
+       __ADD(TCF_META_ID_SK_TYPE, sk_type)
+       __ADD(TCF_META_ID_SK_RMEM_ALLOC, sk_rmem_alloc)
+       __ADD(TCF_META_ID_SK_WMEM_ALLOC, sk_wmem_alloc)
+       __ADD(TCF_META_ID_SK_WMEM_QUEUED, sk_wmem_queued)
+       __ADD(TCF_META_ID_SK_RCV_QLEN, sk_rcv_qlen)
+       __ADD(TCF_META_ID_SK_SND_QLEN, sk_snd_qlen)
+       __ADD(TCF_META_ID_SK_ERR_QLEN, sk_err_qlen)
+       __ADD(TCF_META_ID_SK_FORWARD_ALLOCS, sk_forward_allocs)
+       __ADD(TCF_META_ID_SK_ALLOCS, sk_allocs)
+       __ADD(TCF_META_ID_SK_ROUTE_CAPS, sk_route_caps)
+       __ADD(TCF_META_ID_SK_HASH, sk_hash)
+       __ADD(TCF_META_ID_SK_LINGERTIME, sk_lingertime)
+       __ADD(TCF_META_ID_SK_ACK_BACKLOG, sk_ack_backlog)
+       __ADD(TCF_META_ID_SK_MAX_ACK_BACKLOG, sk_max_ack_backlog)
+       __ADD(TCF_META_ID_SK_PRIO, sk_prio)
+       __ADD(TCF_META_ID_SK_RCVLOWAT, sk_rcvlowat)
+       __ADD(TCF_META_ID_SK_RCVTIMEO, sk_rcvtimeo)
+       __ADD(TCF_META_ID_SK_SNDTIMEO, sk_sndtimeo)
+       __ADD(TCF_META_ID_SK_SENDMSG_OFF, sk_sendmsg_off)
+       __ADD(TCF_META_ID_SK_WRITE_PENDING, sk_write_pending)
+       __ADD(TCF_META_ID_VLAN_TAG, vlan)
+       __ADD(TCF_META_ID_RXHASH, rxhash)
+};
+
+static char *int_id2str(int id, char *buf, size_t size)
+{
+       return __type2str(id, buf, size, meta_int, ARRAY_SIZE(meta_int));
+}
+
+static const struct trans_tbl meta_var[] = {
+       __ADD(TCF_META_ID_DEV,devname)
+       __ADD(TCF_META_ID_SK_BOUND_IF,sk_bound_if)
+};
+
+static char *var_id2str(int id, char *buf, size_t size)
+{
+       return __type2str(id, buf, size, meta_var, ARRAY_SIZE(meta_var));
+}
+
+static void dump_value(struct rtnl_meta_value *v, struct nl_dump_params *p)
+{
+       char buf[32];
+
+       switch (v->mv_type) {
+               case TCF_META_TYPE_INT:
+                       if (v->mv_id == TCF_META_ID_VALUE) {
+                               nl_dump(p, "%u",
+                                       *(uint32_t *) (v + 1));
+                       } else {
+                               nl_dump(p, "%s",
+                                       int_id2str(v->mv_id, buf, sizeof(buf)));
+
+                               if (v->mv_shift)
+                                       nl_dump(p, " >> %u", v->mv_shift);
+
+                               if (v->mv_len == 4)
+                                       nl_dump(p, " & %#x", *(uint32_t *) (v + 1));
+                               else if (v->mv_len == 8)
+                                       nl_dump(p, " & %#x", *(uint64_t *) (v + 1));
+                       }
+               break;
+
+               case TCF_META_TYPE_VAR:
+                       if (v->mv_id == TCF_META_ID_VALUE) {
+                               nl_dump(p, "%s", (char *) (v + 1));
+                       } else {
+                               nl_dump(p, "%s",
+                                       var_id2str(v->mv_id, buf, sizeof(buf)));
+
+                               if (v->mv_shift)
+                                       nl_dump(p, " >> %u", v->mv_shift);
+                       }
+               break;
+       }
+}
+
+static void meta_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+       struct meta_data *m = rtnl_ematch_data(e);
+       char buf[32];
+
+       nl_dump(p, "meta(");
+       dump_value(m->left, p);
+
+       nl_dump(p, " %s ", rtnl_ematch_opnd2txt(m->opnd, buf, sizeof(buf)));
+
+       dump_value(m->right, p);
+       nl_dump(p, ")");
+}
+
+static int meta_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+       struct meta_data *m = rtnl_ematch_data(e);
+       struct tcf_meta_hdr hdr;
+
+       if (!(m->left && m->right))
+               return -NLE_MISSING_ATTR;
+
+       memset(&hdr, 0, sizeof(hdr));
+       hdr.left.kind = (m->left->mv_type << 12) & TCF_META_TYPE_MASK;
+       hdr.left.kind |= m->left->mv_id & TCF_META_ID_MASK;
+       hdr.left.shift = m->left->mv_shift;
+       hdr.left.op = m->opnd;
+       hdr.right.kind = (m->right->mv_type << 12) & TCF_META_TYPE_MASK;
+       hdr.right.kind |= m->right->mv_id & TCF_META_ID_MASK;
+
+       NLA_PUT(msg, TCA_EM_META_HDR, sizeof(hdr), &hdr);
+
+       if (m->left->mv_len)
+               NLA_PUT(msg, TCA_EM_META_LVALUE, m->left->mv_len, (m->left + 1));
+       
+       if (m->right->mv_len)
+               NLA_PUT(msg, TCA_EM_META_RVALUE, m->right->mv_len, (m->right + 1));
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_NOMEM;
+}
+
+static void meta_free(struct rtnl_ematch *e)
+{
+       struct meta_data *m = rtnl_ematch_data(e);
+       free(m->left);
+       free(m->right);
+}
+
+static struct rtnl_ematch_ops meta_ops = {
+       .eo_kind        = TCF_EM_META,
+       .eo_name        = "meta",
+       .eo_minlen      = sizeof(struct tcf_meta_hdr),
+       .eo_datalen     = sizeof(struct meta_data),
+       .eo_parse       = meta_parse,
+       .eo_dump        = meta_dump,
+       .eo_fill        = meta_fill,
+       .eo_free        = meta_free,
+};
+
+static void __init meta_init(void)
+{
+       rtnl_ematch_register(&meta_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch/nbyte.c b/lib/route/cls/ematch/nbyte.c
new file mode 100644 (file)
index 0000000..8852489
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * lib/route/cls/ematch/nbyte.c                Nbyte comparison
+ *
+ *     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) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_nbyte N-Byte Comparison
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/nbyte.h>
+
+struct nbyte_data
+{
+       struct tcf_em_nbyte     cfg;
+       uint8_t *               pattern;
+};
+
+void rtnl_ematch_nbyte_set_offset(struct rtnl_ematch *e, uint8_t layer,
+                                 uint16_t offset)
+{
+       struct nbyte_data *n = rtnl_ematch_data(e);
+       n->cfg.off = offset;
+       n->cfg.layer = layer;
+}
+
+uint16_t rtnl_ematch_nbyte_get_offset(struct rtnl_ematch *e)
+{
+       return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.off;
+}
+
+uint8_t rtnl_ematch_nbyte_get_layer(struct rtnl_ematch *e)
+{
+       return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.layer;
+}
+
+void rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch *e,
+                                  uint8_t *pattern, size_t len)
+{
+       struct nbyte_data *n = rtnl_ematch_data(e);
+
+       if (n->pattern)
+               free(n->pattern);
+
+       n->pattern = pattern;
+       n->cfg.len = len;
+}
+
+uint8_t *rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch *e)
+{
+       return ((struct nbyte_data *) rtnl_ematch_data(e))->pattern;
+}
+
+size_t rtnl_ematch_nbyte_get_len(struct rtnl_ematch *e)
+{
+       return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.len;
+}
+
+static const char *layer_txt(struct tcf_em_nbyte *nbyte)
+{
+       switch (nbyte->layer) {
+       case TCF_LAYER_LINK:
+               return "link";
+       case TCF_LAYER_NETWORK:
+               return "net";
+       case TCF_LAYER_TRANSPORT:
+               return "trans";
+       default:
+               return "?";
+       }
+}
+
+static int nbyte_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+       struct nbyte_data *n = rtnl_ematch_data(e);
+       size_t hdrlen = sizeof(struct tcf_em_nbyte);
+       size_t plen = len - hdrlen;
+
+       memcpy(&n->cfg, data, hdrlen);
+       if (plen > 0) {
+               if (!(n->pattern = calloc(1, plen)))
+                       return -NLE_NOMEM;
+
+               memcpy(n->pattern, data + hdrlen, plen);
+       }
+
+       return 0;
+}
+
+static void nbyte_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+       struct nbyte_data *n = rtnl_ematch_data(e);
+       int i;
+
+       nl_dump(p, "pattern(%u:[", n->cfg.len);
+
+       for (i = 0; i < n->cfg.len; i++) {
+               nl_dump(p, "%02x", n->pattern[i]);
+               if (i+1 < n->cfg.len)
+                       nl_dump(p, " ");
+       }
+
+       nl_dump(p, "] at %s+%u)", layer_txt(&n->cfg), n->cfg.off);
+}
+
+static void nbyte_free(struct rtnl_ematch *e)
+{
+       struct nbyte_data *n = rtnl_ematch_data(e);
+       free(n->pattern);
+}
+
+static struct rtnl_ematch_ops nbyte_ops = {
+       .eo_kind        = TCF_EM_NBYTE,
+       .eo_name        = "nbyte",
+       .eo_minlen      = sizeof(struct tcf_em_nbyte),
+       .eo_datalen     = sizeof(struct nbyte_data),
+       .eo_parse       = nbyte_parse,
+       .eo_dump        = nbyte_dump,
+       .eo_free        = nbyte_free,
+};
+
+static void __init nbyte_init(void)
+{
+       rtnl_ematch_register(&nbyte_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch/text.c b/lib/route/cls/ematch/text.c
new file mode 100644 (file)
index 0000000..e8cdcae
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * lib/route/cls/ematch/text.c         Text Search
+ *
+ *     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) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup ematch
+ * @defgroup em_text Text Search
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/text.h>
+
+struct text_data
+{
+       struct tcf_em_text      cfg;
+       char *                  pattern;
+};
+
+void rtnl_ematch_text_set_from(struct rtnl_ematch *e, uint8_t layer,
+                              uint16_t offset)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       t->cfg.from_offset = offset;
+       t->cfg.from_layer = layer;
+}
+
+uint16_t rtnl_ematch_text_get_from_offset(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_offset;
+}
+
+uint8_t rtnl_ematch_text_get_from_layer(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.from_layer;
+}
+
+void rtnl_ematch_text_set_to(struct rtnl_ematch *e, uint8_t layer,
+                              uint16_t offset)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       t->cfg.to_offset = offset;
+       t->cfg.to_layer = layer;
+}
+
+uint16_t rtnl_ematch_text_get_to_offset(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_offset;
+}
+
+uint8_t rtnl_ematch_text_get_to_layer(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.to_layer;
+}
+
+void rtnl_ematch_text_set_pattern(struct rtnl_ematch *e,
+                                 char *pattern, size_t len)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+
+       if (t->pattern)
+               free(t->pattern);
+
+       t->pattern = pattern;
+       t->cfg.pattern_len = len;
+}
+
+char *rtnl_ematch_text_get_pattern(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->pattern;
+}
+
+size_t rtnl_ematch_text_get_len(struct rtnl_ematch *e)
+{
+       return ((struct text_data *) rtnl_ematch_data(e))->cfg.pattern_len;
+}
+
+void rtnl_ematch_text_set_algo(struct rtnl_ematch *e, const char *algo)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+
+       strncpy(t->cfg.algo, algo, sizeof(t->cfg.algo));
+}
+
+char *rtnl_ematch_text_get_algo(struct rtnl_ematch *e)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+
+       return t->cfg.algo[0] ? t->cfg.algo : NULL;
+}
+
+static int text_parse(struct rtnl_ematch *e, void *data, size_t len)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       size_t hdrlen = sizeof(struct tcf_em_text);
+       size_t plen = len - hdrlen;
+
+       memcpy(&t->cfg, data, hdrlen);
+
+       if (t->cfg.pattern_len > plen)
+               return -NLE_INVAL;
+
+       if (t->cfg.pattern_len > 0) {
+               if (!(t->pattern = calloc(1, t->cfg.pattern_len)))
+                       return -NLE_NOMEM;
+
+               memcpy(t->pattern, data + hdrlen, t->cfg.pattern_len);
+       }
+
+       return 0;
+}
+
+static void text_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       char buf[64];
+
+       nl_dump(p, "text(%s \"%s\"",
+               t->cfg.algo[0] ? t->cfg.algo : "no-algo",
+               t->pattern ? : "no-pattern");
+
+       if (t->cfg.from_layer || t->cfg.from_offset) {
+               nl_dump(p, " from %s",
+                       rtnl_ematch_offset2txt(t->cfg.from_layer,
+                                              t->cfg.from_offset,
+                                              buf, sizeof(buf)));
+       }
+
+       if (t->cfg.to_layer || t->cfg.to_offset) {
+               nl_dump(p, " to %s",
+                       rtnl_ematch_offset2txt(t->cfg.to_layer,
+                                              t->cfg.to_offset,
+                                              buf, sizeof(buf)));
+       }
+
+       nl_dump(p, ")");
+}
+
+static int text_fill(struct rtnl_ematch *e, struct nl_msg *msg)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       int err;
+
+       if ((err = nlmsg_append(msg, &t->cfg, sizeof(t->cfg), 0)) < 0)
+               return err;
+
+       return nlmsg_append(msg, t->pattern, t->cfg.pattern_len, 0);
+}
+
+static void text_free(struct rtnl_ematch *e)
+{
+       struct text_data *t = rtnl_ematch_data(e);
+       free(t->pattern);
+}
+
+static struct rtnl_ematch_ops text_ops = {
+       .eo_kind        = TCF_EM_TEXT,
+       .eo_name        = "text",
+       .eo_minlen      = sizeof(struct tcf_em_text),
+       .eo_datalen     = sizeof(struct text_data),
+       .eo_parse       = text_parse,
+       .eo_dump        = text_dump,
+       .eo_fill        = text_fill,
+       .eo_free        = text_free,
+};
+
+static void __init text_init(void)
+{
+       rtnl_ematch_register(&text_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/ematch_grammar.l b/lib/route/cls/ematch_grammar.l
new file mode 100644 (file)
index 0000000..96ef1a0
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * lib/route/cls/ematch_grammar.l      ematch expression grammar
+ *
+ *     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) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+%{
+ #include <netlink-private/netlink.h>
+ #include <netlink-private/tc.h>
+ #include <netlink/netlink.h>
+ #include <netlink/route/cls/ematch.h>
+ #include <netlink/route/cls/ematch/cmp.h>
+ #include "ematch_syntax.h"
+%}
+
+%option 8bit
+%option reentrant
+%option warn
+%option noyywrap
+%option noinput
+%option nounput
+%option bison-bridge
+%option prefix="ematch_"
+
+%x QUOTE
+
+%%
+
+[ \t\r\n]+
+
+\"                     {
+                               NL_DBG(4, "Beginning of quote\n");
+                               yylval->q.len = 32;
+                               if (!(yylval->q.data = calloc(1, yylval->q.len)))
+                                       return ERROR;
+
+                               yylval->q.index = 0;
+                               BEGIN(QUOTE);
+                       }
+
+<QUOTE>[^\\\n\"]+      {
+                               memcpy(yylval->q.data + yylval->q.index, yytext,
+                                      strlen(yytext));
+                               yylval->q.index += strlen(yytext);
+                       }
+
+<QUOTE>\"              {
+                               BEGIN(0);
+                               return QUOTED;
+                       }
+
+
+[[:digit:]]+           |
+0[xX][[:xdigit:]]+     {
+                               yylval->i = strtoul(yytext, NULL, 0);
+                               return NUMBER;
+                       }
+
+eq                     |
+"="                    return KW_EQ;
+gt                     |
+">"                    return KW_GT;
+lt                     |
+"<"                    return KW_LT;
+
+[aA][nN][dD]           |
+"&&"                   { yylval->i = TCF_EM_REL_AND; return LOGIC; }
+[oO][rR]               |
+"||"                   { yylval->i = TCF_EM_REL_OR; return LOGIC; }
+[nN][oO][tT]           |
+"!"                    return NOT;
+
+[cC][mM][pP]           { yylval->i = TCF_EM_CMP; return EMATCH_CMP; }
+[pP][aA][tT][tT][eE][rR][nN] { yylval->i = TCF_EM_NBYTE; return EMATCH_NBYTE; }
+[tT][eE][xX][tT]       { yylval->i = TCF_EM_TEXT; return EMATCH_TEXT; }
+[mM][eE][tT][aA]       { yylval->i = TCF_EM_META; return EMATCH_META; }
+
+"("                    return KW_OPEN;
+")"                    return KW_CLOSE;
+[mM][aA][sS][kK]       |
+"&"                    return KW_MASK;
+[sS][hH][iI][fF][tT]   |
+">>"                   return KW_SHIFT;
+[aA][tT]               return KW_AT;
+"+"                    return KW_PLUS;
+[fF][rR][oO][mM]       return KW_FROM;
+[tT][oO]               return KW_TO;
+
+[uU]8                  { yylval->i = TCF_EM_ALIGN_U8; return ALIGN; }
+[uU]16                 { yylval->i = TCF_EM_ALIGN_U16; return ALIGN; }
+[uU]32                 { yylval->i = TCF_EM_ALIGN_U32; return ALIGN; }
+
+[lL][iI][nN][kK]       |
+[eE][tT][hH]           { yylval->i = TCF_LAYER_LINK; return LAYER; }
+[nN][eE][tT]           |
+[iI][pP]6              |
+[iI][pP]               { yylval->i = TCF_LAYER_NETWORK; return LAYER; }
+[tT][rR][aA][nN][sS][pP][oO][rR][tT] |
+[tT][cC][pP]           { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; }
+
+random                 return META_RANDOM;
+loadavg_0              return META_LOADAVG_0;
+loadavg_1              return META_LOADAVG_1;
+loadavg_2              return META_LOADAVG_2;
+dev                    return META_DEV;
+prio                   return META_PRIO;
+proto                  return META_PROTO;
+pkttype                        return META_PKTTYPE;
+pktlen                 return META_PKTLEN;
+datalen                        return META_DATALEN;
+maclen                 return META_MACLEN;
+mark                   return META_MARK;
+tcindex                        return META_TCINDEX;
+rtclassid              return META_RTCLASSID;
+rtiif                  return META_RTIIF;
+sk_family              return META_SK_FAMILY;
+sk_state               return META_SK_STATE;
+sk_reuse               return META_SK_REUSE;
+sk_refcnt              return META_SK_REFCNT;
+sk_rcvbuf              return META_SK_RCVBUF;
+sk_sndbuf              return META_SK_SNDBUF;
+sk_shutdown            return META_SK_SHUTDOWN;
+sk_proto               return META_SK_PROTO;
+sk_type                        return META_SK_TYPE;
+sk_rmem_alloc          return META_SK_RMEM_ALLOC;
+sk_wmem_alloc          return META_SK_WMEM_ALLOC;
+sk_wmem_queued         return META_SK_WMEM_QUEUED;
+sk_rcv_qlen            return META_SK_RCV_QLEN;
+sk_snd_qlen            return META_SK_SND_QLEN;
+sk_err_qlen            return META_SK_ERR_QLEN;
+sk_forward_allocs      return META_SK_FORWARD_ALLOCS;
+sk_allocs              return META_SK_ALLOCS;
+sk_route_caps          return META_SK_ROUTE_CAPS;
+sk_hash                        return META_SK_HASH;
+sk_lingertime          return META_SK_LINGERTIME;
+sk_ack_backlog         return META_SK_ACK_BACKLOG;
+sk_max_ack_backlog     return META_SK_MAX_ACK_BACKLOG;
+sk_prio                        return META_SK_PRIO;
+sk_rcvlowat            return META_SK_RCVLOWAT;
+sk_rcvtimeo            return META_SK_RCVTIMEO;
+sk_sndtimeo            return META_SK_SNDTIMEO;
+sk_sendmsg_off         return META_SK_SENDMSG_OFF;
+sk_write_pending       return META_SK_WRITE_PENDING;
+vlan                   return META_VLAN;
+rxhash                 return META_RXHASH;
+
+devname                        return META_DEVNAME;
+sk_bound_if            return META_SK_BOUND_IF;
+
+
+[^ \t\r\n+()=<>&|\"]+  {
+                               yylval->s = strdup(yytext);
+                               if (yylval->s == NULL)
+                                       return ERROR;
+                               NL_DBG(4, "lex STR=%s\n", yylval->s);
+                               return STR;
+                       }
diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y
new file mode 100644 (file)
index 0000000..da21039
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * lib/route/cls/ematch_syntax.y       ematch expression syntax
+ *
+ *     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) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+%{
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/cmp.h>
+#include <netlink/route/cls/ematch/nbyte.h>
+#include <netlink/route/cls/ematch/text.h>
+#include <netlink/route/cls/ematch/meta.h>
+
+#define META_ALLOC rtnl_meta_value_alloc_id
+#define META_ID(name) TCF_META_ID_##name
+#define META_INT TCF_META_TYPE_INT
+#define META_VAR TCF_META_TYPE_VAR
+%}
+
+%error-verbose
+%define api.pure
+%name-prefix "ematch_"
+
+%parse-param {void *scanner}
+%parse-param {char **errp}
+%parse-param {struct nl_list_head *root}
+%lex-param {void *scanner}
+
+%union {
+       struct tcf_em_cmp       cmp;
+       struct ematch_quoted    q;
+       struct rtnl_ematch *    e;
+       struct rtnl_pktloc *    loc;
+       struct rtnl_meta_value *mv;
+       uint32_t                i;
+       uint64_t                i64;
+       char *                  s;
+}
+
+%{
+extern int ematch_lex(YYSTYPE *, void *);
+
+static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const char *msg)
+{
+       if (msg)
+            *errp = strdup(msg);
+        else
+           *errp = NULL;
+}
+%}
+
+%token <i> ERROR LOGIC NOT OPERAND NUMBER ALIGN LAYER
+%token <i> KW_OPEN "("
+%token <i> KW_CLOSE ")"
+%token <i> KW_PLUS "+"
+%token <i> KW_MASK "mask"
+%token <i> KW_SHIFT ">>"
+%token <i> KW_AT "at"
+%token <i> EMATCH_CMP "cmp"
+%token <i> EMATCH_NBYTE "pattern"
+%token <i> EMATCH_TEXT "text"
+%token <i> EMATCH_META "meta"
+%token <i> KW_EQ "="
+%token <i> KW_GT ">"
+%token <i> KW_LT "<"
+%token <i> KW_FROM "from"
+%token <i> KW_TO "to"
+
+%token <i> META_RANDOM "random"
+%token <i> META_LOADAVG_0 "loadavg_0"
+%token <i> META_LOADAVG_1 "loadavg_1"
+%token <i> META_LOADAVG_2 "loadavg_2"
+%token <i> META_DEV "dev"
+%token <i> META_PRIO "prio"
+%token <i> META_PROTO "proto"
+%token <i> META_PKTTYPE "pkttype"
+%token <i> META_PKTLEN "pktlen"
+%token <i> META_DATALEN "datalen"
+%token <i> META_MACLEN "maclen"
+%token <i> META_MARK "mark"
+%token <i> META_TCINDEX "tcindex"
+%token <i> META_RTCLASSID "rtclassid"
+%token <i> META_RTIIF "rtiif"
+%token <i> META_SK_FAMILY "sk_family"
+%token <i> META_SK_STATE "sk_state"
+%token <i> META_SK_REUSE "sk_reuse"
+%token <i> META_SK_REFCNT "sk_refcnt"
+%token <i> META_SK_RCVBUF "sk_rcvbuf"
+%token <i> META_SK_SNDBUF "sk_sndbuf"
+%token <i> META_SK_SHUTDOWN "sk_shutdown"
+%token <i> META_SK_PROTO "sk_proto"
+%token <i> META_SK_TYPE "sk_type"
+%token <i> META_SK_RMEM_ALLOC "sk_rmem_alloc"
+%token <i> META_SK_WMEM_ALLOC "sk_wmem_alloc"
+%token <i> META_SK_WMEM_QUEUED "sk_wmem_queued"
+%token <i> META_SK_RCV_QLEN "sk_rcv_qlen"
+%token <i> META_SK_SND_QLEN "sk_snd_qlen"
+%token <i> META_SK_ERR_QLEN "sk_err_qlen"
+%token <i> META_SK_FORWARD_ALLOCS "sk_forward_allocs"
+%token <i> META_SK_ALLOCS "sk_allocs"
+%token <i> META_SK_ROUTE_CAPS "sk_route_caps"
+%token <i> META_SK_HASH "sk_hash"
+%token <i> META_SK_LINGERTIME "sk_lingertime"
+%token <i> META_SK_ACK_BACKLOG "sk_ack_backlog"
+%token <i> META_SK_MAX_ACK_BACKLOG "sk_max_ack_backlog"
+%token <i> META_SK_PRIO "sk_prio"
+%token <i> META_SK_RCVLOWAT "sk_rcvlowat"
+%token <i> META_SK_RCVTIMEO "sk_rcvtimeo"
+%token <i> META_SK_SNDTIMEO "sk_sndtimeo"
+%token <i> META_SK_SENDMSG_OFF "sk_sendmsg_off"
+%token <i> META_SK_WRITE_PENDING "sk_write_pending"
+%token <i> META_VLAN "vlan"
+%token <i> META_RXHASH "rxhash"
+%token <i> META_DEVNAME "devname"
+%token <i> META_SK_BOUND_IF "sk_bound_if"
+
+%token <s> STR
+
+%token <q> QUOTED
+
+%type <i> align operand shift meta_int_id meta_var_id
+%type <i64> mask
+%type <e> expr match ematch
+%type <cmp> cmp_expr cmp_match
+%type <loc> pktloc text_from text_to
+%type <q> pattern
+%type <mv> meta_value
+
+%destructor { free($$); NL_DBG(2, "string destructor\n"); } <s>
+%destructor { rtnl_pktloc_put($$); NL_DBG(2, "pktloc destructor\n"); } <loc>
+%destructor { free($$.data); NL_DBG(2, "quoted destructor\n"); } <q>
+%destructor { rtnl_meta_value_put($$); NL_DBG(2, "meta value destructor\n"); } <mv>
+
+%start input
+
+%%
+
+input:
+       /* empty */
+       | expr
+               {
+                       nl_list_add_tail(root, &$1->e_list);
+               }
+       ;
+
+expr:
+       match
+               {
+                       $$ = $1;
+               }
+       | match LOGIC expr
+               {
+                       rtnl_ematch_set_flags($1, $2);
+
+                       /* make ematch new head */
+                       nl_list_add_tail(&$1->e_list, &$3->e_list);
+
+                       $$ = $1;
+               }
+       ;
+
+match:
+       NOT ematch
+               {
+                       rtnl_ematch_set_flags($2, TCF_EM_INVERT);
+                       $$ = $2;
+               }
+       | ematch
+               {
+                       $$ = $1;
+               }
+       ;
+
+ematch:
+       /* CMP */
+       cmp_match
+               {
+                       struct rtnl_ematch *e;
+
+                       if (!(e = rtnl_ematch_alloc())) {
+                               *errp = strdup("Unable to allocate ematch object");
+                               YYABORT;
+                       }
+
+                       if (rtnl_ematch_set_kind(e, TCF_EM_CMP) < 0)
+                               BUG();
+
+                       rtnl_ematch_cmp_set(e, &$1);
+                       $$ = e;
+               }
+       | EMATCH_NBYTE "(" pktloc KW_EQ pattern ")"
+               {
+                       struct rtnl_ematch *e;
+
+                       if (!(e = rtnl_ematch_alloc())) {
+                               *errp = strdup("Unable to allocate ematch object");
+                               YYABORT;
+                       }
+
+                       if (rtnl_ematch_set_kind(e, TCF_EM_NBYTE) < 0)
+                               BUG();
+
+                       rtnl_ematch_nbyte_set_offset(e, $3->layer, $3->offset);
+                       rtnl_pktloc_put($3);
+                       rtnl_ematch_nbyte_set_pattern(e, (uint8_t *) $5.data, $5.index);
+
+                       $$ = e;
+               }
+       | EMATCH_TEXT "(" STR QUOTED text_from text_to ")"
+               {
+                       struct rtnl_ematch *e;
+
+                       if (!(e = rtnl_ematch_alloc())) {
+                               *errp = strdup("Unable to allocate ematch object");
+                               YYABORT;
+                       }
+
+                       if (rtnl_ematch_set_kind(e, TCF_EM_TEXT) < 0)
+                               BUG();
+
+                       rtnl_ematch_text_set_algo(e, $3);
+                       rtnl_ematch_text_set_pattern(e, $4.data, $4.index);
+
+                       if ($5) {
+                               rtnl_ematch_text_set_from(e, $5->layer, $5->offset);
+                               rtnl_pktloc_put($5);
+                       }
+
+                       if ($6) {
+                               rtnl_ematch_text_set_to(e, $6->layer, $6->offset);
+                               rtnl_pktloc_put($6);
+                       }
+
+                       $$ = e;
+               }
+       | EMATCH_META "(" meta_value operand meta_value ")"
+               {
+                       struct rtnl_ematch *e;
+
+                       if (!(e = rtnl_ematch_alloc())) {
+                               *errp = strdup("Unable to allocate ematch object");
+                               YYABORT;
+                       }
+
+                       if (rtnl_ematch_set_kind(e, TCF_EM_META) < 0)
+                               BUG();
+
+                       rtnl_ematch_meta_set_lvalue(e, $3);
+                       rtnl_ematch_meta_set_rvalue(e, $5);
+                       rtnl_ematch_meta_set_operand(e, $4);
+
+                       $$ = e;
+               }
+       /* CONTAINER */
+       | "(" expr ")"
+               {
+                       struct rtnl_ematch *e;
+
+                       if (!(e = rtnl_ematch_alloc())) {
+                               *errp = strdup("Unable to allocate ematch object");
+                               YYABORT;
+                       }
+
+                       if (rtnl_ematch_set_kind(e, TCF_EM_CONTAINER) < 0)
+                               BUG();
+
+                       /* Make e->childs the list head of a the ematch sequence */
+                       nl_list_add_tail(&e->e_childs, &$2->e_list);
+
+                       $$ = e;
+               }
+       ;
+
+/*
+ * CMP match
+ *
+ * match  := cmp(expr) | expr
+ * expr   := pktloc (=|>|<) NUMBER
+ * pktloc := alias | definition
+ *
+ */
+cmp_match:
+       EMATCH_CMP "(" cmp_expr ")"
+               { $$ = $3; }
+       | cmp_expr
+               { $$ = $1; }
+       ;
+
+cmp_expr:
+       pktloc operand NUMBER
+               {
+                       if ($1->align == TCF_EM_ALIGN_U16 ||
+                           $1->align == TCF_EM_ALIGN_U32)
+                               $$.flags = TCF_EM_CMP_TRANS;
+
+                       memset(&$$, 0, sizeof($$));
+
+                       $$.mask = $1->mask;
+                       $$.off = $1->offset;
+                       $$.align = $1->align;
+                       $$.layer = $1->layer;
+                       $$.opnd = $2;
+                       $$.val = $3;
+
+                       rtnl_pktloc_put($1);
+               }
+       ;
+
+text_from:
+       /* empty */
+               { $$ = NULL; }
+       | "from" pktloc
+               { $$ = $2; }
+       ;
+
+text_to:
+       /* empty */
+               { $$ = NULL; }
+       | "to" pktloc
+               { $$ = $2; }
+       ;
+
+meta_value:
+       QUOTED
+               { $$ = rtnl_meta_value_alloc_var($1.data, $1.len); }
+       | NUMBER
+               { $$ = rtnl_meta_value_alloc_int($1); }
+       | meta_int_id shift mask
+               { $$ = META_ALLOC(META_INT, $1, $2, $3); }
+       | meta_var_id shift
+               { $$ = META_ALLOC(META_VAR, $1, $2, 0); }
+       ;
+
+meta_int_id:
+       META_RANDOM                     { $$ = META_ID(RANDOM); }
+       |META_LOADAVG_0                 { $$ = META_ID(LOADAVG_0); }
+       |META_LOADAVG_1                 { $$ = META_ID(LOADAVG_1); }
+       |META_LOADAVG_2                 { $$ = META_ID(LOADAVG_2); }
+       | META_DEV                      { $$ = META_ID(DEV); }
+       | META_PRIO                     { $$ = META_ID(PRIORITY); }
+       | META_PROTO                    { $$ = META_ID(PROTOCOL); }
+       | META_PKTTYPE                  { $$ = META_ID(PKTTYPE); }
+       | META_PKTLEN                   { $$ = META_ID(PKTLEN); }
+       | META_DATALEN                  { $$ = META_ID(DATALEN); }
+       | META_MACLEN                   { $$ = META_ID(MACLEN); }
+       | META_MARK                     { $$ = META_ID(NFMARK); }
+       | META_TCINDEX                  { $$ = META_ID(TCINDEX); }
+       | META_RTCLASSID                { $$ = META_ID(RTCLASSID); }
+       | META_RTIIF                    { $$ = META_ID(RTIIF); }
+       | META_SK_FAMILY                { $$ = META_ID(SK_FAMILY); }
+       | META_SK_STATE                 { $$ = META_ID(SK_STATE); }
+       | META_SK_REUSE                 { $$ = META_ID(SK_REUSE); }
+       | META_SK_REFCNT                { $$ = META_ID(SK_REFCNT); }
+       | META_SK_RCVBUF                { $$ = META_ID(SK_RCVBUF); }
+       | META_SK_SNDBUF                { $$ = META_ID(SK_SNDBUF); }
+       | META_SK_SHUTDOWN              { $$ = META_ID(SK_SHUTDOWN); }
+       | META_SK_PROTO                 { $$ = META_ID(SK_PROTO); }
+       | META_SK_TYPE                  { $$ = META_ID(SK_TYPE); }
+       | META_SK_RMEM_ALLOC            { $$ = META_ID(SK_RMEM_ALLOC); }
+       | META_SK_WMEM_ALLOC            { $$ = META_ID(SK_WMEM_ALLOC); }
+       | META_SK_WMEM_QUEUED           { $$ = META_ID(SK_WMEM_QUEUED); }
+       | META_SK_RCV_QLEN              { $$ = META_ID(SK_RCV_QLEN); }
+       | META_SK_SND_QLEN              { $$ = META_ID(SK_SND_QLEN); }
+       | META_SK_ERR_QLEN              { $$ = META_ID(SK_ERR_QLEN); }
+       | META_SK_FORWARD_ALLOCS        { $$ = META_ID(SK_FORWARD_ALLOCS); }
+       | META_SK_ALLOCS                { $$ = META_ID(SK_ALLOCS); }
+       | META_SK_ROUTE_CAPS            { $$ = META_ID(SK_ROUTE_CAPS); }
+       | META_SK_HASH                  { $$ = META_ID(SK_HASH); }
+       | META_SK_LINGERTIME            { $$ = META_ID(SK_LINGERTIME); }
+       | META_SK_ACK_BACKLOG           { $$ = META_ID(SK_ACK_BACKLOG); }
+       | META_SK_MAX_ACK_BACKLOG       { $$ = META_ID(SK_MAX_ACK_BACKLOG); }
+       | META_SK_PRIO                  { $$ = META_ID(SK_PRIO); }
+       | META_SK_RCVLOWAT              { $$ = META_ID(SK_RCVLOWAT); }
+       | META_SK_RCVTIMEO              { $$ = META_ID(SK_RCVTIMEO); }
+       | META_SK_SNDTIMEO              { $$ = META_ID(SK_SNDTIMEO); }
+       | META_SK_SENDMSG_OFF           { $$ = META_ID(SK_SENDMSG_OFF); }
+       | META_SK_WRITE_PENDING         { $$ = META_ID(SK_WRITE_PENDING); }
+       | META_VLAN                     { $$ = META_ID(VLAN_TAG); }
+       | META_RXHASH                   { $$ = META_ID(RXHASH); }
+       ;
+
+meta_var_id:
+       META_DEVNAME            { $$ = META_ID(DEV); }
+       | META_SK_BOUND_IF      { $$ = META_ID(SK_BOUND_IF); }
+       ;
+
+/*
+ * pattern
+ */
+pattern:
+       QUOTED
+               {
+                       $$ = $1;
+               }
+       | STR
+               {
+                       struct nl_addr *addr;
+
+                       if (nl_addr_parse($1, AF_UNSPEC, &addr) == 0) {
+                               $$.len = nl_addr_get_len(addr);
+
+                               $$.index = min_t(int, $$.len, nl_addr_get_prefixlen(addr)/8);
+
+                               if (!($$.data = calloc(1, $$.len))) {
+                                       nl_addr_put(addr);
+                                       YYABORT;
+                               }
+
+                               memcpy($$.data, nl_addr_get_binary_addr(addr), $$.len);
+                               nl_addr_put(addr);
+                       } else {
+                               if (asprintf(errp, "invalid pattern \"%s\"", $1) == -1)
+                                       *errp = NULL;
+                               YYABORT;
+                       }
+               }
+       ;
+
+/*
+ * packet location
+ */
+
+pktloc:
+       STR
+               {
+                       struct rtnl_pktloc *loc;
+
+                       if (rtnl_pktloc_lookup($1, &loc) < 0) {
+                               if (asprintf(errp, "Packet location \"%s\" not found", $1) == -1)
+                                       *errp = NULL;
+                               YYABORT;
+                       }
+
+                       $$ = loc;
+               }
+       /* [u8|u16|u32|NUM at] LAYER + OFFSET [mask MASK] */
+       | align LAYER "+" NUMBER mask
+               {
+                       struct rtnl_pktloc *loc;
+
+                       if ($5 && (!$1 || $1 > TCF_EM_ALIGN_U32)) {
+                               *errp = strdup("mask only allowed for alignments u8|u16|u32");
+                               YYABORT;
+                       }
+
+                       if (!(loc = rtnl_pktloc_alloc())) {
+                               *errp = strdup("Unable to allocate packet location object");
+                               YYABORT;
+                       }
+
+                       loc->name = strdup("<USER-DEFINED>");
+                       loc->align = $1;
+                       loc->layer = $2;
+                       loc->offset = $4;
+                       loc->mask = $5;
+
+                       $$ = loc;
+               }
+       ;
+
+align:
+       /* empty */
+               { $$ = 0; }
+       | ALIGN "at"
+               { $$ = $1; }
+       | NUMBER "at"
+               { $$ = $1; }
+       ;
+
+mask:
+       /* empty */
+               { $$ = 0; }
+       | KW_MASK NUMBER
+               { $$ = $2; }
+       ;
+
+shift:
+       /* empty */
+               { $$ = 0; }
+       | KW_SHIFT NUMBER
+               { $$ = $2; }
+       ;
+
+operand:
+       KW_EQ
+               { $$ = TCF_EM_OPND_EQ; }
+       | KW_GT
+               { $$ = TCF_EM_OPND_GT; }
+       | KW_LT
+               { $$ = TCF_EM_OPND_LT; }
+       ;
diff --git a/lib/route/cls/fw.c b/lib/route/cls/fw.c
new file mode 100644 (file)
index 0000000..b569d4f
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * lib/route/cls/fw.c          fw classifier
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
+ * Copyright (c) 2006 Siemens AG Oesterreich
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_fw Firewall Classifier
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/fw.h>
+
+/** @cond SKIP */
+#define FW_ATTR_CLASSID      0x001
+#define FW_ATTR_ACTION       0x002
+#define FW_ATTR_POLICE       0x004
+#define FW_ATTR_INDEV        0x008
+#define FW_ATTR_MASK         0x010
+/** @endcond */
+
+static struct nla_policy fw_policy[TCA_FW_MAX+1] = {
+       [TCA_FW_CLASSID]        = { .type = NLA_U32 },
+       [TCA_FW_INDEV]          = { .type = NLA_STRING,
+                                   .maxlen = IFNAMSIZ },
+       [TCA_FW_MASK]           = { .type = NLA_U32 },
+};
+
+static int fw_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_FW_MAX + 1];
+       struct rtnl_fw *f = data;
+       int err;
+
+       err = tca_parse(tb, TCA_FW_MAX, tc, fw_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_FW_CLASSID]) {
+               f->cf_classid = nla_get_u32(tb[TCA_FW_CLASSID]);
+               f->cf_mask |= FW_ATTR_CLASSID;
+       }
+
+       if (tb[TCA_FW_ACT]) {
+               f->cf_act = nl_data_alloc_attr(tb[TCA_FW_ACT]);
+               if (!f->cf_act)
+                       return -NLE_NOMEM;
+               f->cf_mask |= FW_ATTR_ACTION;
+       }
+
+       if (tb[TCA_FW_POLICE]) {
+               f->cf_police = nl_data_alloc_attr(tb[TCA_FW_POLICE]);
+               if (!f->cf_police)
+                       return -NLE_NOMEM;
+               f->cf_mask |= FW_ATTR_POLICE;
+       }
+
+       if (tb[TCA_FW_INDEV]) {
+               nla_strlcpy(f->cf_indev, tb[TCA_FW_INDEV], IFNAMSIZ);
+               f->cf_mask |= FW_ATTR_INDEV;
+       }
+
+       if (tb[TCA_FW_MASK]) {
+               f->cf_fwmask = nla_get_u32(tb[TCA_FW_MASK]);
+               f->cf_mask |= FW_ATTR_MASK;
+       }
+
+       return 0;
+}
+
+static void fw_free_data(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_fw *f = data;
+
+       nl_data_free(f->cf_act);
+       nl_data_free(f->cf_police);
+}
+
+static int fw_clone(void *_dst, void *_src)
+{
+       struct rtnl_fw *dst = _dst, *src = _src;
+
+       if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act)))
+               return -NLE_NOMEM;
+       
+       if (src->cf_police && !(dst->cf_police = nl_data_clone(src->cf_police)))
+               return -NLE_NOMEM;
+
+       return 0;
+}
+
+static void fw_dump_line(struct rtnl_tc *tc, void *data,
+                        struct nl_dump_params *p)
+{
+       struct rtnl_fw *f = data;
+
+       if (!f)
+               return;
+
+       if (f->cf_mask & FW_ATTR_CLASSID) {
+               char buf[32];
+
+               nl_dump(p, " target %s",
+                       rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf)));
+       }
+
+       if (f->cf_mask & FW_ATTR_MASK)
+               nl_dump(p, " mask 0x%x", f->cf_fwmask);
+}
+
+static void fw_dump_details(struct rtnl_tc *tc, void *data,
+                           struct nl_dump_params *p)
+{
+       struct rtnl_fw *f = data;
+
+       if (f && f->cf_mask & FW_ATTR_INDEV)
+               nl_dump(p, "indev %s ", f->cf_indev);
+}
+
+static int fw_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       struct rtnl_fw *f = data;
+
+       if (!f)
+               return 0;
+
+       if (f->cf_mask & FW_ATTR_CLASSID)
+               NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid);
+
+       if (f->cf_mask & FW_ATTR_ACTION)
+               NLA_PUT_DATA(msg, TCA_FW_ACT, f->cf_act);
+
+       if (f->cf_mask & FW_ATTR_POLICE)
+               NLA_PUT_DATA(msg, TCA_FW_POLICE, f->cf_police);
+
+       if (f->cf_mask & FW_ATTR_INDEV)
+               NLA_PUT_STRING(msg, TCA_FW_INDEV, f->cf_indev);
+
+       if (f->cf_mask & FW_ATTR_MASK)
+               NLA_PUT_U32(msg, TCA_FW_MASK, f->cf_fwmask);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid)
+{
+       struct rtnl_fw *f;
+
+       if (!(f = rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+       
+       f->cf_classid = classid;
+       f->cf_mask |= FW_ATTR_CLASSID;
+
+       return 0;
+}
+
+int rtnl_fw_set_mask(struct rtnl_cls *cls, uint32_t mask)
+{
+       struct rtnl_fw *f;
+
+       if (!(f = rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+       
+       f->cf_fwmask = mask;
+       f->cf_mask |= FW_ATTR_MASK;
+
+       return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops fw_ops = {
+       .to_kind                = "fw",
+       .to_type                = RTNL_TC_TYPE_CLS,
+       .to_size                = sizeof(struct rtnl_fw),
+       .to_msg_parser          = fw_msg_parser,
+       .to_msg_fill            = fw_msg_fill,
+       .to_free_data           = fw_free_data,
+       .to_clone               = fw_clone,
+       .to_dump = {
+           [NL_DUMP_LINE]      = fw_dump_line,
+           [NL_DUMP_DETAILS]   = fw_dump_details,
+       },
+};
+
+static void __init fw_init(void)
+{
+       rtnl_tc_register(&fw_ops);
+}
+
+static void __exit fw_exit(void)
+{
+       rtnl_tc_unregister(&fw_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/police.c b/lib/route/cls/police.c
new file mode 100644 (file)
index 0000000..1f5d284
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * lib/route/cls/police.c      Policer
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/police.h>
+
+/**
+ * @name Policer Type
+ * @{
+ */
+
+static const struct trans_tbl police_types[] = {
+       __ADD(TC_POLICE_UNSPEC,unspec)
+       __ADD(TC_POLICE_OK,ok)
+       __ADD(TC_POLICE_RECLASSIFY,reclassify)
+       __ADD(TC_POLICE_SHOT,shot)
+#ifdef TC_POLICE_PIPE
+       __ADD(TC_POLICE_PIPE,pipe)
+#endif
+};
+
+/**
+ * Transform a policer type number into a character string (Reentrant).
+ * @arg type           policer type
+ * @arg buf            destination buffer
+ * @arg len            buffer length
+ *
+ * Transforms a policer type number into a character string and stores
+ * it in the provided buffer.
+ *
+ * @return The destination buffer or the type encoded in hex if no match was found.
+ */
+char * nl_police2str(int type, char *buf, size_t len)
+{
+       return __type2str(type, buf, len, police_types,
+                         ARRAY_SIZE(police_types));
+}
+
+/**
+ * Transform a character string into a policer type number
+ * @arg name           policer type name
+ *
+ * Transform the provided character string specifying a policer
+ * type into the corresponding numeric value
+ *
+ * @return Policer type number or a negative value.
+ */
+int nl_str2police(const char *name)
+{
+       return __str2type(name, police_types, ARRAY_SIZE(police_types));
+}
+
+/** @} */
diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c
new file mode 100644 (file)
index 0000000..c468ba7
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * lib/route/cls/u32.c         u32 classifier
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
+ * Copyright (c) 2005-2006 Siemens AG Oesterreich
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_u32 Universal 32-bit Classifier
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/u32.h>
+
+/** @cond SKIP */
+#define U32_ATTR_DIVISOR      0x001
+#define U32_ATTR_HASH         0x002
+#define U32_ATTR_CLASSID      0x004
+#define U32_ATTR_LINK         0x008
+#define U32_ATTR_PCNT         0x010
+#define U32_ATTR_SELECTOR     0x020
+#define U32_ATTR_ACTION       0x040
+#define U32_ATTR_POLICE       0x080
+#define U32_ATTR_INDEV        0x100
+/** @endcond */
+
+static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
+{
+       return (struct tc_u32_sel *) u->cu_selector->d_data;
+}
+
+static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
+{
+       if (!u->cu_selector)
+               u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
+
+       return u32_selector(u);
+}
+
+static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
+       [TCA_U32_DIVISOR]       = { .type = NLA_U32 },
+       [TCA_U32_HASH]          = { .type = NLA_U32 },
+       [TCA_U32_CLASSID]       = { .type = NLA_U32 },
+       [TCA_U32_LINK]          = { .type = NLA_U32 },
+       [TCA_U32_INDEV]         = { .type = NLA_STRING,
+                                   .maxlen = IFNAMSIZ },
+       [TCA_U32_SEL]           = { .minlen = sizeof(struct tc_u32_sel) },
+       [TCA_U32_PCNT]          = { .minlen = sizeof(struct tc_u32_pcnt) },
+};
+
+static int u32_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_u32 *u = data;
+       struct nlattr *tb[TCA_U32_MAX + 1];
+       int err;
+
+       err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_U32_DIVISOR]) {
+               u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
+               u->cu_mask |= U32_ATTR_DIVISOR;
+       }
+
+       if (tb[TCA_U32_SEL]) {
+               u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
+               if (!u->cu_selector)
+                       goto errout_nomem;
+               u->cu_mask |= U32_ATTR_SELECTOR;
+       }
+
+       if (tb[TCA_U32_HASH]) {
+               u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
+               u->cu_mask |= U32_ATTR_HASH;
+       }
+
+       if (tb[TCA_U32_CLASSID]) {
+               u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
+               u->cu_mask |= U32_ATTR_CLASSID;
+       }
+
+       if (tb[TCA_U32_LINK]) {
+               u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
+               u->cu_mask |= U32_ATTR_LINK;
+       }
+
+       if (tb[TCA_U32_ACT]) {
+               u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
+               if (!u->cu_act)
+                       goto errout_nomem;
+               u->cu_mask |= U32_ATTR_ACTION;
+       }
+
+       if (tb[TCA_U32_POLICE]) {
+               u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
+               if (!u->cu_police)
+                       goto errout_nomem;
+               u->cu_mask |= U32_ATTR_POLICE;
+       }
+
+       if (tb[TCA_U32_PCNT]) {
+               struct tc_u32_sel *sel;
+               size_t pcnt_size;
+
+               if (!tb[TCA_U32_SEL]) {
+                       err = -NLE_MISSING_ATTR;
+                       goto errout;
+               }
+               
+               sel = u->cu_selector->d_data;
+               pcnt_size = sizeof(struct tc_u32_pcnt) +
+                               (sel->nkeys * sizeof(uint64_t));
+               if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
+                       err = -NLE_INVAL;
+                       goto errout;
+               }
+
+               u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
+               if (!u->cu_pcnt)
+                       goto errout_nomem;
+               u->cu_mask |= U32_ATTR_PCNT;
+       }
+
+       if (tb[TCA_U32_INDEV]) {
+               nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
+               u->cu_mask |= U32_ATTR_INDEV;
+       }
+
+       return 0;
+
+errout_nomem:
+       err = -NLE_NOMEM;
+errout:
+       return err;
+}
+
+static void u32_free_data(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_u32 *u = data;
+
+       nl_data_free(u->cu_selector);
+       nl_data_free(u->cu_act);
+       nl_data_free(u->cu_police);
+       nl_data_free(u->cu_pcnt);
+}
+
+static int u32_clone(void *_dst, void *_src)
+{
+       struct rtnl_u32 *dst = _dst, *src = _src;
+
+       if (src->cu_selector &&
+           !(dst->cu_selector = nl_data_clone(src->cu_selector)))
+               return -NLE_NOMEM;
+
+       if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
+               return -NLE_NOMEM;
+
+       if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
+               return -NLE_NOMEM;
+
+       if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
+               return -NLE_NOMEM;
+
+       return 0;
+}
+
+static void u32_dump_line(struct rtnl_tc *tc, void *data,
+                         struct nl_dump_params *p)
+{
+       struct rtnl_u32 *u = data;
+       char buf[32];
+       
+       if (!u)
+               return;
+
+       if (u->cu_mask & U32_ATTR_DIVISOR)
+               nl_dump(p, " divisor %u", u->cu_divisor);
+       else if (u->cu_mask & U32_ATTR_CLASSID)
+               nl_dump(p, " target %s",
+                       rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
+}
+
+static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
+                          struct rtnl_u32 *u)
+{
+       int i;
+       struct tc_u32_key *key;
+
+       if (sel->hmask || sel->hoff) {
+               /* I guess this will never be used since the kernel only
+                * exports the selector if no divisor is set but hash offset
+                * and hash mask make only sense in hash filters with divisor
+                * set */
+               nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
+       }
+
+       if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
+               nl_dump(p, " offset at %u", sel->off);
+
+               if (sel->flags & TC_U32_VAROFFSET)
+                       nl_dump(p, " variable (at %u & 0x%x) >> %u",
+                               sel->offoff, ntohs(sel->offmask), sel->offshift);
+       }
+
+       if (sel->flags) {
+               int flags = sel->flags;
+               nl_dump(p, " <");
+
+#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
+       flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+
+               PRINT_FLAG(TERMINAL);
+               PRINT_FLAG(OFFSET);
+               PRINT_FLAG(VAROFFSET);
+               PRINT_FLAG(EAT);
+#undef PRINT_FLAG
+
+               nl_dump(p, ">");
+       }
+               
+       
+       for (i = 0; i < sel->nkeys; i++) {
+               key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
+
+               nl_dump(p, "\n");
+               nl_dump_line(p, "      match key at %s%u ",
+                       key->offmask ? "nexthdr+" : "", key->off);
+
+               if (key->offmask)
+                       nl_dump(p, "[0x%u] ", key->offmask);
+
+               nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
+
+               if (p->dp_type == NL_DUMP_STATS &&
+                   (u->cu_mask & U32_ATTR_PCNT)) {
+                       struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
+                       nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
+               }
+       }
+}
+
+static void u32_dump_details(struct rtnl_tc *tc, void *data,
+                            struct nl_dump_params *p)
+{
+       struct rtnl_u32 *u = data;
+       struct tc_u32_sel *s;
+
+       if (!u)
+               return;
+
+       if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
+               nl_dump(p, "no-selector\n");
+               return;
+       }
+       
+       s = u->cu_selector->d_data;
+
+       nl_dump(p, "nkeys %u ", s->nkeys);
+
+       if (u->cu_mask & U32_ATTR_HASH)
+               nl_dump(p, "ht key 0x%x hash 0x%u",
+                       TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
+
+       if (u->cu_mask & U32_ATTR_LINK)
+               nl_dump(p, "link %u ", u->cu_link);
+
+       if (u->cu_mask & U32_ATTR_INDEV)
+               nl_dump(p, "indev %s ", u->cu_indev);
+
+       print_selector(p, s, u);
+       nl_dump(p, "\n");
+
+#if 0  
+#define U32_ATTR_ACTION       0x040
+#define U32_ATTR_POLICE       0x080
+
+       struct nl_data   act;
+       struct nl_data   police;
+#endif
+}
+
+static void u32_dump_stats(struct rtnl_tc *tc, void *data,
+                          struct nl_dump_params *p)
+{
+       struct rtnl_u32 *u = data;
+
+       if (!u)
+               return;
+
+       if (u->cu_mask & U32_ATTR_PCNT) {
+               struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
+               nl_dump(p, "\n");
+               nl_dump_line(p, "    hit %8" PRIu64 " count %8" PRIu64 "\n",
+                            pc->rhit, pc->rcnt);
+       }
+}
+
+static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       struct rtnl_u32 *u = data;
+
+       if (!u)
+               return 0;
+       
+       if (u->cu_mask & U32_ATTR_DIVISOR)
+               NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
+
+       if (u->cu_mask & U32_ATTR_HASH)
+               NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
+
+       if (u->cu_mask & U32_ATTR_CLASSID)
+               NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
+
+       if (u->cu_mask & U32_ATTR_LINK)
+               NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
+
+       if (u->cu_mask & U32_ATTR_SELECTOR)
+               NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
+
+       if (u->cu_mask & U32_ATTR_ACTION)
+               NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
+
+       if (u->cu_mask & U32_ATTR_POLICE)
+               NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
+
+       if (u->cu_mask & U32_ATTR_INDEV)
+               NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_NOMEM;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
+                        int nodeid)
+{
+       uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
+
+       rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
+}
+int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
+{
+       struct rtnl_u32 *u;
+
+       if (!(u = rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+       
+       u->cu_classid = classid;
+       u->cu_mask |= U32_ATTR_CLASSID;
+
+       return 0;
+}
+
+int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
+{
+       struct rtnl_u32 *u;
+
+       if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+
+       u->cu_divisor = divisor;
+       u->cu_mask |= U32_ATTR_DIVISOR;
+       return 0;
+}
+
+int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
+{
+       struct rtnl_u32 *u;
+
+       if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+
+       u->cu_link = link;
+       u->cu_mask |= U32_ATTR_LINK;
+       return 0;
+}
+
+int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
+{
+       struct rtnl_u32 *u;
+
+       if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+
+       u->cu_hash = ht;
+       u->cu_mask |= U32_ATTR_HASH;
+       return 0;
+}
+
+int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
+{
+       struct rtnl_u32 *u;
+       struct tc_u32_sel *sel;
+       int err;
+
+       hashmask = htonl(hashmask);
+
+       if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+
+       sel = u32_selector_alloc(u);
+       if (!sel)
+               return -NLE_NOMEM;
+
+       err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
+       if(err < 0)
+               return err;
+
+       sel = u32_selector(u);
+
+       sel->hmask = hashmask;
+       sel->hoff = offset;
+       return 0;
+}
+
+int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
+{
+       struct rtnl_u32 *u;
+       struct tc_u32_sel *sel;
+       int err;
+
+       if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+
+       sel = u32_selector_alloc(u);
+       if (!sel)
+               return -NLE_NOMEM;
+
+       err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
+       if(err < 0)
+               return err;
+
+       sel = u32_selector(u);
+
+       sel->flags |= TC_U32_TERMINAL;
+       return 0;
+}
+
+/** @} */
+
+/**
+ * @name Selector Modifications
+ * @{
+ */
+
+int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
+{
+       struct tc_u32_sel *sel;
+       struct rtnl_u32 *u;
+
+       if (!(u = rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+
+       sel = u32_selector_alloc(u);
+       if (!sel)
+               return -NLE_NOMEM;
+
+       sel->flags |= flags;
+       u->cu_mask |= U32_ATTR_SELECTOR;
+
+       return 0;
+}
+
+/**
+ * Append new 32-bit key to the selector
+ *
+ * @arg cls    classifier to be modifier
+ * @arg val    value to be matched (network byte-order)
+ * @arg mask   mask to be applied before matching (network byte-order)
+ * @arg off    offset, in bytes, to start matching
+ * @arg offmask        offset mask
+ *
+ * General selectors define the pattern, mask and offset the pattern will be
+ * matched to the packet contents. Using the general selectors you can match
+ * virtually any single bit in the IP (or upper layer) header.
+ *
+*/
+int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
+                    int off, int offmask)
+{
+       struct tc_u32_sel *sel;
+       struct rtnl_u32 *u;
+       int err;
+
+       if (!(u = rtnl_tc_data(TC_CAST(cls))))
+               return -NLE_NOMEM;
+
+       sel = u32_selector_alloc(u);
+       if (!sel)
+               return -NLE_NOMEM;
+
+       err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
+       if (err < 0)
+               return err;
+
+       /* the selector might have been moved by realloc */
+       sel = u32_selector(u);
+
+       sel->keys[sel->nkeys].mask = mask;
+       sel->keys[sel->nkeys].val = val & mask;
+       sel->keys[sel->nkeys].off = off;
+       sel->keys[sel->nkeys].offmask = offmask;
+       sel->nkeys++;
+       u->cu_mask |= U32_ATTR_SELECTOR;
+
+       return 0;
+}
+
+int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
+                          int off, int offmask)
+{
+       int shift = 24 - 8 * (off & 3);
+
+       return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
+                               htonl((uint32_t)mask << shift),
+                               off & ~3, offmask);
+}
+
+/**
+ * Append new selector key to match a 16-bit number
+ *
+ * @arg cls    classifier to be modified
+ * @arg val    value to be matched (host byte-order)
+ * @arg mask   mask to be applied before matching (host byte-order)
+ * @arg off    offset, in bytes, to start matching
+ * @arg offmask        offset mask
+*/
+int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
+                           int off, int offmask)
+{
+       int shift = ((off & 3) == 0 ? 16 : 0);
+       if (off % 2)
+               return -NLE_INVAL;
+
+       return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
+                               htonl((uint32_t)mask << shift),
+                               off & ~3, offmask);
+}
+
+/**
+ * Append new selector key to match a 32-bit number
+ *
+ * @arg cls    classifier to be modified
+ * @arg val    value to be matched (host byte-order)
+ * @arg mask   mask to be applied before matching (host byte-order)
+ * @arg off    offset, in bytes, to start matching
+ * @arg offmask        offset mask
+*/
+int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
+                           int off, int offmask)
+{
+       return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
+                               off & ~3, offmask);
+}
+
+int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
+                            uint8_t bitmask, int off, int offmask)
+{
+       uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
+       return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
+}
+
+int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
+                             uint8_t bitmask, int off, int offmask)
+{
+       int i, err;
+
+       for (i = 1; i <= 4; i++) {
+               if (32 * i - bitmask <= 0) {
+                       if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
+                                               0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
+                               return err;
+               }
+               else if (32 * i - bitmask < 32) {
+                       uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
+                       if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
+                                               htonl(mask), off+4*(i-1), offmask)) < 0)
+                               return err;
+               }
+               /* otherwise, if (32*i - bitmask >= 32) no key is generated */
+       }
+
+       return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops u32_ops = {
+       .to_kind                = "u32",
+       .to_type                = RTNL_TC_TYPE_CLS,
+       .to_size                = sizeof(struct rtnl_u32),
+       .to_msg_parser          = u32_msg_parser,
+       .to_free_data           = u32_free_data,
+       .to_clone               = u32_clone,
+       .to_msg_fill            = u32_msg_fill,
+       .to_dump = {
+           [NL_DUMP_LINE]      = u32_dump_line,
+           [NL_DUMP_DETAILS]   = u32_dump_details,
+           [NL_DUMP_STATS]     = u32_dump_stats,
+       },
+};
+
+static void __init u32_init(void)
+{
+       rtnl_tc_register(&u32_ops);
+}
+
+static void __exit u32_exit(void)
+{
+       rtnl_tc_unregister(&u32_ops);
+}
+
+/** @} */
diff --git a/lib/route/link.c b/lib/route/link.c
new file mode 100644 (file)
index 0000000..77dd7f1
--- /dev/null
@@ -0,0 +1,2644 @@
+/*
+ * lib/route/link.c    Links (Interfaces)
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup link Links (Interfaces)
+ *
+ * @details
+ * @route_doc{route_link, Link Documentation}
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/hashtable.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink-private/route/link/api.h>
+
+/** @cond SKIP */
+#define LINK_ATTR_MTU          (1 <<  0)
+#define LINK_ATTR_LINK         (1 <<  1)
+#define LINK_ATTR_TXQLEN       (1 <<  2)
+#define LINK_ATTR_WEIGHT       (1 <<  3)
+#define LINK_ATTR_MASTER       (1 <<  4)
+#define LINK_ATTR_QDISC                (1 <<  5)
+#define LINK_ATTR_MAP          (1 <<  6)
+#define LINK_ATTR_ADDR         (1 <<  7)
+#define LINK_ATTR_BRD          (1 <<  8)
+#define LINK_ATTR_FLAGS                (1 <<  9)
+#define LINK_ATTR_IFNAME       (1 << 10)
+#define LINK_ATTR_IFINDEX      (1 << 11)
+#define LINK_ATTR_FAMILY       (1 << 12)
+#define LINK_ATTR_ARPTYPE      (1 << 13)
+#define LINK_ATTR_STATS                (1 << 14)
+#define LINK_ATTR_CHANGE       (1 << 15)
+#define LINK_ATTR_OPERSTATE    (1 << 16)
+#define LINK_ATTR_LINKMODE     (1 << 17)
+#define LINK_ATTR_LINKINFO     (1 << 18)
+#define LINK_ATTR_IFALIAS      (1 << 19)
+#define LINK_ATTR_NUM_VF       (1 << 20)
+#define LINK_ATTR_PROMISCUITY  (1 << 21)
+#define LINK_ATTR_NUM_TX_QUEUES        (1 << 22)
+#define LINK_ATTR_NUM_RX_QUEUES        (1 << 23)
+#define LINK_ATTR_GROUP                (1 << 24)
+#define LINK_ATTR_CARRIER      (1 << 25)
+#define LINK_ATTR_PROTINFO     (1 << 26)
+#define LINK_ATTR_AF_SPEC      (1 << 27)
+
+static struct nl_cache_ops rtnl_link_ops;
+static struct nl_object_ops link_obj_ops;
+/** @endcond */
+
+static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
+                                                   int family)
+{
+       struct rtnl_link_af_ops *af_ops;
+       void *data;
+
+       af_ops = rtnl_link_af_ops_lookup(family);
+       if (!af_ops)
+               return NULL;
+
+       if (!(data = rtnl_link_af_alloc(link, af_ops))) {
+               rtnl_link_af_ops_put(af_ops);
+               return NULL;
+       }
+
+       return af_ops;
+}
+
+static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+                   void *data, void *arg)
+{
+       if (ops->ao_free)
+               ops->ao_free(link, data);
+
+       rtnl_link_af_ops_put(ops);
+
+       return 0;
+}
+
+static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+                   void *data, void *arg)
+{
+       struct rtnl_link *dst = arg;
+
+       if (ops->ao_clone &&
+           !(dst->l_af_data[ops->ao_family] = ops->ao_clone(dst, data)))
+               return -NLE_NOMEM;
+
+       return 0;
+}
+
+static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+                  void *data, void *arg)
+{
+       struct nl_msg *msg = arg;
+       struct nlattr *af_attr;
+       int err;
+
+       if (!ops->ao_fill_af)
+               return 0;
+
+       if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
+               return -NLE_MSGSIZE;
+
+       if ((err = ops->ao_fill_af(link, arg, data)) < 0)
+               return err;
+
+       nla_nest_end(msg, af_attr);
+
+       return 0;
+}
+
+static int af_dump_line(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+                        void *data, void *arg)
+{
+       struct nl_dump_params *p = arg;
+
+       if (ops->ao_dump[NL_DUMP_LINE])
+               ops->ao_dump[NL_DUMP_LINE](link, p, data);
+
+       return 0;
+}
+
+static int af_dump_details(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+                          void *data, void *arg)
+{
+       struct nl_dump_params *p = arg;
+
+       if (ops->ao_dump[NL_DUMP_DETAILS])
+               ops->ao_dump[NL_DUMP_DETAILS](link, p, data);
+
+       return 0;
+}
+
+static int af_dump_stats(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+                        void *data, void *arg)
+{
+       struct nl_dump_params *p = arg;
+
+       if (ops->ao_dump[NL_DUMP_STATS])
+               ops->ao_dump[NL_DUMP_STATS](link, p, data);
+
+       return 0;
+}
+
+static int do_foreach_af(struct rtnl_link *link,
+                        int (*cb)(struct rtnl_link *,
+                                  struct rtnl_link_af_ops *, void *, void *),
+                        void *arg)
+{
+       int i, err;
+
+       for (i = 0; i < AF_MAX; i++) {
+               if (link->l_af_data[i]) {
+                       struct rtnl_link_af_ops *ops;
+
+                       if (!(ops = rtnl_link_af_ops_lookup(i)))
+                               BUG();
+
+                       err = cb(link, ops, link->l_af_data[i], arg);
+
+                       rtnl_link_af_ops_put(ops);
+
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+static void release_link_info(struct rtnl_link *link)
+{
+       struct rtnl_link_info_ops *io = link->l_info_ops;
+
+       if (io != NULL) {
+               if (io->io_free)
+                       io->io_free(link);
+               rtnl_link_info_ops_put(io);
+               link->l_info_ops = NULL;
+       }
+}
+
+static void link_free_data(struct nl_object *c)
+{
+       struct rtnl_link *link = nl_object_priv(c);
+
+       if (link) {
+               struct rtnl_link_info_ops *io;
+
+               if ((io = link->l_info_ops) != NULL)
+                       release_link_info(link);
+
+               /* proto info af reference */
+               rtnl_link_af_ops_put(link->l_af_ops);
+
+               nl_addr_put(link->l_addr);
+               nl_addr_put(link->l_bcast);
+
+               free(link->l_ifalias);
+               free(link->l_info_kind);
+
+               do_foreach_af(link, af_free, NULL);
+       }
+}
+
+static int link_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct rtnl_link *dst = nl_object_priv(_dst);
+       struct rtnl_link *src = nl_object_priv(_src);
+       int err;
+
+       if (src->l_addr)
+               if (!(dst->l_addr = nl_addr_clone(src->l_addr)))
+                       return -NLE_NOMEM;
+
+       if (src->l_bcast)
+               if (!(dst->l_bcast = nl_addr_clone(src->l_bcast)))
+                       return -NLE_NOMEM;
+
+       if (src->l_ifalias)
+               if (!(dst->l_ifalias = strdup(src->l_ifalias)))
+                       return -NLE_NOMEM;
+
+       if (src->l_info_kind)
+               if (!(dst->l_info_kind = strdup(src->l_info_kind)))
+                       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)
+                       return err;
+       }
+
+       if ((err = do_foreach_af(src, af_clone, dst)) < 0)
+               return err;
+
+       return 0;
+}
+
+static struct nla_policy link_policy[IFLA_MAX+1] = {
+       [IFLA_IFNAME]           = { .type = NLA_STRING,
+                                   .maxlen = IFNAMSIZ },
+       [IFLA_MTU]              = { .type = NLA_U32 },
+       [IFLA_TXQLEN]           = { .type = NLA_U32 },
+       [IFLA_LINK]             = { .type = NLA_U32 },
+       [IFLA_WEIGHT]           = { .type = NLA_U32 },
+       [IFLA_MASTER]           = { .type = NLA_U32 },
+       [IFLA_OPERSTATE]        = { .type = NLA_U8 },
+       [IFLA_LINKMODE]         = { .type = NLA_U8 },
+       [IFLA_LINKINFO]         = { .type = NLA_NESTED },
+       [IFLA_QDISC]            = { .type = NLA_STRING,
+                                   .maxlen = IFQDISCSIZ },
+       [IFLA_STATS]            = { .minlen = sizeof(struct rtnl_link_stats) },
+       [IFLA_STATS64]          = { .minlen = sizeof(struct rtnl_link_stats64)},
+       [IFLA_MAP]              = { .minlen = sizeof(struct rtnl_link_ifmap) },
+       [IFLA_IFALIAS]          = { .type = NLA_STRING, .maxlen = IFALIASZ },
+       [IFLA_NUM_VF]           = { .type = NLA_U32 },
+       [IFLA_AF_SPEC]          = { .type = NLA_NESTED },
+       [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
+       [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
+       [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
+       [IFLA_GROUP]            = { .type = NLA_U32 },
+       [IFLA_CARRIER]          = { .type = NLA_U8 },
+};
+
+static struct nla_policy link_info_policy[IFLA_INFO_MAX+1] = {
+       [IFLA_INFO_KIND]        = { .type = NLA_STRING },
+       [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
+       [IFLA_INFO_XSTATS]      = { .type = NLA_NESTED },
+};
+
+static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                          struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+       struct rtnl_link *link;
+       struct ifinfomsg *ifi;
+       struct nlattr *tb[IFLA_MAX+1];
+       struct rtnl_link_af_ops *af_ops = NULL;
+       int err, family;
+       struct nla_policy real_link_policy[IFLA_MAX+1];
+
+       memcpy(&real_link_policy, link_policy, sizeof(link_policy));
+
+       link = rtnl_link_alloc();
+       if (link == NULL) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+               
+       link->ce_msgtype = n->nlmsg_type;
+
+       if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
+               return -NLE_MSG_TOOSHORT;
+
+       ifi = nlmsg_data(n);
+       link->l_family = family = ifi->ifi_family;
+       link->l_arptype = ifi->ifi_type;
+       link->l_index = ifi->ifi_index;
+       link->l_flags = ifi->ifi_flags;
+       link->l_change = ifi->ifi_change;
+       link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
+                         LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
+                         LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
+
+       if ((af_ops = af_lookup_and_alloc(link, family))) {
+               if (af_ops->ao_protinfo_policy) {
+                       memcpy(&real_link_policy[IFLA_PROTINFO],
+                              af_ops->ao_protinfo_policy,
+                              sizeof(struct nla_policy));
+               }
+
+               link->l_af_ops = af_ops;
+       }
+
+       err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, real_link_policy);
+       if (err < 0)
+               goto errout;
+
+       if (tb[IFLA_IFNAME] == NULL) {
+               err = -NLE_MISSING_ATTR;
+               goto errout;
+       }
+
+       nla_strlcpy(link->l_name, tb[IFLA_IFNAME], IFNAMSIZ);
+
+
+       if (tb[IFLA_STATS]) {
+               struct rtnl_link_stats *st = nla_data(tb[IFLA_STATS]);
+
+               link->l_stats[RTNL_LINK_RX_PACKETS]     = st->rx_packets;
+               link->l_stats[RTNL_LINK_TX_PACKETS]     = st->tx_packets;
+               link->l_stats[RTNL_LINK_RX_BYTES]       = st->rx_bytes;
+               link->l_stats[RTNL_LINK_TX_BYTES]       = st->tx_bytes;
+               link->l_stats[RTNL_LINK_RX_ERRORS]      = st->rx_errors;
+               link->l_stats[RTNL_LINK_TX_ERRORS]      = st->tx_errors;
+               link->l_stats[RTNL_LINK_RX_DROPPED]     = st->rx_dropped;
+               link->l_stats[RTNL_LINK_TX_DROPPED]     = st->tx_dropped;
+               link->l_stats[RTNL_LINK_MULTICAST]      = st->multicast;
+               link->l_stats[RTNL_LINK_COLLISIONS]     = st->collisions;
+
+               link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st->rx_length_errors;
+               link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st->rx_over_errors;
+               link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st->rx_crc_errors;
+               link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st->rx_frame_errors;
+               link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st->rx_fifo_errors;
+               link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st->rx_missed_errors;
+
+               link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st->tx_aborted_errors;
+               link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st->tx_carrier_errors;
+               link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st->tx_fifo_errors;
+               link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st->tx_heartbeat_errors;
+               link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st->tx_window_errors;
+
+               link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st->rx_compressed;
+               link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st->tx_compressed;
+
+               link->ce_mask |= LINK_ATTR_STATS;
+       }
+
+       if (tb[IFLA_STATS64]) {
+               /*
+                * This structure contains 64bit parameters, and per the
+                * documentation in lib/attr.c, must not be accessed
+                * directly (because of alignment to 4 instead of 8).
+                * Therefore, copy the data to the stack and access it from
+                * there, where it will be aligned to 8.
+                */
+               struct rtnl_link_stats64 st;
+
+               nla_memcpy(&st, tb[IFLA_STATS64], 
+                          sizeof(struct rtnl_link_stats64));
+               
+               link->l_stats[RTNL_LINK_RX_PACKETS]     = st.rx_packets;
+               link->l_stats[RTNL_LINK_TX_PACKETS]     = st.tx_packets;
+               link->l_stats[RTNL_LINK_RX_BYTES]       = st.rx_bytes;
+               link->l_stats[RTNL_LINK_TX_BYTES]       = st.tx_bytes;
+               link->l_stats[RTNL_LINK_RX_ERRORS]      = st.rx_errors;
+               link->l_stats[RTNL_LINK_TX_ERRORS]      = st.tx_errors;
+               link->l_stats[RTNL_LINK_RX_DROPPED]     = st.rx_dropped;
+               link->l_stats[RTNL_LINK_TX_DROPPED]     = st.tx_dropped;
+               link->l_stats[RTNL_LINK_MULTICAST]      = st.multicast;
+               link->l_stats[RTNL_LINK_COLLISIONS]     = st.collisions;
+
+               link->l_stats[RTNL_LINK_RX_LEN_ERR]     = st.rx_length_errors;
+               link->l_stats[RTNL_LINK_RX_OVER_ERR]    = st.rx_over_errors;
+               link->l_stats[RTNL_LINK_RX_CRC_ERR]     = st.rx_crc_errors;
+               link->l_stats[RTNL_LINK_RX_FRAME_ERR]   = st.rx_frame_errors;
+               link->l_stats[RTNL_LINK_RX_FIFO_ERR]    = st.rx_fifo_errors;
+               link->l_stats[RTNL_LINK_RX_MISSED_ERR]  = st.rx_missed_errors;
+
+               link->l_stats[RTNL_LINK_TX_ABORT_ERR]   = st.tx_aborted_errors;
+               link->l_stats[RTNL_LINK_TX_CARRIER_ERR] = st.tx_carrier_errors;
+               link->l_stats[RTNL_LINK_TX_FIFO_ERR]    = st.tx_fifo_errors;
+               link->l_stats[RTNL_LINK_TX_HBEAT_ERR]   = st.tx_heartbeat_errors;
+               link->l_stats[RTNL_LINK_TX_WIN_ERR]     = st.tx_window_errors;
+
+               link->l_stats[RTNL_LINK_RX_COMPRESSED]  = st.rx_compressed;
+               link->l_stats[RTNL_LINK_TX_COMPRESSED]  = st.tx_compressed;
+
+               link->ce_mask |= LINK_ATTR_STATS;
+       }
+
+       if (tb[IFLA_TXQLEN]) {
+               link->l_txqlen = nla_get_u32(tb[IFLA_TXQLEN]);
+               link->ce_mask |= LINK_ATTR_TXQLEN;
+       }
+
+       if (tb[IFLA_MTU]) {
+               link->l_mtu = nla_get_u32(tb[IFLA_MTU]);
+               link->ce_mask |= LINK_ATTR_MTU;
+       }
+
+       if (tb[IFLA_ADDRESS]) {
+               link->l_addr = nl_addr_alloc_attr(tb[IFLA_ADDRESS], AF_UNSPEC);
+               if (link->l_addr == NULL) {
+                       err = -NLE_NOMEM;
+                       goto errout;
+               }
+               nl_addr_set_family(link->l_addr,
+                                  nl_addr_guess_family(link->l_addr));
+               link->ce_mask |= LINK_ATTR_ADDR;
+       }
+
+       if (tb[IFLA_BROADCAST]) {
+               link->l_bcast = nl_addr_alloc_attr(tb[IFLA_BROADCAST],
+                                                  AF_UNSPEC);
+               if (link->l_bcast == NULL) {
+                       err = -NLE_NOMEM;
+                       goto errout;
+               }
+               nl_addr_set_family(link->l_bcast,
+                                  nl_addr_guess_family(link->l_bcast));
+               link->ce_mask |= LINK_ATTR_BRD;
+       }
+
+       if (tb[IFLA_LINK]) {
+               link->l_link = nla_get_u32(tb[IFLA_LINK]);
+               link->ce_mask |= LINK_ATTR_LINK;
+       }
+
+       if (tb[IFLA_WEIGHT]) {
+               link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
+               link->ce_mask |= LINK_ATTR_WEIGHT;
+       }
+
+       if (tb[IFLA_QDISC]) {
+               nla_strlcpy(link->l_qdisc, tb[IFLA_QDISC], IFQDISCSIZ);
+               link->ce_mask |= LINK_ATTR_QDISC;
+       }
+
+       if (tb[IFLA_MAP]) {
+               nla_memcpy(&link->l_map, tb[IFLA_MAP], 
+                          sizeof(struct rtnl_link_ifmap));
+               link->ce_mask |= LINK_ATTR_MAP;
+       }
+
+       if (tb[IFLA_MASTER]) {
+               link->l_master = nla_get_u32(tb[IFLA_MASTER]);
+               link->ce_mask |= LINK_ATTR_MASTER;
+       }
+
+       if (tb[IFLA_CARRIER]) {
+               link->l_carrier = nla_get_u8(tb[IFLA_CARRIER]);
+               link->ce_mask |= LINK_ATTR_CARRIER;
+       }
+
+       if (tb[IFLA_OPERSTATE]) {
+               link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
+               link->ce_mask |= LINK_ATTR_OPERSTATE;
+       }
+
+       if (tb[IFLA_LINKMODE]) {
+               link->l_linkmode = nla_get_u8(tb[IFLA_LINKMODE]);
+               link->ce_mask |= LINK_ATTR_LINKMODE;
+       }
+
+       if (tb[IFLA_IFALIAS]) {
+               link->l_ifalias = nla_strdup(tb[IFLA_IFALIAS]);
+               if (link->l_ifalias == NULL) {
+                       err = -NLE_NOMEM;
+                       goto errout;
+               }
+               link->ce_mask |= LINK_ATTR_IFALIAS;
+       }
+
+       if (tb[IFLA_NUM_VF]) {
+               link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
+               link->ce_mask |= LINK_ATTR_NUM_VF;
+       }
+
+       if (tb[IFLA_LINKINFO]) {
+               struct nlattr *li[IFLA_INFO_MAX+1];
+
+               err = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
+                                      link_info_policy);
+               if (err < 0)
+                       goto errout;
+
+               if (li[IFLA_INFO_KIND]) {
+                       struct rtnl_link_info_ops *ops;
+                       char *kind;
+
+                       kind = nla_strdup(li[IFLA_INFO_KIND]);
+                       if (kind == NULL) {
+                               err = -NLE_NOMEM;
+                               goto errout;
+                       }
+                       link->l_info_kind = kind;
+                       link->ce_mask |= LINK_ATTR_LINKINFO;
+
+                       ops = rtnl_link_info_ops_lookup(kind);
+                       link->l_info_ops = ops;
+
+                       if (ops) {
+                               if (ops->io_parse &&
+                                   (li[IFLA_INFO_DATA] || li[IFLA_INFO_XSTATS])) {
+                                       err = ops->io_parse(link, li[IFLA_INFO_DATA],
+                                                           li[IFLA_INFO_XSTATS]);
+                                       if (err < 0)
+                                               goto errout;
+                               } else {
+                                       /* XXX: Warn about unparsed info? */
+                               }
+                       }
+               }
+               link->ce_mask |= LINK_ATTR_LINKINFO;
+       }
+
+       if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
+               err = af_ops->ao_parse_protinfo(link, tb[IFLA_PROTINFO],
+                                               link->l_af_data[link->l_family]);
+               if (err < 0)
+                       goto errout;
+               link->ce_mask |= LINK_ATTR_PROTINFO;
+       }
+
+       if (tb[IFLA_AF_SPEC]) {
+               struct nlattr *af_attr;
+               int remaining;
+
+               nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
+                       af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
+                       if (af_ops && af_ops->ao_parse_af) {
+                               char *af_data = link->l_af_data[nla_type(af_attr)];
+
+                               err = af_ops->ao_parse_af(link, af_attr, af_data);
+                               if (err < 0)
+                                       goto errout;
+                       }
+
+               }
+               link->ce_mask |= LINK_ATTR_AF_SPEC;
+       }
+
+       if (tb[IFLA_PROMISCUITY]) {
+               link->l_promiscuity = nla_get_u32(tb[IFLA_PROMISCUITY]);
+               link->ce_mask |= LINK_ATTR_PROMISCUITY;
+       }
+
+       if (tb[IFLA_NUM_TX_QUEUES]) {
+               link->l_num_tx_queues = nla_get_u32(tb[IFLA_NUM_TX_QUEUES]);
+               link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
+       }
+
+       if (tb[IFLA_NUM_RX_QUEUES]) {
+               link->l_num_rx_queues = nla_get_u32(tb[IFLA_NUM_RX_QUEUES]);
+               link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
+       }
+
+       if (tb[IFLA_GROUP]) {
+               link->l_group = nla_get_u32(tb[IFLA_GROUP]);
+               link->ce_mask |= LINK_ATTR_GROUP;
+       }
+
+       err = pp->pp_cb((struct nl_object *) link, pp);
+errout:
+       rtnl_link_af_ops_put(af_ops);
+       rtnl_link_put(link);
+       return err;
+}
+
+static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+       int family = cache->c_iarg1;
+
+       return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
+}
+
+static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+       char buf[128];
+       struct nl_cache *cache = obj->ce_cache;
+       struct rtnl_link *link = (struct rtnl_link *) obj;
+
+       nl_dump_line(p, "%s %s ", link->l_name,
+                    nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
+
+       if (link->l_addr && !nl_addr_iszero(link->l_addr))
+               nl_dump(p, "%s ", nl_addr2str(link->l_addr, buf, sizeof(buf)));
+
+       if (link->ce_mask & LINK_ATTR_MASTER) {
+               struct rtnl_link *master = rtnl_link_get(cache, link->l_master);
+               nl_dump(p, "master %s ", master ? master->l_name : "inv");
+               if (master)
+                       rtnl_link_put(master);
+       }
+
+       rtnl_link_flags2str(link->l_flags, buf, sizeof(buf));
+       if (buf[0])
+               nl_dump(p, "<%s> ", buf);
+
+       if (link->ce_mask & LINK_ATTR_LINK) {
+               struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
+               nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
+               if (ll)
+                       rtnl_link_put(ll);
+       }
+
+       if (link->ce_mask & LINK_ATTR_GROUP)
+               nl_dump(p, "group %u ", link->l_group);
+
+       if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_LINE])
+               link->l_info_ops->io_dump[NL_DUMP_LINE](link, p);
+
+       do_foreach_af(link, af_dump_line, p);
+
+       nl_dump(p, "\n");
+}
+
+static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_link *link = (struct rtnl_link *) obj;
+       char buf[64];
+
+       link_dump_line(obj, p);
+
+       nl_dump_line(p, "    mtu %u ", link->l_mtu);
+       nl_dump(p, "txqlen %u weight %u ", link->l_txqlen, link->l_weight);
+
+       if (link->ce_mask & LINK_ATTR_QDISC)
+               nl_dump(p, "qdisc %s ", link->l_qdisc);
+
+       if (link->ce_mask & LINK_ATTR_MAP && link->l_map.lm_irq)
+               nl_dump(p, "irq %u ", link->l_map.lm_irq);
+
+       if (link->ce_mask & LINK_ATTR_IFINDEX)
+               nl_dump(p, "index %u ", link->l_index);
+
+       if (link->ce_mask & LINK_ATTR_PROMISCUITY && link->l_promiscuity > 0)
+               nl_dump(p, "promisc-mode (%u users) ", link->l_promiscuity);
+
+       nl_dump(p, "\n");
+
+       if (link->ce_mask & LINK_ATTR_IFALIAS)
+               nl_dump_line(p, "    alias %s\n", link->l_ifalias);
+
+       nl_dump_line(p, "    ");
+
+       if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
+               nl_dump(p, "txq %u ", link->l_num_tx_queues);
+
+       if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
+               nl_dump(p, "rxq %u ", link->l_num_rx_queues);
+
+       if (link->ce_mask & LINK_ATTR_BRD)
+               nl_dump(p, "brd %s ", nl_addr2str(link->l_bcast, buf,
+                                                  sizeof(buf)));
+
+       if ((link->ce_mask & LINK_ATTR_OPERSTATE) &&
+           link->l_operstate != IF_OPER_UNKNOWN) {
+               rtnl_link_operstate2str(link->l_operstate, buf, sizeof(buf));
+               nl_dump(p, "state %s ", buf);
+       }
+
+       if (link->ce_mask & LINK_ATTR_NUM_VF)
+               nl_dump(p, "num-vf %u ", link->l_num_vf);
+
+       nl_dump(p, "mode %s ",
+               rtnl_link_mode2str(link->l_linkmode, buf, sizeof(buf)));
+
+       nl_dump(p, "carrier %s",
+               rtnl_link_carrier2str(link->l_carrier, buf, sizeof(buf)));
+
+       nl_dump(p, "\n");
+
+       if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
+               link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
+
+       do_foreach_af(link, af_dump_details, p);
+}
+
+static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_link *link = (struct rtnl_link *) obj;
+       char *unit, fmt[64];
+       float res;
+       
+       link_dump_details(obj, p);
+
+       nl_dump_line(p, "    Stats:    bytes    packets     errors "
+                       "   dropped   fifo-err compressed\n");
+
+       res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_RX_BYTES], &unit);
+
+       strcpy(fmt, "     RX %X.2f %s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n");
+       fmt[9] = *unit == 'B' ? '9' : '7';
+       
+       nl_dump_line(p, fmt, res, unit,
+               link->l_stats[RTNL_LINK_RX_PACKETS],
+               link->l_stats[RTNL_LINK_RX_ERRORS],
+               link->l_stats[RTNL_LINK_RX_DROPPED],
+               link->l_stats[RTNL_LINK_RX_FIFO_ERR],
+               link->l_stats[RTNL_LINK_RX_COMPRESSED]);
+
+       res = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_TX_BYTES], &unit);
+
+       strcpy(fmt, "     TX %X.2f %s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n");
+       fmt[9] = *unit == 'B' ? '9' : '7';
+       
+       nl_dump_line(p, fmt, res, unit,
+               link->l_stats[RTNL_LINK_TX_PACKETS],
+               link->l_stats[RTNL_LINK_TX_ERRORS],
+               link->l_stats[RTNL_LINK_TX_DROPPED],
+               link->l_stats[RTNL_LINK_TX_FIFO_ERR],
+               link->l_stats[RTNL_LINK_TX_COMPRESSED]);
+
+       nl_dump_line(p, "    Errors:  length       over        crc "
+                       "     frame     missed  multicast\n");
+
+       nl_dump_line(p, "     RX  %10" PRIu64 " %10" PRIu64 " %10"
+                               PRIu64 " %10" PRIu64 " %10" PRIu64 " %10"
+                               PRIu64 "\n",
+               link->l_stats[RTNL_LINK_RX_LEN_ERR],
+               link->l_stats[RTNL_LINK_RX_OVER_ERR],
+               link->l_stats[RTNL_LINK_RX_CRC_ERR],
+               link->l_stats[RTNL_LINK_RX_FRAME_ERR],
+               link->l_stats[RTNL_LINK_RX_MISSED_ERR],
+               link->l_stats[RTNL_LINK_MULTICAST]);
+
+       nl_dump_line(p, "            aborted    carrier  heartbeat "
+                       "    window  collision\n");
+       
+       nl_dump_line(p, "     TX  %10" PRIu64 " %10" PRIu64 " %10"
+                       PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_TX_ABORT_ERR],
+               link->l_stats[RTNL_LINK_TX_CARRIER_ERR],
+               link->l_stats[RTNL_LINK_TX_HBEAT_ERR],
+               link->l_stats[RTNL_LINK_TX_WIN_ERR],
+               link->l_stats[RTNL_LINK_COLLISIONS]);
+
+       if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_STATS])
+               link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
+
+       do_foreach_af(link, af_dump_stats, p);
+}
+
+#if 0
+static int link_handle_event(struct nl_object *a, struct rtnl_link_event_cb *cb)
+{
+       struct rtnl_link *l = (struct rtnl_link *) a;
+       struct nl_cache *c = dp_cache(a);
+       int nevents = 0;
+
+       if (l->l_change == ~0U) {
+               if (l->ce_msgtype == RTM_NEWLINK)
+                       cb->le_register(l);
+               else
+                       cb->le_unregister(l);
+
+               return 1;
+       }
+
+       if (l->l_change & IFF_SLAVE) {
+               if (l->l_flags & IFF_SLAVE) {
+                       struct rtnl_link *m = rtnl_link_get(c, l->l_master);
+                       cb->le_new_bonding(l, m);
+                       if (m)
+                               rtnl_link_put(m);
+               } else
+                       cb->le_cancel_bonding(l);
+       }
+
+#if 0
+       if (l->l_change & IFF_UP && l->l_change & IFF_RUNNING)
+               dp_dump_line(p, line++, "link %s changed state to %s.\n",
+                       l->l_name, l->l_flags & IFF_UP ? "up" : "down");
+
+       if (l->l_change & IFF_PROMISC) {
+               dp_new_line(p, line++);
+               dp_dump(p, "link %s %s promiscuous mode.\n",
+                   l->l_name, l->l_flags & IFF_PROMISC ? "entered" : "left");
+       }
+
+       if (line == 0)
+               dp_dump_line(p, line++, "link %s sent unknown event.\n",
+                            l->l_name);
+#endif
+
+       return nevents;
+}
+#endif
+
+
+static void link_keygen(struct nl_object *obj, uint32_t *hashkey,
+        uint32_t table_sz)
+{
+       struct rtnl_link *link = (struct rtnl_link *) obj;
+       unsigned int lkey_sz;
+       struct link_hash_key {
+               uint32_t        l_index;
+               uint32_t        l_family;
+       } __attribute__((packed)) lkey;
+
+       lkey_sz = sizeof(lkey);
+       lkey.l_index = link->l_index;
+       lkey.l_family = link->l_family;
+
+       *hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
+
+       NL_DBG(5, "link %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
+              link, lkey.l_index, lkey.l_family, lkey_sz, *hashkey);
+
+       return;
+}
+
+static int link_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       struct rtnl_link *a = (struct rtnl_link *) _a;
+       struct rtnl_link *b = (struct rtnl_link *) _b;
+       int diff = 0;
+
+#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= LINK_DIFF(IFINDEX,      a->l_index != b->l_index);
+       diff |= LINK_DIFF(MTU,          a->l_mtu != b->l_mtu);
+       diff |= LINK_DIFF(LINK,         a->l_link != b->l_link);
+       diff |= LINK_DIFF(TXQLEN,       a->l_txqlen != b->l_txqlen);
+       diff |= LINK_DIFF(WEIGHT,       a->l_weight != b->l_weight);
+       diff |= LINK_DIFF(MASTER,       a->l_master != b->l_master);
+       diff |= LINK_DIFF(FAMILY,       a->l_family != b->l_family);
+       diff |= LINK_DIFF(OPERSTATE,    a->l_operstate != b->l_operstate);
+       diff |= LINK_DIFF(LINKMODE,     a->l_linkmode != b->l_linkmode);
+       diff |= LINK_DIFF(QDISC,        strcmp(a->l_qdisc, b->l_qdisc));
+       diff |= LINK_DIFF(IFNAME,       strcmp(a->l_name, b->l_name));
+       diff |= LINK_DIFF(ADDR,         nl_addr_cmp(a->l_addr, b->l_addr));
+       diff |= LINK_DIFF(BRD,          nl_addr_cmp(a->l_bcast, b->l_bcast));
+       diff |= LINK_DIFF(IFALIAS,      strcmp(a->l_ifalias, b->l_ifalias));
+       diff |= LINK_DIFF(NUM_VF,       a->l_num_vf != b->l_num_vf);
+       diff |= LINK_DIFF(PROMISCUITY,  a->l_promiscuity != b->l_promiscuity);
+       diff |= LINK_DIFF(NUM_TX_QUEUES,a->l_num_tx_queues != b->l_num_tx_queues);
+       diff |= LINK_DIFF(NUM_RX_QUEUES,a->l_num_rx_queues != b->l_num_rx_queues);
+       diff |= LINK_DIFF(GROUP,        a->l_group != b->l_group);
+
+       if (flags & LOOSE_COMPARISON)
+               diff |= LINK_DIFF(FLAGS,
+                                 (a->l_flags ^ b->l_flags) & b->l_flag_mask);
+       else
+               diff |= LINK_DIFF(FLAGS, a->l_flags != b->l_flags);
+
+       /*
+        * Compare LINK_ATTR_PROTINFO af_data
+        */
+       if (a->l_family == b->l_family) {
+               if (rtnl_link_af_data_compare(a, b, a->l_family) != 0)
+                       goto protinfo_mismatch;
+       }
+
+out:
+       return diff;
+
+protinfo_mismatch:
+       diff |= LINK_DIFF(PROTINFO, 1);
+       goto out;
+
+#undef LINK_DIFF
+}
+
+static const struct trans_tbl link_attrs[] = {
+       __ADD(LINK_ATTR_MTU, mtu)
+       __ADD(LINK_ATTR_LINK, link)
+       __ADD(LINK_ATTR_TXQLEN, txqlen)
+       __ADD(LINK_ATTR_WEIGHT, weight)
+       __ADD(LINK_ATTR_MASTER, master)
+       __ADD(LINK_ATTR_QDISC, qdisc)
+       __ADD(LINK_ATTR_MAP, map)
+       __ADD(LINK_ATTR_ADDR, address)
+       __ADD(LINK_ATTR_BRD, broadcast)
+       __ADD(LINK_ATTR_FLAGS, flags)
+       __ADD(LINK_ATTR_IFNAME, name)
+       __ADD(LINK_ATTR_IFINDEX, ifindex)
+       __ADD(LINK_ATTR_FAMILY, family)
+       __ADD(LINK_ATTR_ARPTYPE, arptype)
+       __ADD(LINK_ATTR_STATS, stats)
+       __ADD(LINK_ATTR_CHANGE, change)
+       __ADD(LINK_ATTR_OPERSTATE, operstate)
+       __ADD(LINK_ATTR_LINKMODE, linkmode)
+       __ADD(LINK_ATTR_IFALIAS, ifalias)
+       __ADD(LINK_ATTR_NUM_VF, num_vf)
+       __ADD(LINK_ATTR_PROMISCUITY, promiscuity)
+       __ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues)
+       __ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues)
+       __ADD(LINK_ATTR_GROUP, group)
+       __ADD(LINK_ATTR_CARRIER, carrier)
+};
+
+static char *link_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, link_attrs,
+                          ARRAY_SIZE(link_attrs));
+}
+
+/**
+ * @name Get / List
+ * @{
+ */
+
+
+/**
+ * Allocate link cache and fill in all configured links.
+ * @arg sk             Netlink socket.
+ * @arg family         Link address family or AF_UNSPEC
+ * @arg result         Pointer to store resulting cache.
+ *
+ * Allocates and initializes a new link cache. A netlink message is sent to
+ * the kernel requesting a full dump of all configured links. The returned
+ * messages are parsed and filled into the cache. If the operation succeeds
+ * the resulting cache will a link object for each link configured in the
+ * kernel.
+ *
+ * If \c family is set to an address family other than \c AF_UNSPEC the
+ * contents of the cache can be limited to a specific address family.
+ * Currently the following address families are supported:
+ * - AF_BRIDGE
+ * - AF_INET6
+ *
+ * @route_doc{link_list, Get List of Links}
+ * @see rtnl_link_get()
+ * @see rtnl_link_get_by_name()
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
+{
+       struct nl_cache * cache;
+       int err;
+       
+       cache = nl_cache_alloc(&rtnl_link_ops);
+       if (!cache)
+               return -NLE_NOMEM;
+
+       cache->c_iarg1 = family;
+       
+       if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+               nl_cache_free(cache);
+               return err;
+       }
+
+       *result = cache;
+       return 0;
+}
+
+/**
+ * Lookup link in cache by interface index
+ * @arg cache          Link cache
+ * @arg ifindex                Interface index
+ *
+ * Searches through the provided cache looking for a link with matching
+ * interface index.
+ *
+ * @attention The reference counter of the returned link object will be
+ *            incremented. Use rtnl_link_put() to release the reference.
+ *
+ * @route_doc{link_list, Get List of Links}
+ * @see rtnl_link_get_by_name()
+ * @return Link object or NULL if no match was found.
+ */
+struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex)
+{
+       struct rtnl_link *link;
+
+       if (cache->c_ops != &rtnl_link_ops)
+               return NULL;
+
+       nl_list_for_each_entry(link, &cache->c_items, ce_list) {
+               if (link->l_index == ifindex) {
+                       nl_object_get((struct nl_object *) link);
+                       return link;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Lookup link in cache by link name
+ * @arg cache          Link cache
+ * @arg name           Name of link
+ *
+ * Searches through the provided cache looking for a link with matching
+ * link name
+ *
+ * @attention The reference counter of the returned link object will be
+ *            incremented. Use rtnl_link_put() to release the reference.
+ *
+ * @route_doc{link_list, Get List of Links}
+ * @see rtnl_link_get()
+ * @return Link object or NULL if no match was found.
+ */
+struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache,
+                                        const char *name)
+{
+       struct rtnl_link *link;
+
+       if (cache->c_ops != &rtnl_link_ops)
+               return NULL;
+
+       nl_list_for_each_entry(link, &cache->c_items, ce_list) {
+               if (!strcmp(name, link->l_name)) {
+                       nl_object_get((struct nl_object *) link);
+                       return link;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Construct RTM_GETLINK netlink message
+ * @arg ifindex                Interface index
+ * @arg name           Name of link
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_get_kernel()
+ * with the exception that it will not send the message but return it in
+ * the provided return pointer instead.
+ *
+ * @see rtnl_link_get_kernel()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_get_request(int ifindex, const char *name,
+                               struct nl_msg **result)
+{
+       struct ifinfomsg ifi;
+       struct nl_msg *msg;
+
+       if (ifindex <= 0 && !name) {
+               APPBUG("ifindex or name must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       memset(&ifi, 0, sizeof(ifi));
+
+       if (!(msg = nlmsg_alloc_simple(RTM_GETLINK, 0)))
+               return -NLE_NOMEM;
+
+       if (ifindex > 0)
+               ifi.ifi_index = ifindex;
+
+       if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       if (name)
+               NLA_PUT_STRING(msg, IFLA_IFNAME, name);
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * Get a link object directly from kernel
+ * @arg sk             Netlink socket
+ * @arg ifindex                Interface index
+ * @arg name           Name of link
+ * @arg result         Pointer to store resulting link object
+ *
+ * This function builds a \c RTM_GETLINK netlink message to request
+ * a specific link directly from the kernel. The returned answer is
+ * parsed into a struct rtnl_link object and returned via the result
+ * pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
+ * found.
+ *
+ * @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)}
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
+                        struct rtnl_link **result)
+{
+       struct nl_msg *msg = NULL;
+       struct nl_object *obj;
+       int err;
+
+       if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
+               return err;
+
+       /* We have used link_msg_parser(), object is definitely a link */
+       *result = (struct rtnl_link *) obj;
+
+       /* If an object has been returned, we also need to wait for the ACK */
+        if (err == 0 && obj)
+                wait_for_ack(sk);
+
+       return 0;
+}
+
+/**
+ * Translate interface index to corresponding link name
+ * @arg cache          Link cache
+ * @arg ifindex                Interface index
+ * @arg dst            String to store name
+ * @arg len            Length of destination string
+ *
+ * Translates the specified interface index to the corresponding
+ * link name and stores the name in the destination string.
+ *
+ * @route_doc{link_translate_ifindex, Translating interface index to link name}
+ * @see rtnl_link_name2i()
+ * @return Name of link or NULL if no match was found.
+ */
+char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst,
+                       size_t len)
+{
+       struct rtnl_link *link = rtnl_link_get(cache, ifindex);
+
+       if (link) {
+               strncpy(dst, link->l_name, len - 1);
+               rtnl_link_put(link);
+               return dst;
+       }
+
+       return NULL;
+}
+
+/**
+ * Translate link name to corresponding interface index
+ * @arg cache          Link cache
+ * @arg name           Name of link
+ *
+ * @route_doc{link_translate_ifindex, Translating interface index to link name}
+ * @see rtnl_link_i2name()
+ * @return Interface index or 0 if no match was found.
+ */
+int rtnl_link_name2i(struct nl_cache *cache, const char *name)
+{
+       int ifindex = 0;
+       struct rtnl_link *link;
+       
+       link = rtnl_link_get_by_name(cache, name);
+       if (link) {
+               ifindex = link->l_index;
+               rtnl_link_put(link);
+       }
+
+       return ifindex;
+}
+
+/** @} */
+
+static int build_link_msg(int cmd, struct ifinfomsg *hdr,
+                         struct rtnl_link *link, int flags, struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct nlattr *af_spec;
+
+       msg = nlmsg_alloc_simple(cmd, flags);
+       if (!msg)
+               return -NLE_NOMEM;
+
+       if (nlmsg_append(msg, hdr, sizeof(*hdr), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       if (link->ce_mask & LINK_ATTR_ADDR)
+               NLA_PUT_ADDR(msg, IFLA_ADDRESS, link->l_addr);
+
+       if (link->ce_mask & LINK_ATTR_BRD)
+               NLA_PUT_ADDR(msg, IFLA_BROADCAST, link->l_bcast);
+
+       if (link->ce_mask & LINK_ATTR_MTU)
+               NLA_PUT_U32(msg, IFLA_MTU, link->l_mtu);
+
+       if (link->ce_mask & LINK_ATTR_TXQLEN)
+               NLA_PUT_U32(msg, IFLA_TXQLEN, link->l_txqlen);
+
+       if (link->ce_mask & LINK_ATTR_WEIGHT)
+               NLA_PUT_U32(msg, IFLA_WEIGHT, link->l_weight);
+
+       if (link->ce_mask & LINK_ATTR_IFNAME)
+               NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
+
+       if (link->ce_mask & LINK_ATTR_OPERSTATE)
+               NLA_PUT_U8(msg, IFLA_OPERSTATE, link->l_operstate);
+
+       if (link->ce_mask & LINK_ATTR_CARRIER)
+               NLA_PUT_U8(msg, IFLA_CARRIER, link->l_carrier);
+
+       if (link->ce_mask & LINK_ATTR_LINKMODE)
+               NLA_PUT_U8(msg, IFLA_LINKMODE, link->l_linkmode);
+
+       if (link->ce_mask & LINK_ATTR_IFALIAS)
+               NLA_PUT_STRING(msg, IFLA_IFALIAS, link->l_ifalias);
+
+       if (link->ce_mask & LINK_ATTR_LINK)
+               NLA_PUT_U32(msg, IFLA_LINK, link->l_link);
+
+       if (link->ce_mask & LINK_ATTR_MASTER)
+               NLA_PUT_U32(msg, IFLA_MASTER, link->l_master);
+
+       if (link->ce_mask & LINK_ATTR_NUM_TX_QUEUES)
+               NLA_PUT_U32(msg, IFLA_NUM_TX_QUEUES, link->l_num_tx_queues);
+
+       if (link->ce_mask & LINK_ATTR_NUM_RX_QUEUES)
+               NLA_PUT_U32(msg, IFLA_NUM_RX_QUEUES, link->l_num_rx_queues);
+
+       if (link->ce_mask & LINK_ATTR_GROUP)
+               NLA_PUT_U32(msg, IFLA_GROUP, link->l_group);
+
+       if (link->ce_mask & LINK_ATTR_LINKINFO) {
+               struct nlattr *info;
+
+               if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
+                       goto nla_put_failure;
+
+               NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_kind);
+
+               if (link->l_info_ops) {
+                       if (link->l_info_ops->io_put_attrs &&
+                           link->l_info_ops->io_put_attrs(msg, link) < 0)
+                               goto nla_put_failure;
+               }
+
+               nla_nest_end(msg, info);
+       }
+
+       if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
+               goto nla_put_failure;
+
+       if (do_foreach_af(link, af_fill, msg) < 0)
+               goto nla_put_failure;
+
+       nla_nest_end(msg, af_spec);
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Add / Modify
+ * @{
+ */
+
+/**
+ * Build a netlink message requesting the addition of new virtual link
+ * @arg link           new link to add
+ * @arg flags          additional netlink message flags
+ * @arg result         pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_add() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_link_add()
+ *
+ * @note This operation is not supported on all kernel versions.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_add_request(struct rtnl_link *link, int flags,
+                               struct nl_msg **result)
+{
+       struct ifinfomsg ifi = {
+               .ifi_family = link->l_family,
+               .ifi_index = link->l_index,
+               .ifi_flags = link->l_flags,
+       };
+
+       return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
+}
+
+/**
+ * Add virtual link
+ * @arg sk             netlink socket.
+ * @arg link           new link to add
+ * @arg flags          additional netlink message flags
+ *
+ * Builds a \c RTM_NEWLINK netlink message requesting the addition of
+ * a new virtual link.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @copydoc auto_ack_warning
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       err = rtnl_link_build_add_request(link, flags, &msg);
+       if (err < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build a netlink message requesting the modification of link
+ * @arg orig           original link to change
+ * @arg changes                link containing the changes to be made
+ * @arg flags          additional netlink message flags
+ * @arg result         pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_change() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_link_change()
+ *
+ * @note The resulting message will have message type set to RTM_NEWLINK
+ *       which may not work with older kernels. You may have to modify it
+ *       to RTM_SETLINK (does not allow changing link info attributes) to
+ *       have the change request work with older kernels.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_change_request(struct rtnl_link *orig,
+                                  struct rtnl_link *changes, int flags,
+                                  struct nl_msg **result)
+{
+       struct ifinfomsg ifi = {
+               .ifi_family = orig->l_family,
+               .ifi_index = orig->l_index,
+       };
+       int err;
+
+       if (changes->ce_mask & LINK_ATTR_FLAGS) {
+               ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
+               ifi.ifi_flags |= changes->l_flags;
+       }
+
+       if (changes->l_family && changes->l_family != orig->l_family) {
+               APPBUG("link change: family is immutable");
+               return -NLE_IMMUTABLE;
+       }
+
+       /* Avoid unnecessary name change requests */
+       if (orig->ce_mask & LINK_ATTR_IFINDEX &&
+           orig->ce_mask & LINK_ATTR_IFNAME &&
+           changes->ce_mask & LINK_ATTR_IFNAME &&
+           !strcmp(orig->l_name, changes->l_name))
+               changes->ce_mask &= ~LINK_ATTR_IFNAME;
+
+       if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
+               goto errout;
+
+       return 0;
+
+errout:
+       return err;
+}
+
+/**
+ * Change link
+ * @arg sk             netlink socket.
+ * @arg orig           original link to be changed
+ * @arg changes                link containing the changes to be made
+ * @arg flags          additional netlink message flags
+ *
+ * Builds a \c RTM_NEWLINK netlink message requesting the change of
+ * a network link. If -EOPNOTSUPP is returned by the kernel, the
+ * message type will be changed to \c RTM_SETLINK and the message is
+ * resent to work around older kernel versions.
+ *
+ * The link to be changed is looked up based on the interface index
+ * supplied in the \p orig link. Optionaly the link name is used but
+ * only if no interface index is provided, otherwise providing an
+ * link name will result in the link name being changed.
+ *
+ * If no matching link exists, the function will return
+ * -NLE_OBJ_NOTFOUND.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @copydoc auto_ack_warning
+ *
+ * @note The link name can only be changed if the link has been put
+ *       in opertional down state. (~IF_UP)
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
+                    struct rtnl_link *changes, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       err = rtnl_link_build_change_request(orig, changes, flags, &msg);
+       if (err < 0)
+               return err;
+
+retry:
+       err = nl_send_auto_complete(sk, msg);
+       if (err < 0)
+               goto errout;
+
+       err = wait_for_ack(sk);
+       if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
+               msg->nm_nlh->nlmsg_type = RTM_SETLINK;
+               goto retry;
+       }
+
+errout:
+       nlmsg_free(msg);
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Delete
+ * @{
+ */
+
+/**
+ * Build a netlink message requesting the deletion of a link
+ * @arg link           Link to delete
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_link_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_link_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_build_delete_request(const struct rtnl_link *link,
+                                  struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct ifinfomsg ifi = {
+               .ifi_index = link->l_index,
+       };
+
+       if (!(link->ce_mask & (LINK_ATTR_IFINDEX | LINK_ATTR_IFNAME))) {
+               APPBUG("ifindex or name must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       if (!(msg = nlmsg_alloc_simple(RTM_DELLINK, 0)))
+               return -NLE_NOMEM;
+
+       if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       if (link->ce_mask & LINK_ATTR_IFNAME)
+               NLA_PUT_STRING(msg, IFLA_IFNAME, link->l_name);
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * Delete link
+ * @arg sk             Netlink socket
+ * @arg link           Link to delete
+ *
+ * Builds a \c RTM_DELLINK netlink message requesting the deletion of
+ * a network link which has been previously added to the kernel and
+ * sends the message to the kernel.
+ *
+ * If no matching link exists, the function will return
+ * -NLE_OBJ_NOTFOUND.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @copydoc auto_ack_warning
+ *
+ * @note Only virtual links such as dummy interface or vlan interfaces
+ *       can be deleted. It is not possible to delete physical interfaces
+ *       such as ethernet interfaces or the loopback device.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_link_build_delete_request(link, &msg)) < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Link Object
+ * @{
+ */
+
+/**
+ * Allocate link object
+ *
+ * @see rtnl_link_put()
+ * @return New link object or NULL if allocation failed
+ */
+struct rtnl_link *rtnl_link_alloc(void)
+{
+       return (struct rtnl_link *) nl_object_alloc(&link_obj_ops);
+}
+
+/**
+ * Return a link object reference
+ * @arg link           Link object
+ */
+void rtnl_link_put(struct rtnl_link *link)
+{
+       nl_object_put((struct nl_object *) link);
+}
+
+/**
+ * Set name of link object
+ * @arg link           Link object
+ * @arg name           New name
+ *
+ * @note To change the name of a link in the kernel, set the interface
+ *       index to the link you wish to change, modify the link name using
+ *       this function and pass the link object to rtnl_link_change() or
+ *       rtnl_link_add().
+ *
+ * @route_doc{link_attr_name, Link Name}
+ * @see rtnl_link_get_name()
+ * @see rtnl_link_set_ifindex()
+ */
+void rtnl_link_set_name(struct rtnl_link *link, const char *name)
+{
+       strncpy(link->l_name, name, sizeof(link->l_name) - 1);
+       link->ce_mask |= LINK_ATTR_IFNAME;
+}
+
+/**
+ * Return name of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_name, Link Name}
+ * @see rtnl_link_set_name()
+ * @return Link name or NULL if name is not specified
+ */
+char *rtnl_link_get_name(struct rtnl_link *link)
+{
+       return link->ce_mask & LINK_ATTR_IFNAME ? link->l_name : NULL;
+}
+
+/**
+ * Set the group identifier of a link object
+ * @arg link           Link object
+ * @arg group          Group identifier
+ */
+void rtnl_link_set_group(struct rtnl_link *link, uint32_t group)
+{
+       link->l_group = group;
+       link->ce_mask |= LINK_ATTR_GROUP;
+}
+
+/**
+ * Return the group identifier of link object
+ * @arg link           Link object
+ *
+ * @return Group identifier or 0 if not set.
+ */
+uint32_t rtnl_link_get_group(struct rtnl_link *link)
+{
+       return link->l_group;
+}
+
+static inline void __assign_addr(struct rtnl_link *link, struct nl_addr **pos,
+                                struct nl_addr *new, int flag)
+{
+       if (*pos)
+               nl_addr_put(*pos);
+
+       nl_addr_get(new);
+       *pos = new;
+
+       link->ce_mask |= flag;
+}
+
+/**
+ * Set link layer address of link object
+ * @arg link           Link object
+ * @arg addr           New link layer address
+ *
+ * The function increments the reference counter of the address object
+ * and overwrites any existing link layer address previously assigned.
+ *
+ * @route_doc{link_attr_address, Link layer address}
+ * @see rtnl_link_get_addr()
+ */
+void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr)
+{
+       __assign_addr(link, &link->l_addr, addr, LINK_ATTR_ADDR);
+}
+
+/**
+ * Return link layer address of link object
+ * @arg link           Link object
+ *
+ * @copydoc pointer_lifetime_warning
+ * @route_doc{link_attr_address, Link Layer Address}
+ * @see rtnl_link_set_addr()
+ * @return Link layer address or NULL if not set.
+ */
+struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link)
+{
+       return link->ce_mask & LINK_ATTR_ADDR ? link->l_addr : NULL;
+}
+
+/**
+ * Set link layer broadcast address of link object
+ * @arg link           Link object
+ * @arg addr           New broadcast address
+ *
+ * The function increments the reference counter of the address object
+ * and overwrites any existing link layer broadcast address previously
+ * assigned.
+ *
+ * @route_doc{link_attr_broadcast, Link Layer Broadcast Address}
+ * @see rtnl_link_get_broadcast()
+ */
+void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr)
+{
+       __assign_addr(link, &link->l_bcast, addr, LINK_ATTR_BRD);
+}
+
+/**
+ * Return link layer broadcast address of link object
+ * @arg link           Link object
+ *
+ * @copydoc pointer_lifetime_warning
+ * @route_doc{link_attr_address, Link Layer Address}
+ * @see rtnl_link_set_broadcast()
+ * @return Link layer address or NULL if not set.
+ */
+struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link)
+{
+       return link->ce_mask & LINK_ATTR_BRD ? link->l_bcast : NULL;
+}
+
+/**
+ * Set flags of link object
+ * @arg link           Link object
+ * @arg flags          Flags
+ *
+ * @see rtnl_link_get_flags()
+ * @see rtnl_link_unset_flags()
+ */
+void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags)
+{
+       link->l_flag_mask |= flags;
+       link->l_flags |= flags;
+       link->ce_mask |= LINK_ATTR_FLAGS;
+}
+
+/**
+ * Unset flags of link object
+ * @arg link           Link object
+ * @arg flags          Flags
+ *
+ * @see rtnl_link_set_flags()
+ * @see rtnl_link_get_flags()
+ */
+void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags)
+{
+       link->l_flag_mask |= flags;
+       link->l_flags &= ~flags;
+       link->ce_mask |= LINK_ATTR_FLAGS;
+}
+
+/**
+ * Return flags of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_flags, Link Flags}
+ * @see rtnl_link_set_flags()
+ * @see rtnl_link_unset_flags()
+ * @return Link flags or 0 if none have been set.
+ */
+unsigned int rtnl_link_get_flags(struct rtnl_link *link)
+{
+       return link->l_flags;
+}
+
+/**
+ * Set address family of link object
+ *
+ * @see rtnl_link_get_family()
+ */
+void rtnl_link_set_family(struct rtnl_link *link, int family)
+{
+       link->l_family = family;
+       link->ce_mask |= LINK_ATTR_FAMILY;
+
+       if (link->l_af_ops)
+               af_free(link, link->l_af_ops,
+                       link->l_af_data[link->l_af_ops->ao_family], NULL);
+
+       link->l_af_ops = af_lookup_and_alloc(link, family);
+}
+
+/**
+ * Return address family of link object
+ * @arg link           Link object
+ *
+ * @see rtnl_link_set_family()
+ * @return Address family or \c AF_UNSPEC if not specified.
+ */
+int rtnl_link_get_family(struct rtnl_link *link)
+{
+       return link->ce_mask & LINK_ATTR_FAMILY ? link->l_family : AF_UNSPEC;
+}
+
+/**
+ * Set hardware type of link object
+ * @arg link           Link object
+ * @arg arptype                New hardware type \c (ARPHRD_*)
+ *
+ * @route_doc{link_attr_arptype, Hardware Type}
+ * @copydoc read_only_attribute
+ * @see rtnl_link_get_arptype()
+ */
+void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype)
+{
+       link->l_arptype = arptype;
+       link->ce_mask |= LINK_ATTR_ARPTYPE;
+}
+
+/**
+ * Get hardware type of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_arptype, Hardware Type}
+ * @see rtnl_link_set_arptype()
+ * @return Hardware type \c (ARPHRD_ETHER *) or \c ARPHRD_VOID
+ */
+unsigned int rtnl_link_get_arptype(struct rtnl_link *link)
+{
+       if (link->ce_mask & LINK_ATTR_ARPTYPE)
+               return link->l_arptype;
+       else
+               return ARPHRD_VOID;
+}
+
+/**
+ * Set interface index of link object
+ * @arg link           Link object
+ * @arg ifindex                Interface index
+ *
+ * @route_doc{link_attr_ifindex, Interface Index}
+ * @see rtnl_link_get_ifindex()
+ */
+void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex)
+{
+       link->l_index = ifindex;
+       link->ce_mask |= LINK_ATTR_IFINDEX;
+}
+
+
+/**
+ * Return interface index of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_ifindex, Interface Index}
+ * @see rtnl_link_set_ifindex()
+ * @return Interface index or 0 if not set.
+ */
+int rtnl_link_get_ifindex(struct rtnl_link *link)
+{
+       return link->l_index;
+}
+
+/**
+ * Set Maximum Transmission Unit of link object
+ * @arg link           Link object
+ * @arg mtu            New MTU value in number of bytes
+ *
+ * @route_doc{link_attr_mtu, Maximum Transmission Unit}
+ * @see rtnl_link_get_mtu()
+ */
+void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu)
+{
+       link->l_mtu = mtu;
+       link->ce_mask |= LINK_ATTR_MTU;
+}
+
+/**
+ * Return maximum transmission unit of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_mtu, Maximum Transmission Unit}
+ * @see rtnl_link_set_mtu()
+ * @return MTU in bytes or 0 if not set
+ */
+unsigned int rtnl_link_get_mtu(struct rtnl_link *link)
+{
+       return link->l_mtu;
+}
+
+/**
+ * Set transmission queue length
+ * @arg link           Link object
+ * @arg txqlen         New queue length
+ *
+ * The unit is dependant on the link type. The most common units is number
+ * of packets.
+ *
+ * @route_doc{link_attr_txqlen, Transmission Queue Length}
+ */
+void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen)
+{
+       link->l_txqlen = txqlen;
+       link->ce_mask |= LINK_ATTR_TXQLEN;
+}
+
+/**
+ * Return transmission queue length
+ * @arg link           Link object
+ *
+ * The unit is dependant on the link type. The most common units is number
+ * of packets.
+ *
+ * @route_doc{link_attr_txqlen, Transmission Queue Length}
+ * @return queue length or 0 if not specified.
+ */
+unsigned int rtnl_link_get_txqlen(struct rtnl_link *link)
+{
+       return link->ce_mask & LINK_ATTR_TXQLEN ? link->l_txqlen : 0;
+}
+
+void rtnl_link_set_link(struct rtnl_link *link, int ifindex)
+{
+       link->l_link = ifindex;
+       link->ce_mask |= LINK_ATTR_LINK;
+}
+
+int rtnl_link_get_link(struct rtnl_link *link)
+{
+       return link->l_link;
+}
+
+/**
+ * Set master link of link object
+ * @arg link           Link object
+ * @arg ifindex                Interface index of master link
+ *
+ * @see rtnl_link_get_master()
+ */
+void rtnl_link_set_master(struct rtnl_link *link, int ifindex)
+{
+       link->l_master = ifindex;
+       link->ce_mask |= LINK_ATTR_MASTER;
+}
+
+/**
+ * Return master link of link object
+ * @arg link           Link object
+ *
+ * @see rtnl_link_set_master()
+ * @return Interface index of master link or 0 if not specified
+ */
+int rtnl_link_get_master(struct rtnl_link *link)
+{
+       return link->l_master;
+}
+
+/**
+ * Set carrier of link object
+ * @arg link           Link object
+ * @arg status         New carrier status
+ *
+ * @see rtnl_link_get_carrier()
+ */
+void rtnl_link_set_carrier(struct rtnl_link *link, uint8_t status)
+{
+       link->l_carrier = status;
+       link->ce_mask |= LINK_ATTR_CARRIER;
+}
+
+/**
+ * Return carrier status of link object
+ * @arg link           Link object
+ *
+ * @see rtnl_link_set_master()
+ * @return Carrier state.
+ */
+uint8_t rtnl_link_get_carrier(struct rtnl_link *link)
+{
+       return link->l_carrier;
+}
+
+/**
+ * Set operational status of link object
+ * @arg link           Link object
+ * @arg status         New opertional status
+ *
+ * @route_doc{link_attr_operstate, Operational Status}}
+ * @see rtnl_link_get_operstate()
+ */
+void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t status)
+{
+       link->l_operstate = status;
+       link->ce_mask |= LINK_ATTR_OPERSTATE;
+}
+
+/**
+ * Return operational status of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_operstate, Operational Status}
+ * @see rtnl_link_set_operstate()
+ * @return Opertional state or \c IF_OPER_UNKNOWN
+ */
+uint8_t rtnl_link_get_operstate(struct rtnl_link *link)
+{
+       return link->l_operstate;
+}
+
+/**
+ * Set link mode of link object
+ * @arg link           Link object
+ * @arg mode           New link mode
+ *
+ * @route_doc{link_attr_mode, Mode}
+ * @see rtnl_link_get_linkmode()
+ */
+void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode)
+{
+       link->l_linkmode = mode;
+       link->ce_mask |= LINK_ATTR_LINKMODE;
+}
+
+/**
+ * Return link mode of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_mode, Mode}
+ * @see rtnl_link_get_linkmode()
+ * @return Link mode or \c IF_LINK_MODE_DEFAULT
+ */
+uint8_t rtnl_link_get_linkmode(struct rtnl_link *link)
+{
+       return link->l_linkmode;
+}
+
+/**
+ * Return alias name of link object (SNMP IfAlias)
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_alias, Alias}
+ * @see rtnl_link_set_ifalias()
+ * @return Alias name or NULL if not set.
+ */
+const char *rtnl_link_get_ifalias(struct rtnl_link *link)
+{
+       return link->l_ifalias;
+}
+
+/**
+ * Set alias name of link object (SNMP IfAlias)
+ * @arg link           Link object
+ * @arg alias          Alias name or NULL to unset
+ *
+ * Sets the alias name of the link to the specified name. The alias
+ * name can be unset by specyfing NULL as the alias. The name will
+ * be strdup()ed, so no need to provide a persistent character string.
+ *
+ * @route_doc{link_attr_alias, Alias}
+ * @see rtnl_link_get_ifalias()
+ */
+void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias)
+{
+       free(link->l_ifalias);
+       link->ce_mask &= ~LINK_ATTR_IFALIAS;
+
+       if (alias) {
+               link->l_ifalias = strdup(alias);
+               link->ce_mask |= LINK_ATTR_IFALIAS;
+       }
+}
+
+/**
+ * Set queueing discipline name of link object
+ * @arg link           Link object
+ * @arg name           Name of queueing discipline
+ *
+ * @copydoc read_only_attribute
+ *
+ * For more information on how to modify the qdisc of a link, see section
+ * @ref_route{route_tc, Traffic Control}.
+ *
+ * @route_doc{link_attr_qdisc, Queueing Discipline Name}
+ * @see rtnl_link_get_qdisc()
+ */
+void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name)
+{
+       strncpy(link->l_qdisc, name, sizeof(link->l_qdisc) - 1);
+       link->ce_mask |= LINK_ATTR_QDISC;
+}
+
+/**
+ * Return name of queueing discipline of link object
+ * @arg link           Link object
+ *
+ * @route_doc{link_attr_qdisc, Queueing Discipline Name}
+ * @see rtnl_link_set_qdisc()
+ * @return Name of qdisc or NULL if not specified.
+ */
+char *rtnl_link_get_qdisc(struct rtnl_link *link)
+{
+       return link->ce_mask & LINK_ATTR_QDISC ? link->l_qdisc : NULL;
+}
+
+
+/**
+ * Return number of PCI virtual functions of link object
+ * @arg link           Link object
+ * @arg num_vf         Pointer to store number of VFs
+ *
+ * @return 0 on success or -NLE_OPNOTSUPP if not available
+ */
+int rtnl_link_get_num_vf(struct rtnl_link *link, uint32_t *num_vf)
+{
+       if (link->ce_mask & LINK_ATTR_NUM_VF) {
+               *num_vf = link->l_num_vf;
+               return 0;
+       } else
+               return -NLE_OPNOTSUPP;
+}
+
+/**
+ * Return value of link statistics counter
+ * @arg link           Link object
+ * @arg id             Identifier of statistical counter
+ *
+ * @return Value of counter or 0 if not specified.
+ */
+uint64_t rtnl_link_get_stat(struct rtnl_link *link, rtnl_link_stat_id_t id)
+{
+       if (id > RTNL_LINK_STATS_MAX)
+               return 0;
+
+       return link->l_stats[id];
+}
+
+/**
+ * Set value of link statistics counter
+ * @arg link           Link object
+ * @arg id             Identifier of statistical counter
+ * @arg value          New value
+ *
+ * \note Changing the value of a statistical counter will not change the
+ *       value in the kernel.
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id,
+                      const uint64_t value)
+{
+       if (id > RTNL_LINK_STATS_MAX)
+               return -NLE_INVAL;
+
+       link->l_stats[id] = value;
+
+       return 0;
+}
+
+/**
+ * Set type of link object
+ * @arg link           Link object
+ * @arg type           Name of link type
+ *
+ * Looks up the link type module and prepares the link to store type
+ * specific attributes. If a type has been assigned already it will
+ * be released with all link type specific attributes lost.
+ *
+ * @route_doc{link_modules, Link Modules}
+ * @return 0 on success or a negative errror code.
+ */
+int rtnl_link_set_type(struct rtnl_link *link, const char *type)
+{
+       struct rtnl_link_info_ops *io;
+       int err;
+       char *kind;
+
+       free(link->l_info_kind);
+       link->ce_mask &= ~LINK_ATTR_LINKINFO;
+       if (link->l_info_ops)
+               release_link_info(link);
+
+       if (!type)
+               return 0;
+
+       kind = strdup(type);
+       if (!kind)
+               return -NLE_NOMEM;
+
+       io = rtnl_link_info_ops_lookup(type);
+       if (io) {
+               if (io->io_alloc && (err = io->io_alloc(link)) < 0)
+                       goto errout;
+
+               link->l_info_ops = io;
+       }
+
+       link->l_info_kind = kind;
+       link->ce_mask |= LINK_ATTR_LINKINFO;
+
+       return 0;
+
+errout:
+       free(kind);
+       return err;
+}
+
+/**
+ * Return type of link
+ * @arg link           Link object
+ *
+ * @route_doc{link_modules, Link Modules}
+ * @return Name of link type or NULL if not specified.
+ */
+char *rtnl_link_get_type(struct rtnl_link *link)
+{
+       return link->l_info_kind;
+}
+
+/**
+ * Set link promiscuity count
+ * @arg link           Link object
+ * @arg count          New promiscuity count
+ *
+ * @copydoc read_only_attribute
+ *
+ * @see rtnl_link_get_promiscuity()
+ */
+void rtnl_link_set_promiscuity(struct rtnl_link *link, uint32_t count)
+{
+       link->l_promiscuity = count;
+       link->ce_mask |= LINK_ATTR_PROMISCUITY;
+}
+
+/**
+ * Return link promiscuity count
+ * @arg link           Link object
+ *
+ * @see rtnl_link_set_promiscuity()
+ * @return Link promiscuity count or 0
+ */
+uint32_t rtnl_link_get_promiscuity(struct rtnl_link *link)
+{
+       return link->l_promiscuity;
+}
+
+/**
+ * Set number of TX queues
+ * @arg link           Link object
+ * @arg nqueues                Number of queues
+ *
+ * Sets the number of TX queues of the link object. The value is considered
+ * by the kernel when creating network devices that can be created via
+ * netlink. The value will be passed on to alloc_netdev_mqs()
+ *
+ * Therefore use of rtnl_link_set_num_tx_queues() only makes sense in
+ * combination with rtnl_link_add() or if the link object is used as a filter.
+ *
+ * @see rtnl_link_get_num_tx_queues()
+ */
+void rtnl_link_set_num_tx_queues(struct rtnl_link *link, uint32_t nqueues)
+{
+       link->l_num_tx_queues = nqueues;
+       link->ce_mask |= LINK_ATTR_NUM_TX_QUEUES;
+}
+
+/**
+ * Return number of TX queues
+ * @arg link           Link object
+ *
+ * @return Number of TX queues or 0
+ */
+uint32_t rtnl_link_get_num_tx_queues(struct rtnl_link *link)
+{
+       return link->l_num_tx_queues;
+}
+
+/**
+ * Set number of RX queues
+ * @arg link           Link object
+ * @arg nqueues                Number of queues
+ *
+ * Sets the number of RX queues of the link object. The value is considered
+ * by the kernel when creating network devices that can be created via
+ * netlink. The value will be passed on to alloc_netdev_mqs()
+ *
+ * Therefore use of rtnl_link_set_num_rx_queues() only makes sense in
+ * combination with rtnl_link_add() or if the link object is used as a filter.
+ *
+ * @see rtnl_link_get_num_rx_queues()
+ */
+void rtnl_link_set_num_rx_queues(struct rtnl_link *link, uint32_t nqueues)
+{
+       link->l_num_rx_queues = nqueues;
+       link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
+}
+
+/**
+ * Return number of RX queues
+ * @arg link           Link object
+ *
+ * @return Number of RX queues or 0
+ */
+uint32_t rtnl_link_get_num_rx_queues(struct rtnl_link *link)
+{
+       return link->l_num_rx_queues;
+}
+
+/** @} */
+
+/**
+ * @name Master/Slave
+ * @{
+ */
+
+/**
+ * Enslave slave link to master link
+ * @arg sock           netlink socket
+ * @arg master         ifindex of master link
+ * @arg slave          ifindex of slave link
+ *
+ * This function is identical to rtnl_link_enslave() except that
+ * it takes interface indices instead of rtnl_link objects.
+ *
+ * @see rtnl_link_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
+{
+       struct rtnl_link *link;
+       int err;
+
+       if (!(link = rtnl_link_alloc()))
+               return -NLE_NOMEM;
+
+       rtnl_link_set_ifindex(link, slave);
+       rtnl_link_set_master(link, master);
+       
+       if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
+               goto errout;
+
+       rtnl_link_put(link);
+
+       /*
+        * Due to the kernel not signaling whether this opertion is
+        * supported or not, we will retrieve the attribute to see  if the
+        * request was successful. If the master assigned remains unchanged
+        * we will return NLE_OPNOTSUPP to allow performing backwards
+        * compatibility of some sort.
+        */
+       if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
+               return err;
+
+       if (rtnl_link_get_master(link) != master)
+               err = -NLE_OPNOTSUPP;
+
+errout:
+       rtnl_link_put(link);
+
+       return err;
+}
+
+/**
+ * Enslave slave link to master link
+ * @arg sock           netlink socket
+ * @arg master         master link
+ * @arg slave          slave link
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
+ * the master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_enslave_ifindex()
+ * @see rtnl_link_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_enslave(struct nl_sock *sock, struct rtnl_link *master,
+                     struct rtnl_link *slave)
+{
+       return rtnl_link_enslave_ifindex(sock, rtnl_link_get_ifindex(master),
+                                        rtnl_link_get_ifindex(slave));
+}
+
+/**
+ * Release slave link from its master
+ * @arg sock           netlink socket
+ * @arg slave          slave link
+ *
+ * This function is identical to rtnl_link_release() except that
+ * it takes an interface index instead of a rtnl_link object.
+ *
+ * @see rtnl_link_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_release_ifindex(struct nl_sock *sock, int slave)
+{
+       return rtnl_link_enslave_ifindex(sock, 0, slave);
+}
+
+/**
+ * Release slave link from its master
+ * @arg sock           netlink socket
+ * @arg slave          slave link
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
+ * its master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_release_ifindex()
+ * @see rtnl_link_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_release(struct nl_sock *sock, struct rtnl_link *slave)
+{
+       return rtnl_link_release_ifindex(sock, rtnl_link_get_ifindex(slave));
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+static const struct trans_tbl link_flags[] = {
+       __ADD(IFF_LOOPBACK, loopback)
+       __ADD(IFF_BROADCAST, broadcast)
+       __ADD(IFF_POINTOPOINT, pointopoint)
+       __ADD(IFF_MULTICAST, multicast)
+       __ADD(IFF_NOARP, noarp)
+       __ADD(IFF_ALLMULTI, allmulti)
+       __ADD(IFF_PROMISC, promisc)
+       __ADD(IFF_MASTER, master)
+       __ADD(IFF_SLAVE, slave)
+       __ADD(IFF_DEBUG, debug)
+       __ADD(IFF_DYNAMIC, dynamic)
+       __ADD(IFF_AUTOMEDIA, automedia)
+       __ADD(IFF_PORTSEL, portsel)
+       __ADD(IFF_NOTRAILERS, notrailers)
+       __ADD(IFF_UP, up)
+       __ADD(IFF_RUNNING, running)
+       __ADD(IFF_LOWER_UP, lowerup)
+       __ADD(IFF_DORMANT, dormant)
+       __ADD(IFF_ECHO, echo)
+};
+
+char *rtnl_link_flags2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, link_flags,
+                          ARRAY_SIZE(link_flags));
+}
+
+int rtnl_link_str2flags(const char *name)
+{
+       return __str2flags(name, link_flags, ARRAY_SIZE(link_flags));
+}
+
+static const struct trans_tbl link_stats[] = {
+       __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
+       __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
+       __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
+       __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
+       __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
+       __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
+       __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
+       __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
+       __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
+       __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
+       __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
+       __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
+       __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
+       __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
+       __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
+       __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
+       __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
+       __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
+       __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
+       __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
+       __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
+       __ADD(RTNL_LINK_COLLISIONS, collisions)
+       __ADD(RTNL_LINK_MULTICAST, multicast)
+       __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives)
+       __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors)
+       __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors)
+       __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes)
+       __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors)
+       __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos)
+       __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts)
+       __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards)
+       __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers)
+       __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams)
+       __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests)
+       __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards)
+       __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes)
+       __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout)
+       __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds)
+       __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs)
+       __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails)
+       __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs)
+       __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails)
+       __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates)
+       __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts)
+       __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts)
+       __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts)
+       __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts)
+       __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets)
+       __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets)
+       __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets)
+       __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets)
+       __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets)
+       __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets)
+       __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs)
+       __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors)
+       __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs)
+       __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors)
+};
+
+char *rtnl_link_stat2str(int st, char *buf, size_t len)
+{
+       return __type2str(st, buf, len, link_stats, ARRAY_SIZE(link_stats));
+}
+
+int rtnl_link_str2stat(const char *name)
+{
+       return __str2type(name, link_stats, ARRAY_SIZE(link_stats));
+}
+
+static const struct trans_tbl link_operstates[] = {
+       __ADD(IF_OPER_UNKNOWN, unknown)
+       __ADD(IF_OPER_NOTPRESENT, notpresent)
+       __ADD(IF_OPER_DOWN, down)
+       __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
+       __ADD(IF_OPER_TESTING, testing)
+       __ADD(IF_OPER_DORMANT, dormant)
+       __ADD(IF_OPER_UP, up)
+};
+
+char *rtnl_link_operstate2str(uint8_t st, char *buf, size_t len)
+{
+       return __type2str(st, buf, len, link_operstates,
+                         ARRAY_SIZE(link_operstates));
+}
+
+int rtnl_link_str2operstate(const char *name)
+{
+       return __str2type(name, link_operstates,
+                         ARRAY_SIZE(link_operstates));
+}
+
+static const struct trans_tbl link_modes[] = {
+       __ADD(IF_LINK_MODE_DEFAULT, default)
+       __ADD(IF_LINK_MODE_DORMANT, dormant)
+};
+
+static const struct trans_tbl carrier_states[] = {
+       __ADD(IF_CARRIER_DOWN, down)
+       __ADD(IF_CARRIER_UP, up)
+};
+
+char *rtnl_link_mode2str(uint8_t st, char *buf, size_t len)
+{
+       return __type2str(st, buf, len, link_modes, ARRAY_SIZE(link_modes));
+}
+
+int rtnl_link_str2mode(const char *name)
+{
+       return __str2type(name, link_modes, ARRAY_SIZE(link_modes));
+}
+
+char *rtnl_link_carrier2str(uint8_t st, char *buf, size_t len)
+{
+       return __type2str(st, buf, len, carrier_states,
+                         ARRAY_SIZE(carrier_states));
+}
+
+int rtnl_link_str2carrier(const char *name)
+{
+       return __str2type(name, carrier_states, ARRAY_SIZE(carrier_states));
+}
+
+/** @} */
+
+/**
+ * @name Deprecated Functions
+ */
+
+/**
+ * @deprecated Use of this function is deprecated, use rtnl_link_set_type()
+ */
+int rtnl_link_set_info_type(struct rtnl_link *link, const char *type)
+{
+       return rtnl_link_set_type(link, type);
+}
+
+/**
+ * @deprecated Use of this function is deprecated, use rtnl_link_get_type()
+ */
+char *rtnl_link_get_info_type(struct rtnl_link *link)
+{
+       return rtnl_link_get_type(link);
+}
+
+/**
+ * @deprecated The weight attribute is unused and obsoleted in all recent kernels
+ */
+void rtnl_link_set_weight(struct rtnl_link *link, unsigned int weight)
+{
+       link->l_weight = weight;
+       link->ce_mask |= LINK_ATTR_WEIGHT;
+}
+
+/**
+ * @deprecated The weight attribute is unused and obsoleted in all recent kernels
+ */
+unsigned int rtnl_link_get_weight(struct rtnl_link *link)
+{
+       return link->l_weight;
+}
+
+/** @} */
+
+static struct nl_object_ops link_obj_ops = {
+       .oo_name                = "route/link",
+       .oo_size                = sizeof(struct rtnl_link),
+       .oo_free_data           = link_free_data,
+       .oo_clone               = link_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = link_dump_line,
+           [NL_DUMP_DETAILS]   = link_dump_details,
+           [NL_DUMP_STATS]     = link_dump_stats,
+       },
+       .oo_compare             = link_compare,
+       .oo_keygen              = link_keygen,
+       .oo_attrs2str           = link_attrs2str,
+       .oo_id_attrs            = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY,
+};
+
+static struct nl_af_group link_groups[] = {
+       { AF_UNSPEC,    RTNLGRP_LINK },
+       { AF_BRIDGE,    RTNLGRP_LINK },
+       { END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_link_ops = {
+       .co_name                = "route/link",
+       .co_hdrsize             = sizeof(struct ifinfomsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWLINK, NL_ACT_NEW, "new" },
+                                       { RTM_DELLINK, NL_ACT_DEL, "del" },
+                                       { RTM_GETLINK, NL_ACT_GET, "get" },
+                                       { RTM_SETLINK, NL_ACT_CHANGE, "set" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_groups              = link_groups,
+       .co_request_update      = link_request_update,
+       .co_msg_parser          = link_msg_parser,
+       .co_obj_ops             = &link_obj_ops,
+};
+
+static void __init link_init(void)
+{
+       nl_cache_mngt_register(&rtnl_link_ops);
+}
+
+static void __exit link_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_link_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/api.c b/lib/route/link/api.c
new file mode 100644 (file)
index 0000000..6d1e12f
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * lib/route/link/api.c                Link Info API
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup link_API Link Modules API
+ * @brief API for modules implementing specific link types/semantics.
+ *
+ * @par 1) Registering/Unregistering a new link info type
+ * @code
+ * static struct rtnl_link_info_ops vlan_info_ops = {
+ *     .io_name                = "vlan",
+ *     .io_alloc               = vlan_alloc,
+ *     .io_parse               = vlan_parse,
+ *     .io_dump[NL_DUMP_BRIEF] = vlan_dump_brief,
+ *     .io_dump[NL_DUMP_FULL]  = vlan_dump_full,
+ *     .io_free                = vlan_free,
+ * };
+ *
+ * static void __init vlan_init(void)
+ * {
+ *     rtnl_link_register_info(&vlan_info_ops);
+ * }
+ *
+ * static void __exit vlan_exit(void)
+ * {
+ *     rtnl_link_unregister_info(&vlan_info_ops);
+ * }
+ * @endcode
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/link.h>
+#include <netlink-private/route/link/api.h>
+
+static NL_LIST_HEAD(info_ops);
+
+/* lock protecting info_ops and af_ops */
+static NL_RW_LOCK(info_lock);
+
+static struct rtnl_link_info_ops *__rtnl_link_info_ops_lookup(const char *name)
+{
+       struct rtnl_link_info_ops *ops;
+
+       nl_list_for_each_entry(ops, &info_ops, io_list)
+               if (!strcmp(ops->io_name, name))
+                       return ops;
+
+       return NULL;
+}
+
+/**
+ * @name Link Info Modules
+ * @{
+ */
+
+/**
+ * Return operations of a specific link info type
+ * @arg name           Name of link info type.
+ *
+ * @note The returned pointer must be given back using rtnl_link_info_ops_put()
+ *
+ * @return Pointer to operations or NULL if unavailable.
+ */
+struct rtnl_link_info_ops *rtnl_link_info_ops_lookup(const char *name)
+{
+       struct rtnl_link_info_ops *ops;
+
+       nl_write_lock(&info_lock);
+       if ((ops = __rtnl_link_info_ops_lookup(name)))
+               ops->io_refcnt++;
+       nl_write_unlock(&info_lock);
+
+       return ops;
+}
+
+/**
+ * Give back reference to a set of operations.
+ * @arg ops            Link info operations.
+ */
+void rtnl_link_info_ops_put(struct rtnl_link_info_ops *ops)
+{
+       if (ops)
+               ops->io_refcnt--;
+}
+
+/**
+ * Register operations for a link info type
+ * @arg ops            Link info operations
+ *
+ * This function must be called by modules implementing a specific link
+ * info type. It will make the operations implemented by the module
+ * available for everyone else.
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_INVAL Link info name not specified.
+ * @return -NLE_EXIST Operations for address family already registered.
+ */
+int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
+{
+       int err = 0;
+
+       if (ops->io_name == NULL)
+               return -NLE_INVAL;
+
+       nl_write_lock(&info_lock);
+       if (__rtnl_link_info_ops_lookup(ops->io_name)) {
+               err = -NLE_EXIST;
+               goto errout;
+       }
+
+       NL_DBG(1, "Registered link info operations %s\n", ops->io_name);
+
+       nl_list_add_tail(&ops->io_list, &info_ops);
+errout:
+       nl_write_unlock(&info_lock);
+
+       return err;
+}
+
+/**
+ * Unregister operations for a link info type
+ * @arg ops            Link info operations
+ *
+ * This function must be called if a module implementing a specific link
+ * info type is unloaded or becomes unavailable. It must provide a
+ * set of operations which have previously been registered using
+ * rtnl_link_register_info().
+ *
+ * @return 0 on success or a negative error code
+ * @return _NLE_OPNOTSUPP Link info operations not registered.
+ * @return -NLE_BUSY Link info operations still in use.
+ */
+int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
+{
+       struct rtnl_link_info_ops *t;
+       int err = -NLE_OPNOTSUPP;
+
+       nl_write_lock(&info_lock);
+
+       nl_list_for_each_entry(t, &info_ops, io_list) {
+               if (t == ops) {
+                       if (t->io_refcnt > 0) {
+                               err = -NLE_BUSY;
+                               goto errout;
+                       }
+
+                       nl_list_del(&t->io_list);
+
+                       NL_DBG(1, "Unregistered link info operations %s\n",
+                               ops->io_name);
+                       err = 0;
+                       goto errout;
+               }
+       }
+
+errout:
+       nl_write_unlock(&info_lock);
+
+       return err;
+}
+
+/** @} */
+
+/**
+ * @name Link Address Family Modules
+ * @{
+ */
+
+static struct rtnl_link_af_ops *af_ops[AF_MAX];
+
+/**
+ * Return operations of a specific link address family
+ * @arg family         Address family
+ *
+ * @note The returned pointer must be given back using rtnl_link_af_ops_put()
+ *
+ * @return Pointer to operations or NULL if unavailable.
+ */
+struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(const unsigned int family)
+{
+       if (family == AF_UNSPEC || family >= AF_MAX)
+               return NULL;
+
+       nl_write_lock(&info_lock);
+       if (af_ops[family])
+               af_ops[family]->ao_refcnt++;
+       nl_write_unlock(&info_lock);
+
+       return af_ops[family];
+}
+
+/**
+ * Give back reference to a set of operations.
+ * @arg ops            Address family operations.
+ */
+void rtnl_link_af_ops_put(struct rtnl_link_af_ops *ops)
+{
+       if (ops)
+               ops->ao_refcnt--;
+}
+
+/**
+ * Allocate and return data buffer for link address family modules
+ * @arg link           Link object
+ * @arg ops            Address family operations
+ *
+ * This function must be called by link address family modules in all
+ * cases where the API does not provide the data buffer as argument
+ * already. This typically includes set functions the module provides.
+ * Calling this function is strictly required to ensure proper allocation
+ * of the buffer upon first use. Link objects will NOT proactively
+ * allocate a data buffer for each registered link address family.
+ *
+ * @return Pointer to data buffer or NULL on error.
+ */
+void *rtnl_link_af_alloc(struct rtnl_link *link,
+                        const struct rtnl_link_af_ops *ops)
+{
+       int family;
+
+       if (!link || !ops)
+               BUG();
+
+       family = ops->ao_family;
+
+       if (!link->l_af_data[family]) {
+               if (!ops->ao_alloc)
+                       BUG();
+               
+               link->l_af_data[family] = ops->ao_alloc(link);
+               if (!link->l_af_data[family])
+                       return NULL;
+       }
+
+       return link->l_af_data[family];
+}
+
+/**
+ * Return data buffer for link address family modules
+ * @arg link           Link object
+ * @arg ops            Address family operations
+ *
+ * This function returns a pointer to the data buffer for the specified link
+ * address family module or NULL if the buffer was not allocated yet. This
+ * function is typically used by get functions of modules which are not
+ * interested in having the data buffer allocated if no values have been set
+ * yet.
+ *
+ * @return Pointer to data buffer or NULL on error.
+ */
+void *rtnl_link_af_data(const struct rtnl_link *link,
+                       const struct rtnl_link_af_ops *ops)
+{
+       if (!link || !ops)
+               BUG();
+
+       return link->l_af_data[ops->ao_family];
+}
+
+/**
+ * Register operations for a link address family
+ * @arg ops            Address family operations
+ *
+ * This function must be called by modules implementing a specific link
+ * address family. It will make the operations implemented by the module
+ * available for everyone else.
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_INVAL Address family is out of range (0..AF_MAX)
+ * @return -NLE_EXIST Operations for address family already registered.
+ */
+int rtnl_link_af_register(struct rtnl_link_af_ops *ops)
+{
+       int err = 0;
+
+       if (ops->ao_family == AF_UNSPEC || ops->ao_family >= AF_MAX)
+               return -NLE_INVAL;
+
+       nl_write_lock(&info_lock);
+       if (af_ops[ops->ao_family]) {
+               err = -NLE_EXIST;
+               goto errout;
+       }
+
+       ops->ao_refcnt = 0;
+       af_ops[ops->ao_family] = ops;
+
+       NL_DBG(1, "Registered link address family operations %u\n",
+               ops->ao_family);
+
+errout:
+       nl_write_unlock(&info_lock);
+
+       return err;
+}
+
+/**
+ * Unregister operations for a link address family
+ * @arg ops            Address family operations
+ *
+ * This function must be called if a module implementing a specific link
+ * address family is unloaded or becomes unavailable. It must provide a
+ * set of operations which have previously been registered using
+ * rtnl_link_af_register().
+ *
+ * @return 0 on success or a negative error code
+ * @return -NLE_INVAL ops is NULL
+ * @return -NLE_OBJ_NOTFOUND Address family operations not registered.
+ * @return -NLE_BUSY Address family operations still in use.
+ */
+int rtnl_link_af_unregister(struct rtnl_link_af_ops *ops)
+{
+       int err = -NLE_INVAL;
+
+       if (!ops)
+               return err;
+
+       nl_write_lock(&info_lock);
+       if (!af_ops[ops->ao_family]) {
+               err = -NLE_OBJ_NOTFOUND;
+               goto errout;
+       }
+
+       if (ops->ao_refcnt > 0) {
+               err = -NLE_BUSY;
+               goto errout;
+       }
+
+       af_ops[ops->ao_family] = NULL;
+
+       NL_DBG(1, "Unregistered link address family operations %u\n",
+               ops->ao_family);
+
+errout:
+       nl_write_unlock(&info_lock);
+
+       return err;
+}
+
+/**
+ * Compare af data for a link address family
+ * @arg a              Link object a
+ * @arg b              Link object b
+ * @arg family         af data family
+ *
+ * This function will compare af_data between two links
+ * a and b of family given by arg family
+ *
+ * @return 0 if address family specific data matches or is not present
+ * or != 0 if it mismatches.
+ */
+int rtnl_link_af_data_compare(struct rtnl_link *a, struct rtnl_link *b,
+                             int family)
+{
+       struct rtnl_link_af_ops *af_ops;
+       int ret = 0;
+
+       if (!a->l_af_data[family] && !b->l_af_data[family])
+               return 0;
+
+       if (!a->l_af_data[family] || !b->l_af_data[family])
+               return ~0;
+
+       af_ops = rtnl_link_af_ops_lookup(family);
+       if (!af_ops)
+               return ~0;
+
+       if (af_ops->ao_compare == NULL) {
+               ret = ~0;
+               goto out;
+       }
+
+       ret = af_ops->ao_compare(a, b, family, ~0, 0);
+
+out:
+       rtnl_link_af_ops_put(af_ops);
+
+       return ret;
+}
+
+/** @} */
+
+/** @} */
+
diff --git a/lib/route/link/bonding.c b/lib/route/link/bonding.c
new file mode 100644 (file)
index 0000000..f4c520b
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * lib/route/link/bonding.c    Bonding Link Module
+ *
+ *     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) 2011-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup bonding Bonding
+ *
+ * @details
+ * \b Link Type Name: "bond"
+ *
+ * @route_doc{link_bonding, Bonding Documentation}
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/link/api.h>
+
+/**
+ * Allocate link object of type bond
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_bond_alloc(void)
+{
+       struct rtnl_link *link;
+       int err;
+
+       if (!(link = rtnl_link_alloc()))
+               return NULL;
+
+       if ((err = rtnl_link_set_type(link, "bond")) < 0) {
+               rtnl_link_put(link);
+               return NULL;
+       }
+
+       return link;
+}
+
+/**
+ * Create a new kernel bonding device
+ * @arg sock           netlink socket
+ * @arg name           name of bonding device or NULL
+ * @arg opts           bonding options (currently unused)
+ *
+ * Creates a new bonding device in the kernel. If no name is
+ * provided, the kernel will automatically pick a name of the
+ * form "type%d" (e.g. bond0, vlan1, etc.)
+ *
+ * The \a opts argument is currently unused. In the future, it
+ * may be used to carry additional bonding options to be set
+ * when creating the bonding device.
+ *
+ * @note When letting the kernel assign a name, it will become
+ *       difficult to retrieve the interface afterwards because
+ *       you have to guess the name the kernel has chosen. It is
+ *       therefore not recommended to not provide a device name.
+ *
+ * @see rtnl_link_bond_enslave()
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_bond_add(struct nl_sock *sock, const char *name,
+                      struct rtnl_link *opts)
+{
+       struct rtnl_link *link;
+       int err;
+
+       if (!(link = rtnl_link_bond_alloc()))
+               return -NLE_NOMEM;
+
+       if (!name && opts)
+               name = rtnl_link_get_name(opts);
+
+       if (name)
+               rtnl_link_set_name(link, name);
+
+       err = rtnl_link_add(sock, link, NLM_F_CREATE);
+
+       rtnl_link_put(link);
+
+       return err;
+}
+
+/**
+ * Add a link to a bond (enslave)
+ * @arg sock           netlink socket
+ * @arg master         ifindex of bonding master
+ * @arg slave          ifindex of slave link to add to bond
+ *
+ * This function is identical to rtnl_link_bond_enslave() except that
+ * it takes interface indices instead of rtnl_link objcets.
+ *
+ * @see rtnl_link_bond_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master,
+                                  int slave)
+{
+       struct rtnl_link *link;
+       int err;
+
+       if (!(link = rtnl_link_bond_alloc()))
+               return -NLE_NOMEM;
+
+       rtnl_link_set_ifindex(link, slave);
+       rtnl_link_set_master(link, master);
+       
+       if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
+               goto errout;
+
+       rtnl_link_put(link);
+
+       /*
+        * Due to the kernel not signaling whether this opertion is
+        * supported or not, we will retrieve the attribute to see  if the
+        * request was successful. If the master assigned remains unchanged
+        * we will return NLE_OPNOTSUPP to allow performing backwards
+        * compatibility of some sort.
+        */
+       if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
+               return err;
+
+       if (rtnl_link_get_master(link) != master)
+               err = -NLE_OPNOTSUPP;
+
+errout:
+       rtnl_link_put(link);
+
+       return err;
+}
+
+/**
+ * Add a link to a bond (enslave)
+ * @arg sock           netlink socket
+ * @arg master         bonding master
+ * @arg slave          slave link to add to bond
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
+ * the master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_bond_enslave_ifindex()
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master,
+                          struct rtnl_link *slave)
+{
+       return rtnl_link_bond_enslave_ifindex(sock,
+                               rtnl_link_get_ifindex(master),
+                               rtnl_link_get_ifindex(slave));
+}
+
+/**
+ * Release a link from a bond
+ * @arg sock           netlink socket
+ * @arg slave          slave link to be released
+ *
+ * This function is identical to rtnl_link_bond_release() except that
+ * it takes an interface index instead of a rtnl_link object.
+ *
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
+{
+       return rtnl_link_bond_enslave_ifindex(sock, 0, slave);
+}
+
+/**
+ * Release a link from a bond
+ * @arg sock           netlink socket
+ * @arg slave          slave link to be released
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
+ * its master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ *       recently to the kernel (Feb 2011). Also, the kernel does not signal
+ *       if the operation is not supported. Therefore this function will
+ *       verify if the master assignment has changed and will return
+ *       -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_bond_release_ifindex()
+ * @see rtnl_link_bond_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
+{
+       return rtnl_link_bond_release_ifindex(sock,
+                               rtnl_link_get_ifindex(slave));
+}
+
+static struct rtnl_link_info_ops bonding_info_ops = {
+       .io_name                = "bond",
+};
+
+static void __init bonding_init(void)
+{
+       rtnl_link_register_info(&bonding_info_ops);
+}
+
+static void __exit bonding_exit(void)
+{
+       rtnl_link_unregister_info(&bonding_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/bridge.c b/lib/route/link/bridge.c
new file mode 100644 (file)
index 0000000..eb02b22
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * lib/route/link/bridge.c     AF_BRIDGE link support
+ *
+ *     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) 2010-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup bridge Bridging
+ *
+ * @details
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/bridge.h>
+#include <netlink-private/route/link/api.h>
+#include <linux/if_bridge.h>
+
+/** @cond SKIP */
+#define BRIDGE_ATTR_PORT_STATE         (1 << 0)
+#define BRIDGE_ATTR_PRIORITY           (1 << 1)
+#define BRIDGE_ATTR_COST               (1 << 2)
+#define BRIDGE_ATTR_FLAGS              (1 << 3)
+
+#define PRIV_FLAG_NEW_ATTRS            (1 << 0)
+
+struct bridge_data
+{
+       uint8_t                 b_port_state;
+       uint8_t                 b_priv_flags; /* internal flags */
+       uint16_t                b_priority;
+       uint32_t                b_cost;
+       uint32_t                b_flags;
+       uint32_t                b_flags_mask;
+       uint32_t                ce_mask; /* HACK to support attr macros */
+};
+
+static struct rtnl_link_af_ops bridge_ops;
+
+#define IS_BRIDGE_LINK_ASSERT(link) \
+       if (!rtnl_link_is_bridge(link)) { \
+               APPBUG("A function was expecting a link object of type bridge."); \
+               return -NLE_OPNOTSUPP; \
+       }
+
+static inline struct bridge_data *bridge_data(struct rtnl_link *link)
+{
+       return rtnl_link_af_data(link, &bridge_ops);
+}
+
+static void *bridge_alloc(struct rtnl_link *link)
+{
+       return calloc(1, sizeof(struct bridge_data));
+}
+
+static void *bridge_clone(struct rtnl_link *link, void *data)
+{
+       struct bridge_data *bd;
+
+       if ((bd = bridge_alloc(link)))
+               memcpy(bd, data, sizeof(*bd));
+
+       return bd;
+}
+
+static void bridge_free(struct rtnl_link *link, void *data)
+{
+       free(data);
+}
+
+static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
+       [IFLA_BRPORT_STATE]             = { .type = NLA_U8 },
+       [IFLA_BRPORT_PRIORITY]          = { .type = NLA_U16 },
+       [IFLA_BRPORT_COST]              = { .type = NLA_U32 },
+       [IFLA_BRPORT_MODE]              = { .type = NLA_U8 },
+       [IFLA_BRPORT_GUARD]             = { .type = NLA_U8 },
+       [IFLA_BRPORT_PROTECT]           = { .type = NLA_U8 },
+       [IFLA_BRPORT_FAST_LEAVE]        = { .type = NLA_U8 },
+};
+
+static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
+                      int type, int flag)
+{
+       if (attrs[type] && nla_get_u8(attrs[type]))
+               rtnl_link_bridge_set_flags(link, flag);
+}
+
+static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
+                                void *data)
+{
+       struct bridge_data *bd = data;
+       struct nlattr *br_attrs[IFLA_BRPORT_MAX+1];
+       int err;
+
+       /* Backwards compatibility */
+       if (!nla_is_nested(attr)) {
+               if (nla_len(attr) < 1)
+                       return -NLE_RANGE;
+
+               bd->b_port_state = nla_get_u8(attr);
+               bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
+
+               return 0;
+       }
+
+       if ((err = nla_parse_nested(br_attrs, IFLA_BRPORT_MAX, attr,
+            br_attrs_policy)) < 0)
+               return err;
+
+       bd->b_priv_flags |= PRIV_FLAG_NEW_ATTRS;
+
+       if (br_attrs[IFLA_BRPORT_STATE]) {
+               bd->b_port_state = nla_get_u8(br_attrs[IFLA_BRPORT_STATE]);
+               bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
+       }
+
+       if (br_attrs[IFLA_BRPORT_PRIORITY]) {
+               bd->b_priority = nla_get_u16(br_attrs[IFLA_BRPORT_PRIORITY]);
+               bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
+       }
+
+       if (br_attrs[IFLA_BRPORT_COST]) {
+               bd->b_cost = nla_get_u32(br_attrs[IFLA_BRPORT_COST]);
+               bd->ce_mask |= BRIDGE_ATTR_COST;
+       }
+
+       check_flag(link, br_attrs, IFLA_BRPORT_MODE, RTNL_BRIDGE_HAIRPIN_MODE);
+       check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
+       check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
+       check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
+
+       return 0;
+}
+
+static void bridge_dump_details(struct rtnl_link *link,
+                               struct nl_dump_params *p, void *data)
+{
+       struct bridge_data *bd = data;
+
+       nl_dump_line(p, "    bridge: ");
+
+       if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
+               nl_dump(p, "port-state %u ", bd->b_port_state);
+
+       if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
+               nl_dump(p, "prio %u ", bd->b_priority);
+
+       if (bd->ce_mask & BRIDGE_ATTR_COST)
+               nl_dump(p, "cost %u ", bd->b_cost);
+
+       nl_dump(p, "\n");
+}
+
+static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
+                         int family, uint32_t attrs, int flags)
+{
+       struct bridge_data *a = bridge_data(_a);
+       struct bridge_data *b = bridge_data(_b);
+       int diff = 0;
+
+#define BRIDGE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, BRIDGE_ATTR_##ATTR, a, b, EXPR)
+       diff |= BRIDGE_DIFF(PORT_STATE, a->b_port_state != b->b_port_state);
+       diff |= BRIDGE_DIFF(PRIORITY, a->b_priority != b->b_priority);
+       diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost);
+
+       if (flags & LOOSE_COMPARISON)
+               diff |= BRIDGE_DIFF(FLAGS,
+                                 (a->b_flags ^ b->b_flags) & b->b_flags_mask);
+       else
+               diff |= BRIDGE_DIFF(FLAGS, a->b_flags != b->b_flags);
+#undef BRIDGE_DIFF
+
+       return diff;
+}
+/** @endcond */
+
+/**
+ * Allocate link object of type bridge
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_bridge_alloc(void)
+{
+       struct rtnl_link *link;
+       int err;
+
+       if (!(link = rtnl_link_alloc()))
+               return NULL;
+
+       if ((err = rtnl_link_set_type(link, "bridge")) < 0) {
+               rtnl_link_put(link);
+               return NULL;
+       }
+
+       return link;
+}
+
+/**
+ * Check if a link is a bridge
+ * @arg link           Link object
+ *
+ * @return 1 if the link is a bridge, 0 otherwise.
+ */
+int rtnl_link_is_bridge(struct rtnl_link *link)
+{
+       return link->l_family == AF_BRIDGE &&
+              link->l_af_ops == &bridge_ops;
+}
+
+/**
+ * Check if bridge has extended information
+ * @arg link           Link object of type bridge
+ *
+ * Checks if the bridge object has been constructed based on
+ * information that is only available in newer kernels. This
+ * affectes the following functions:
+ *  - rtnl_link_bridge_get_cost()
+ *  - rtnl_link_bridge_get_priority()
+ *  - rtnl_link_bridge_get_flags()
+ *
+ * @return 1 if extended information is available, otherwise 0 is returned.
+ */
+int rtnl_link_bridge_has_ext_info(struct rtnl_link *link)
+{
+       struct bridge_data *bd;
+
+       if (!rtnl_link_is_bridge(link))
+               return 0;
+
+       bd = bridge_data(link);
+       return !!(bd->b_priv_flags & PRIV_FLAG_NEW_ATTRS);
+}
+
+/**
+ * Set Spanning Tree Protocol (STP) port state
+ * @arg link           Link object of type bridge
+ * @arg state          New STP port state
+ *
+ * The value of state must be one of the following:
+ *   - BR_STATE_DISABLED
+ *   - BR_STATE_LISTENING
+ *   - BR_STATE_LEARNING
+ *   - BR_STATE_FORWARDING
+ *   - BR_STATE_BLOCKING
+ *
+ * @see rtnl_link_bridge_get_port_state()
+ *
+ * @return 0 on success or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ * @retval -NLE_INVAL Invalid state value (0..BR_STATE_BLOCKING)
+ */
+int rtnl_link_bridge_set_port_state(struct rtnl_link *link, uint8_t state)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       if (state > BR_STATE_BLOCKING)
+               return -NLE_INVAL;
+
+       bd->b_port_state = state;
+       bd->ce_mask |= BRIDGE_ATTR_PORT_STATE;
+
+       return 0;
+}
+
+/**
+ * Get Spanning Tree Protocol (STP) port state
+ * @arg link           Link object of type bridge
+ *
+ * @see rtnl_link_bridge_set_port_state()
+ *
+ * @return The STP port state or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ */
+int rtnl_link_bridge_get_port_state(struct rtnl_link *link)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       return bd->b_port_state;
+}
+
+/**
+ * Set priority
+ * @arg link           Link object of type bridge
+ * @arg prio           Bridge priority
+ *
+ * @see rtnl_link_bridge_get_priority()
+ *
+ * @return 0 on success or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ */
+int rtnl_link_bridge_set_priority(struct rtnl_link *link, uint16_t prio)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       bd->b_priority = prio;
+       bd->ce_mask |= BRIDGE_ATTR_PRIORITY;
+
+       return 0;
+}
+
+/**
+ * Get priority
+ * @arg link           Link object of type bridge
+ *
+ * @see rtnl_link_bridge_set_priority()
+ *
+ * @return 0 on success or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ */
+int rtnl_link_bridge_get_priority(struct rtnl_link *link)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       return bd->b_priority;
+}
+
+/**
+ * Set Spanning Tree Protocol (STP) path cost
+ * @arg link           Link object of type bridge
+ * @arg cost           New STP path cost value
+ *
+ * @see rtnl_link_bridge_get_cost()
+ *
+ * @return The bridge priority or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ */
+int rtnl_link_bridge_set_cost(struct rtnl_link *link, uint32_t cost)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       bd->b_cost = cost;
+       bd->ce_mask |= BRIDGE_ATTR_COST;
+
+       return 0;
+}
+
+/**
+ * Get Spanning Tree Protocol (STP) path cost
+ * @arg link           Link object of type bridge
+ * @arg cost           Pointer to store STP cost value
+ *
+ * @see rtnl_link_bridge_set_cost()
+ *
+ * @return 0 on success or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ * @retval -NLE_INVAL `cost` is not a valid pointer
+ */
+int rtnl_link_bridge_get_cost(struct rtnl_link *link, uint32_t *cost)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       if (!cost)
+               return -NLE_INVAL;
+
+       *cost = bd->b_cost;
+
+       return 0;
+}
+
+/**
+ * Unset flags
+ * @arg link           Link object of type bridge
+ * @arg flags          Bridging flags to unset
+ *
+ * @see rtnl_link_bridge_set_flags()
+ * @see rtnl_link_bridge_get_flags()
+ *
+ * @return 0 on success or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ */
+int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       bd->b_flags_mask |= flags;
+       bd->b_flags &= ~flags;
+       bd->ce_mask |= BRIDGE_ATTR_FLAGS;
+
+       return 0;
+}
+
+/**
+ * Set flags
+ * @arg link           Link object of type bridge
+ * @arg flags          Bridging flags to set
+ *
+ * Valid flags are:
+ *   - RTNL_BRIDGE_HAIRPIN_MODE
+ *   - RTNL_BRIDGE_BPDU_GUARD
+ *   - RTNL_BRIDGE_ROOT_BLOCK
+ *   - RTNL_BRIDGE_FAST_LEAVE
+ *
+ * @see rtnl_link_bridge_unset_flags()
+ * @see rtnl_link_bridge_get_flags()
+ *
+ * @return 0 on success or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ */
+int rtnl_link_bridge_set_flags(struct rtnl_link *link, unsigned int flags)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       bd->b_flags_mask |= flags;
+       bd->b_flags |= flags;
+       bd->ce_mask |= BRIDGE_ATTR_FLAGS;
+
+       return 0;
+}
+
+/**
+ * Get flags
+ * @arg link           Link object of type bridge
+ *
+ * @see rtnl_link_bridge_set_flags()
+ * @see rtnl_link_bridge_unset_flags()
+ *
+ * @return Flags or a negative error code.
+ * @retval -NLE_OPNOTSUPP Link is not a bridge
+ */
+int rtnl_link_bridge_get_flags(struct rtnl_link *link)
+{
+       struct bridge_data *bd = bridge_data(link);
+
+       IS_BRIDGE_LINK_ASSERT(link);
+
+       return bd->b_flags;
+}
+
+static struct rtnl_link_af_ops bridge_ops = {
+       .ao_family                      = AF_BRIDGE,
+       .ao_alloc                       = &bridge_alloc,
+       .ao_clone                       = &bridge_clone,
+       .ao_free                        = &bridge_free,
+       .ao_parse_protinfo              = &bridge_parse_protinfo,
+       .ao_dump[NL_DUMP_DETAILS]       = &bridge_dump_details,
+       .ao_compare                     = &bridge_compare,
+};
+
+static void __init bridge_init(void)
+{
+       rtnl_link_af_register(&bridge_ops);
+}
+
+static void __exit bridge_exit(void)
+{
+       rtnl_link_af_unregister(&bridge_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/can.c b/lib/route/link/can.c
new file mode 100644 (file)
index 0000000..60da42d
--- /dev/null
@@ -0,0 +1,784 @@
+/*
+ * lib/route/link/can.c                CAN Link Info
+ *
+ *     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) 2012 Benedikt Spranger <b.spranger@linutronix.de>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup can CAN
+ * Controller Area Network link module
+ *
+ * @details
+ * \b Link Type Name: "can"
+ *
+ * @route_doc{link_can, CAN Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/can.h>
+
+#include <linux/can/netlink.h>
+
+/** @cond SKIP */
+#define CAN_HAS_BITTIMING              (1<<0)
+#define CAN_HAS_BITTIMING_CONST                (1<<1)
+#define CAN_HAS_CLOCK                  (1<<2)
+#define CAN_HAS_STATE                  (1<<3)
+#define CAN_HAS_CTRLMODE               (1<<4)
+#define CAN_HAS_RESTART_MS             (1<<5)
+#define CAN_HAS_RESTART                        (1<<6)
+#define CAN_HAS_BERR_COUNTER           (1<<7)
+
+struct can_info {
+       uint32_t                        ci_state;
+       uint32_t                        ci_restart;
+       uint32_t                        ci_restart_ms;
+       struct can_ctrlmode             ci_ctrlmode;
+       struct can_bittiming            ci_bittiming;
+       struct can_bittiming_const      ci_bittiming_const;
+       struct can_clock                ci_clock;
+       struct can_berr_counter         ci_berr_counter;
+       uint32_t                        ci_mask;
+};
+
+/** @endcond */
+
+static struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
+       [IFLA_CAN_STATE]        = { .type = NLA_U32 },
+       [IFLA_CAN_CTRLMODE]     = { .minlen = sizeof(struct can_ctrlmode) },
+       [IFLA_CAN_RESTART_MS]   = { .type = NLA_U32 },
+       [IFLA_CAN_RESTART]      = { .type = NLA_U32 },
+       [IFLA_CAN_BITTIMING]    = { .minlen = sizeof(struct can_bittiming) },
+       [IFLA_CAN_BITTIMING_CONST]
+                               = { .minlen = sizeof(struct can_bittiming_const) },
+       [IFLA_CAN_CLOCK]        = { .minlen = sizeof(struct can_clock) },
+       [IFLA_CAN_BERR_COUNTER] = { .minlen = sizeof(struct can_berr_counter) },
+};
+
+static int can_alloc(struct rtnl_link *link)
+{
+       struct can_info *ci;
+
+       ci = calloc(1, sizeof(*ci));
+       if (!ci)
+               return -NLE_NOMEM;
+
+       link->l_info = ci;
+
+       return 0;
+}
+
+static int can_parse(struct rtnl_link *link, struct nlattr *data,
+                    struct nlattr *xstats)
+{
+       struct nlattr *tb[IFLA_CAN_MAX+1];
+       struct can_info *ci;
+       int err;
+
+       NL_DBG(3, "Parsing CAN link info");
+
+       if ((err = nla_parse_nested(tb, IFLA_CAN_MAX, data, can_policy)) < 0)
+               goto errout;
+
+       if ((err = can_alloc(link)) < 0)
+               goto errout;
+
+       ci = link->l_info;
+
+       if (tb[IFLA_CAN_STATE]) {
+               ci->ci_state = nla_get_u32(tb[IFLA_CAN_STATE]);
+               ci->ci_mask |= CAN_HAS_STATE;
+       }
+
+       if (tb[IFLA_CAN_RESTART]) {
+               ci->ci_restart = nla_get_u32(tb[IFLA_CAN_RESTART]);
+               ci->ci_mask |= CAN_HAS_RESTART;
+       }
+
+       if (tb[IFLA_CAN_RESTART_MS]) {
+               ci->ci_restart_ms = nla_get_u32(tb[IFLA_CAN_RESTART_MS]);
+               ci->ci_mask |= CAN_HAS_RESTART_MS;
+       }
+
+       if (tb[IFLA_CAN_CTRLMODE]) {
+               nla_memcpy(&ci->ci_ctrlmode, tb[IFLA_CAN_CTRLMODE],
+                          sizeof(ci->ci_ctrlmode));
+               ci->ci_mask |= CAN_HAS_CTRLMODE;
+       }
+
+       if (tb[IFLA_CAN_BITTIMING]) {
+               nla_memcpy(&ci->ci_bittiming, tb[IFLA_CAN_BITTIMING],
+                          sizeof(ci->ci_bittiming));
+               ci->ci_mask |= CAN_HAS_BITTIMING;
+       }
+
+       if (tb[IFLA_CAN_BITTIMING_CONST]) {
+               nla_memcpy(&ci->ci_bittiming_const,
+                          tb[IFLA_CAN_BITTIMING_CONST],
+                          sizeof(ci->ci_bittiming_const));
+               ci->ci_mask |= CAN_HAS_BITTIMING_CONST;
+       }
+
+       if (tb[IFLA_CAN_CLOCK]) {
+               nla_memcpy(&ci->ci_clock, tb[IFLA_CAN_CLOCK],
+                          sizeof(ci->ci_clock));
+               ci->ci_mask |= CAN_HAS_CLOCK;
+       }
+
+       if (tb[IFLA_CAN_BERR_COUNTER]) {
+               nla_memcpy(&ci->ci_berr_counter, tb[IFLA_CAN_BERR_COUNTER],
+                          sizeof(ci->ci_berr_counter));
+               ci->ci_mask |= CAN_HAS_BERR_COUNTER;
+       }
+
+       err = 0;
+errout:
+       return err;
+}
+
+static void can_free(struct rtnl_link *link)
+{
+       struct can_info *ci = link->l_info;
+
+       free(ci);
+       link->l_info = NULL;
+}
+
+static char *print_can_state (uint32_t state)
+{
+       char *text;
+
+       switch (state)
+       {
+       case CAN_STATE_ERROR_ACTIVE:
+               text = "error active";
+               break;
+       case CAN_STATE_ERROR_WARNING:
+               text = "error warning";
+               break;
+       case CAN_STATE_ERROR_PASSIVE:
+               text = "error passive";
+               break;
+       case CAN_STATE_BUS_OFF:
+               text = "bus off";
+               break;
+       case CAN_STATE_STOPPED:
+               text = "stopped";
+               break;
+       case CAN_STATE_SLEEPING:
+               text = "sleeping";
+               break;
+       default:
+               text = "unknown state";
+       }
+
+       return text;
+}
+
+static void can_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+       struct can_info *ci = link->l_info;
+       char buf [64];
+
+       rtnl_link_can_ctrlmode2str(ci->ci_ctrlmode.flags, buf, sizeof(buf));
+       nl_dump(p, "bitrate %d %s <%s>",
+               ci->ci_bittiming.bitrate, print_can_state(ci->ci_state), buf);
+}
+
+static void can_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+       struct can_info *ci = link->l_info;
+       char buf [64];
+
+       rtnl_link_can_ctrlmode2str(ci->ci_ctrlmode.flags, buf, sizeof(buf));
+       nl_dump(p, "    bitrate %d %s <%s>",
+               ci->ci_bittiming.bitrate, print_can_state(ci->ci_state), buf);
+
+       if (ci->ci_mask & CAN_HAS_RESTART) {
+               if (ci->ci_restart)
+                       nl_dump_line(p,"    restarting\n");
+       }
+
+       if (ci->ci_mask & CAN_HAS_RESTART_MS) {
+               nl_dump_line(p,"    restart interval %d ms\n",
+                            ci->ci_restart_ms);
+       }
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING) {
+               nl_dump_line(p,"    sample point %f %%\n",
+                            ((float) ci->ci_bittiming.sample_point)/10);
+               nl_dump_line(p,"    time quanta %d ns\n",
+                            ci->ci_bittiming.tq);
+               nl_dump_line(p,"    propagation segment %d tq\n",
+                            ci->ci_bittiming.prop_seg);
+               nl_dump_line(p,"    phase buffer segment1 %d tq\n",
+                            ci->ci_bittiming.phase_seg1);
+               nl_dump_line(p,"    phase buffer segment2 %d tq\n",
+                            ci->ci_bittiming.phase_seg2);
+               nl_dump_line(p,"    synchronisation jump width %d tq\n",
+                            ci->ci_bittiming.sjw);
+               nl_dump_line(p,"    bitrate prescaler %d\n",
+                            ci->ci_bittiming.brp);
+       }
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING_CONST) {
+               nl_dump_line(p,"    minimum tsig1 %d tq\n",
+                            ci->ci_bittiming_const.tseg1_min);
+               nl_dump_line(p,"    maximum tsig1 %d tq\n",
+                            ci->ci_bittiming_const.tseg1_max);
+               nl_dump_line(p,"    minimum tsig2 %d tq\n",
+                            ci->ci_bittiming_const.tseg2_min);
+               nl_dump_line(p,"    maximum tsig2 %d tq\n",
+                            ci->ci_bittiming_const.tseg2_max);
+               nl_dump_line(p,"    maximum sjw %d tq\n",
+                            ci->ci_bittiming_const.sjw_max);
+               nl_dump_line(p,"    minimum brp %d\n",
+                            ci->ci_bittiming_const.brp_min);
+               nl_dump_line(p,"    maximum brp %d\n",
+                            ci->ci_bittiming_const.brp_max);
+               nl_dump_line(p,"    brp increment %d\n",
+                            ci->ci_bittiming_const.brp_inc);
+       }
+
+       if (ci->ci_mask & CAN_HAS_CLOCK) {
+               nl_dump_line(p,"    base freq %d Hz\n", ci->ci_clock);
+
+       }
+
+       if (ci->ci_mask & CAN_HAS_BERR_COUNTER) {
+               nl_dump_line(p,"    bus error RX %d\n",
+                            ci->ci_berr_counter.rxerr);
+               nl_dump_line(p,"    bus error TX %d\n",
+                            ci->ci_berr_counter.txerr);
+       }
+
+       return;
+}
+
+static int can_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+       struct can_info *cdst, *csrc = src->l_info;
+       int ret;
+
+       dst->l_info = NULL;
+       ret = rtnl_link_set_type(dst, "can");
+       if (ret < 0)
+               return ret;
+
+       cdst = malloc(sizeof(*cdst));
+       if (!cdst)
+               return -NLE_NOMEM;
+
+       *cdst = *csrc;
+       dst->l_info = cdst;
+
+       return 0;
+}
+
+static int can_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+       struct can_info *ci = link->l_info;
+       struct nlattr *data;
+
+       data = nla_nest_start(msg, IFLA_INFO_DATA);
+       if (!data)
+               return -NLE_MSGSIZE;
+
+       if (ci->ci_mask & CAN_HAS_RESTART)
+               NLA_PUT_U32(msg, CAN_HAS_RESTART, ci->ci_restart);
+
+       if (ci->ci_mask & CAN_HAS_RESTART_MS)
+               NLA_PUT_U32(msg, CAN_HAS_RESTART_MS, ci->ci_restart_ms);
+
+       if (ci->ci_mask & CAN_HAS_CTRLMODE)
+               NLA_PUT(msg, CAN_HAS_CTRLMODE, sizeof(ci->ci_ctrlmode),
+                       &ci->ci_ctrlmode);
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING)
+               NLA_PUT(msg, CAN_HAS_BITTIMING, sizeof(ci->ci_bittiming),
+                       &ci->ci_bittiming);
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING_CONST)
+               NLA_PUT(msg, CAN_HAS_BITTIMING_CONST,
+                       sizeof(ci->ci_bittiming_const),
+                       &ci->ci_bittiming_const);
+
+       if (ci->ci_mask & CAN_HAS_CLOCK)
+               NLA_PUT(msg, CAN_HAS_CLOCK, sizeof(ci->ci_clock),
+                       &ci->ci_clock);
+
+       nla_nest_end(msg, data);
+
+nla_put_failure:
+
+       return 0;
+}
+
+static struct rtnl_link_info_ops can_info_ops = {
+       .io_name                = "can",
+       .io_alloc               = can_alloc,
+       .io_parse               = can_parse,
+       .io_dump = {
+           [NL_DUMP_LINE]      = can_dump_line,
+           [NL_DUMP_DETAILS]   = can_dump_details,
+       },
+       .io_clone               = can_clone,
+       .io_put_attrs           = can_put_attrs,
+       .io_free                = can_free,
+};
+
+/** @cond SKIP */
+#define IS_CAN_LINK_ASSERT(link) \
+       if ((link)->l_info_ops != &can_info_ops) { \
+               APPBUG("Link is not a CAN link. set type \"can\" first."); \
+               return -NLE_OPNOTSUPP; \
+       }
+/** @endcond */
+
+/**
+ * @name CAN Object
+ * @{
+ */
+
+/**
+ * Check if link is a CAN link
+ * @arg link           Link object
+ *
+ * @return True if link is a CAN link, otherwise false is returned.
+ */
+int rtnl_link_is_can(struct rtnl_link *link)
+{
+       return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "can");
+}
+
+/**
+ * Restart CAN device
+ * @arg link            Link object
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_restart(struct rtnl_link *link)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       ci->ci_restart = 1;
+       ci->ci_restart |= CAN_HAS_RESTART;
+
+       return 0;
+}
+
+/**
+ * Get CAN base frequency
+ * @arg link            Link object
+ * @arg freq           frequency in Hz
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_freq(struct rtnl_link *link, uint32_t *freq)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!freq)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_CLOCK)
+               *freq = ci->ci_clock.freq;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Get CAN state
+ * @arg link            Link object
+ * @arg state          CAN bus state
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_state(struct rtnl_link *link, uint32_t *state)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!state)
+               return -NLE_INVAL;
+
+       *state = ci->ci_state;
+
+       return 0;
+}
+
+/**
+ * Get CAN RX bus error count
+ * @arg link            Link object
+ *
+ * @return RX bus error count on success or a negative error code
+ */
+int rtnl_link_can_berr_rx(struct rtnl_link *link)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       if (ci->ci_mask & CAN_HAS_BERR_COUNTER)
+               return ci->ci_berr_counter.rxerr;
+       else
+               return -NLE_AGAIN;
+}
+
+/**
+ * Get CAN TX bus error count
+ * @arg link            Link object
+ *
+ * @return TX bus error count on success or a negative error code
+ */
+int rtnl_link_can_berr_tx(struct rtnl_link *link)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       if (ci->ci_mask & CAN_HAS_BERR_COUNTER)
+               return ci->ci_berr_counter.txerr;
+       else
+               return -NLE_AGAIN;
+}
+
+/**
+ * Get CAN bus error count
+ * @arg link            Link object
+ * @arg berr           Bus error count
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_berr(struct rtnl_link *link, struct can_berr_counter *berr)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!berr)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_BERR_COUNTER)
+               *berr = ci->ci_berr_counter;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Get CAN harware-dependent bit-timing constant
+ * @arg link            Link object
+ * @arg bt_const       Bit-timing constant
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_bt_const(struct rtnl_link *link,
+                              struct can_bittiming_const *bt_const)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!bt_const)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING_CONST)
+               *bt_const = ci->ci_bittiming_const;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Get CAN device bit-timing
+ * @arg link            Link object
+ * @arg bit_timing     CAN bit-timing
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_bittiming(struct rtnl_link *link,
+                               struct can_bittiming *bit_timing)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!bit_timing)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING)
+               *bit_timing = ci->ci_bittiming;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Set CAN device bit-timing
+ * @arg link            Link object
+ * @arg bit_timing     CAN bit-timing
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_set_bittiming(struct rtnl_link *link,
+                               struct can_bittiming *bit_timing)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!bit_timing)
+               return -NLE_INVAL;
+
+       ci->ci_bittiming = *bit_timing;
+       ci->ci_mask |= CAN_HAS_BITTIMING;
+
+       return 0;
+}
+
+/**
+ * Get CAN device bit-timing
+ * @arg link            Link object
+ * @arg bitrate                CAN bitrate
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_bitrate(struct rtnl_link *link, uint32_t *bitrate)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!bitrate)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING)
+               *bitrate = ci->ci_bittiming.bitrate;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Set CAN device bit-rate
+ * @arg link            Link object
+ * @arg bitrate                CAN bitrate
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_set_bitrate(struct rtnl_link *link, uint32_t bitrate)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       ci->ci_bittiming.bitrate = bitrate;
+       ci->ci_mask |= CAN_HAS_BITTIMING;
+
+       return 0;
+}
+
+/**
+ * Get CAN device sample point
+ * @arg link            Link object
+ * @arg sp             CAN sample point
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_sample_point(struct rtnl_link *link, uint32_t *sp)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!sp)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_BITTIMING)
+               *sp = ci->ci_bittiming.sample_point;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Set CAN device sample point
+ * @arg link            Link object
+ * @arg sp             CAN sample point
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_set_sample_point(struct rtnl_link *link, uint32_t sp)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       ci->ci_bittiming.sample_point = sp;
+       ci->ci_mask |= CAN_HAS_BITTIMING;
+
+       return 0;
+}
+
+/**
+ * Get CAN device restart intervall
+ * @arg link            Link object
+ * @arg interval       Restart intervall in ms
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_restart_ms(struct rtnl_link *link, uint32_t *interval)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!interval)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_RESTART_MS)
+               *interval = ci->ci_restart_ms;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Set CAN device restart intervall
+ * @arg link            Link object
+ * @arg interval       Restart intervall in ms
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_set_restart_ms(struct rtnl_link *link, uint32_t interval)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       ci->ci_restart_ms = interval;
+       ci->ci_mask |= CAN_HAS_RESTART_MS;
+
+       return 0;
+}
+
+/**
+ * Get CAN control mode
+ * @arg link            Link object
+ * @arg ctrlmode       CAN control mode
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_get_ctrlmode(struct rtnl_link *link, uint32_t *ctrlmode)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+       if (!ctrlmode)
+               return -NLE_INVAL;
+
+       if (ci->ci_mask & CAN_HAS_CTRLMODE)
+               *ctrlmode = ci->ci_ctrlmode.flags;
+       else
+               return -NLE_AGAIN;
+
+       return 0;
+}
+
+/**
+ * Set a CAN Control Mode
+ * @arg link            Link object
+ * @arg ctrlmode       CAN control mode
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_set_ctrlmode(struct rtnl_link *link, uint32_t ctrlmode)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       ci->ci_ctrlmode.flags |= ctrlmode;
+       ci->ci_ctrlmode.mask |= ctrlmode;
+       ci->ci_mask |= CAN_HAS_CTRLMODE;
+
+       return 0;
+}
+
+/**
+ * Unset a CAN Control Mode
+ * @arg link            Link object
+ * @arg ctrlmode       CAN control mode
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_can_unset_ctrlmode(struct rtnl_link *link, uint32_t ctrlmode)
+{
+       struct can_info *ci = link->l_info;
+
+       IS_CAN_LINK_ASSERT(link);
+
+       ci->ci_ctrlmode.flags &= ~ctrlmode;
+       ci->ci_ctrlmode.mask |= ctrlmode;
+       ci->ci_mask |= CAN_HAS_CTRLMODE;
+
+       return 0;
+}
+
+/** @} */
+
+/**
+ * @name Control Mode Translation
+ * @{
+ */
+
+static const struct trans_tbl can_ctrlmode[] = {
+       __ADD(CAN_CTRLMODE_LOOPBACK, loopback)
+       __ADD(CAN_CTRLMODE_LISTENONLY, listen-only)
+       __ADD(CAN_CTRLMODE_3_SAMPLES, triple-sampling)
+       __ADD(CAN_CTRLMODE_ONE_SHOT, one-shot)
+       __ADD(CAN_CTRLMODE_BERR_REPORTING, berr-reporting)
+};
+
+char *rtnl_link_can_ctrlmode2str(int ctrlmode, char *buf, size_t len)
+{
+       return __flags2str(ctrlmode, buf, len, can_ctrlmode,
+                          ARRAY_SIZE(can_ctrlmode));
+}
+
+int rtnl_link_can_str2ctrlmode(const char *name)
+{
+       return __str2flags(name, can_ctrlmode, ARRAY_SIZE(can_ctrlmode));
+}
+
+/** @} */
+
+static void __init can_init(void)
+{
+       rtnl_link_register_info(&can_info_ops);
+}
+
+static void __exit can_exit(void)
+{
+       rtnl_link_unregister_info(&can_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/dummy.c b/lib/route/link/dummy.c
new file mode 100644 (file)
index 0000000..1fd9f5a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * lib/route/link/dummy.c      Dummy Interfaces
+ *
+ *     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) 2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup dummy Dummy
+ *
+ * @details
+ * \b Link Type Name: "dummy"
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/link/api.h>
+
+static struct rtnl_link_info_ops dummy_info_ops = {
+       .io_name                = "dummy",
+};
+
+static void __init dummy_init(void)
+{
+       rtnl_link_register_info(&dummy_info_ops);
+}
+
+static void __exit dummy_exit(void)
+{
+       rtnl_link_unregister_info(&dummy_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/inet.c b/lib/route/link/inet.c
new file mode 100644 (file)
index 0000000..e2c867d
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * lib/route/link/inet.c       AF_INET link operations
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup link_API
+ * @defgroup link_inet IPv4 Link Module
+ * @brief Implementation of IPv4 specific link attributes
+ *
+ *
+ *
+ * @par Example: Reading the value of IPV4_DEVCONF_FORWARDING
+ * @code
+ * struct nl_cache *cache;
+ * struct rtnl_link *link;
+ * uint32_t value;
+ *
+ * // Allocate a link cache
+ * rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
+ *
+ * // Search for the link we wish to see the value from
+ * link = rtnl_link_get_by_name(cache, "eth0");
+ *
+ * // Read the value of the setting IPV4_DEVCONF_FORWARDING
+ * if (rtnl_link_inet_get_conf(link, IPV4_DEVCONF_FORWARDING, &value) < 0)
+ *         // Error: Unable to read config setting
+ *
+ * printf("forwarding is %s\n", value ? "enabled" : "disabled");
+ * @endcode
+ *
+ * @par Example: Changing the value of IPV4_DEVCONF_FOWARDING
+ * @code
+ * //
+ * // ... Continueing from the previous example ...
+ * //
+ *
+ * struct rtnl_link *new;
+ *
+ * // Allocate a new link to store the changes we wish to make.
+ * new = rtnl_link_alloc();
+ *
+ * // Set IPV4_DEVCONF_FORWARDING to '1'
+ * rtnl_link_inet_set_conf(new, IPV4_DEVCONF_FORWARDING, 1);
+ *
+ * // Send the change request to the kernel.
+ * rtnl_link_change(sock, link, new, 0);
+ * @endcode
+ *
+ * @{
+ */
+
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+
+/** @cond SKIP */
+struct inet_data
+{
+       uint8_t                 i_confset[IPV4_DEVCONF_MAX];
+       uint32_t                i_conf[IPV4_DEVCONF_MAX];
+};
+/** @endcond */
+
+static void *inet_alloc(struct rtnl_link *link)
+{
+       return calloc(1, sizeof(struct inet_data));
+}
+
+static void *inet_clone(struct rtnl_link *link, void *data)
+{
+       struct inet_data *id;
+
+       if ((id = inet_alloc(link)))
+               memcpy(id, data, sizeof(*id));
+
+       return id;
+}
+
+static void inet_free(struct rtnl_link *link, void *data)
+{
+       free(data);
+}
+
+static struct nla_policy inet_policy[IFLA_INET6_MAX+1] = {
+       [IFLA_INET_CONF]        = { .minlen = IPV4_DEVCONF_MAX * 4 },
+};
+
+static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
+{
+       struct inet_data *id = data;
+       struct nlattr *tb[IFLA_INET_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[IFLA_INET_CONF])
+               nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
+
+       return 0;
+}
+
+static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
+{
+       struct inet_data *id = data;
+       struct nlattr *nla;
+       int i;
+
+       if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
+               return -NLE_MSGSIZE;
+
+       for (i = 0; i < IPV4_DEVCONF_MAX; i++)
+               if (id->i_confset[i])
+                       NLA_PUT_U32(msg, i+1, id->i_conf[i]);
+
+       nla_nest_end(msg, nla);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+static const struct trans_tbl inet_devconf[] = {
+       __ADD(IPV4_DEVCONF_FORWARDING, forwarding)
+       __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding)
+       __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp)
+       __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
+       __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects)
+       __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects)
+       __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media)
+       __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter)
+       __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
+       __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay)
+       __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians)
+       __ADD(IPV4_DEVCONF_TAG, tag)
+       __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter)
+       __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id)
+       __ADD(IPV4_DEVCONF_NOXFRM, noxfrm)
+       __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy)
+       __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version)
+       __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce)
+       __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore)
+       __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries)
+       __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept)
+       __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify)
+       __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local)
+       __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark)
+       __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan)
+};
+
+const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
+{
+       return __type2str(type, buf, len, inet_devconf,
+                         ARRAY_SIZE(inet_devconf));
+}
+
+int rtnl_link_inet_str2devconf(const char *name)
+{
+       return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
+}
+
+static void inet_dump_details(struct rtnl_link *link,
+                             struct nl_dump_params *p, void *data)
+{
+       struct inet_data *id = data;
+       char buf[64];
+       int i, n = 0;
+
+       nl_dump_line(p, "    ipv4 devconf:\n");
+       nl_dump_line(p, "      ");
+
+       for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
+               nl_dump_line(p, "%-19s %3u",
+                       rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
+                       id->i_conf[i]);
+
+               if (++n == 3) {
+                       nl_dump(p, "\n");
+                       nl_dump_line(p, "      ");
+                       n = 0;
+               } else
+                       nl_dump(p, "  ");
+       }
+
+       if (n != 0)
+               nl_dump(p, "\n");
+}
+
+static struct rtnl_link_af_ops inet_ops = {
+       .ao_family                      = AF_INET,
+       .ao_alloc                       = &inet_alloc,
+       .ao_clone                       = &inet_clone,
+       .ao_free                        = &inet_free,
+       .ao_parse_af                    = &inet_parse_af,
+       .ao_fill_af                     = &inet_fill_af,
+       .ao_dump[NL_DUMP_DETAILS]       = &inet_dump_details,
+};
+
+/**
+ * Get value of a ipv4 link configuration setting
+ * @arg link           Link object
+ * @arg cfgid          Configuration identifier
+ * @arg res            Result pointer
+ *
+ * Stores the value of the specified configuration setting in the provided
+ * result pointer.
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
+ * @return -NLE_NOATTR configuration setting not available
+ */
+int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
+                           uint32_t *res)
+{
+       struct inet_data *id;
+
+       if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
+               return -NLE_RANGE;
+
+       if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
+               return -NLE_NOATTR;
+
+       *res = id->i_conf[cfgid - 1];
+
+       return 0;
+}
+
+/**
+ * Change value of a ipv4 link configuration setting
+ * @arg link           Link object
+ * @arg cfgid          Configuration identifier
+ * @arg value          New value
+ *
+ * Changes the value in the per link ipv4 configuration array. 
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
+ * @return -NLE_NOMEM memory allocation failed
+ */
+int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
+                           uint32_t value)
+{
+       struct inet_data *id;
+
+       if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
+               return -NLE_NOMEM;
+
+       if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
+               return -NLE_RANGE;
+
+       id->i_confset[cfgid - 1] = 1;
+       id->i_conf[cfgid - 1] = value;
+
+       return 0;
+}
+
+
+static void __init inet_init(void)
+{
+       rtnl_link_af_register(&inet_ops);
+}
+
+static void __exit inet_exit(void)
+{
+       rtnl_link_af_unregister(&inet_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/inet6.c b/lib/route/link/inet6.c
new file mode 100644 (file)
index 0000000..4c627bd
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * lib/route/link/inet6.c      AF_INET6 link operations
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+
+struct inet6_data
+{
+       uint32_t                i6_flags;
+       struct ifla_cacheinfo   i6_cacheinfo;
+       uint32_t                i6_conf[DEVCONF_MAX];
+};
+
+static void *inet6_alloc(struct rtnl_link *link)
+{
+       return calloc(1, sizeof(struct inet6_data));
+}
+
+static void *inet6_clone(struct rtnl_link *link, void *data)
+{
+       struct inet6_data *i6;
+
+       if ((i6 = inet6_alloc(link)))
+               memcpy(i6, data, sizeof(*i6));
+
+       return i6;
+}
+
+static void inet6_free(struct rtnl_link *link, void *data)
+{
+       free(data);
+}
+
+static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
+       [IFLA_INET6_FLAGS]      = { .type = NLA_U32 },
+       [IFLA_INET6_CACHEINFO]  = { .minlen = sizeof(struct ifla_cacheinfo) },
+       [IFLA_INET6_CONF]       = { .minlen = DEVCONF_MAX * 4 },
+       [IFLA_INET6_STATS]      = { .minlen = __IPSTATS_MIB_MAX * 8 },
+       [IFLA_INET6_ICMP6STATS] = { .minlen = __ICMP6_MIB_MAX * 8 },
+};
+
+static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
+                               void *data)
+{
+       struct inet6_data *i6 = data;
+       struct nlattr *tb[IFLA_INET6_MAX+1];
+       int err;
+
+       err = nla_parse_nested(tb, IFLA_INET6_MAX, attr, inet6_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[IFLA_INET6_FLAGS])
+               i6->i6_flags = nla_get_u32(tb[IFLA_INET6_FLAGS]);
+
+       if (tb[IFLA_INET6_CACHEINFO])
+               nla_memcpy(&i6->i6_cacheinfo, tb[IFLA_INET6_CACHEINFO],
+                          sizeof(i6->i6_cacheinfo));
+
+       if (tb[IFLA_INET6_CONF])
+               nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
+                          sizeof(i6->i6_conf));
+       /*
+        * Due to 32bit data alignment, these addresses must be copied to an
+        * aligned location prior to access.
+        */
+       if (tb[IFLA_INET6_STATS]) {
+               unsigned char *cnt = nla_data(tb[IFLA_INET6_STATS]);
+               uint64_t stat;
+               int i;
+
+               for (i = 1; i < __IPSTATS_MIB_MAX; i++) {
+                       memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
+                       rtnl_link_set_stat(link, RTNL_LINK_IP6_INPKTS + i - 1,
+                                          stat);
+               }
+       }
+
+       if (tb[IFLA_INET6_ICMP6STATS]) {
+               unsigned char *cnt = nla_data(tb[IFLA_INET6_ICMP6STATS]);
+               uint64_t stat;
+               int i;
+
+               for (i = 1; i < __ICMP6_MIB_MAX; i++) {
+                       memcpy(&stat, &cnt[i * sizeof(stat)], sizeof(stat));
+                       rtnl_link_set_stat(link, RTNL_LINK_ICMP6_INMSGS + i - 1,
+                                          stat);
+               }
+       }
+
+       return 0;
+}
+
+/* These live in include/net/if_inet6.h and should be moved to include/linux */
+#define IF_RA_OTHERCONF        0x80
+#define IF_RA_MANAGED  0x40
+#define IF_RA_RCVD     0x20
+#define IF_RS_SENT     0x10
+#define IF_READY       0x80000000
+
+static const struct trans_tbl inet6_flags[] = {
+       __ADD(IF_RA_OTHERCONF, ra_otherconf)
+       __ADD(IF_RA_MANAGED, ra_managed)
+       __ADD(IF_RA_RCVD, ra_rcvd)
+       __ADD(IF_RS_SENT, rs_sent)
+       __ADD(IF_READY, ready)
+};
+
+static char *inet6_flags2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, inet6_flags,
+                          ARRAY_SIZE(inet6_flags));
+}
+
+static const struct trans_tbl inet6_devconf[] = {
+       __ADD(DEVCONF_FORWARDING, forwarding)
+       __ADD(DEVCONF_HOPLIMIT, hoplimit)
+       __ADD(DEVCONF_MTU6, mtu6)
+       __ADD(DEVCONF_ACCEPT_RA, accept_ra)
+       __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
+       __ADD(DEVCONF_AUTOCONF, autoconf)
+       __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits)
+       __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits)
+       __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval)
+       __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay)
+       __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr)
+       __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft)
+       __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft)
+       __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry)
+       __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor)
+       __ADD(DEVCONF_MAX_ADDRESSES, max_addresses)
+       __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version)
+       __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr)
+       __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo)
+       __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref)
+       __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval)
+       __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info)
+       __ADD(DEVCONF_PROXY_NDP, proxy_ndp)
+       __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad)
+       __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
+       __ADD(DEVCONF_MC_FORWARDING, mc_forwarding)
+       __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6)
+       __ADD(DEVCONF_ACCEPT_DAD, accept_dad)
+       __ADD(DEVCONF_FORCE_TLLAO, force_tllao)
+};
+
+static char *inet6_devconf2str(int type, char *buf, size_t len)
+{
+       return __type2str(type, buf, len, inet6_devconf,
+                         ARRAY_SIZE(inet6_devconf));
+}
+
+
+static void inet6_dump_details(struct rtnl_link *link,
+                               struct nl_dump_params *p, void *data)
+{
+       struct inet6_data *i6 = data;
+       char buf[64], buf2[64];
+       int i, n = 0;
+
+       nl_dump_line(p, "    ipv6 max-reasm-len %s",
+               nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf)));
+
+       nl_dump(p, " <%s>\n",
+               inet6_flags2str(i6->i6_flags, buf, sizeof(buf)));
+
+
+       nl_dump_line(p, "      create-stamp %.2fs reachable-time %s",
+               (double) i6->i6_cacheinfo.tstamp / 100.,
+               nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf)));
+
+       nl_dump(p, " retrans-time %s\n",
+               nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
+
+       nl_dump_line(p, "      devconf:\n");
+       nl_dump_line(p, "      ");
+
+       for (i = 0; i < DEVCONF_MAX; i++) {
+               uint32_t value = i6->i6_conf[i];
+               int x, offset;
+
+               switch (i) {
+               case DEVCONF_TEMP_VALID_LFT:
+               case DEVCONF_TEMP_PREFERED_LFT:
+                       nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2));
+                       break;
+
+               case DEVCONF_RTR_PROBE_INTERVAL:
+               case DEVCONF_RTR_SOLICIT_INTERVAL:
+               case DEVCONF_RTR_SOLICIT_DELAY:
+                       nl_msec2str(value, buf2, sizeof(buf2));
+                       break;
+
+               default:
+                       snprintf(buf2, sizeof(buf2), "%u", value);
+                       break;
+                       
+               }
+
+               inet6_devconf2str(i, buf, sizeof(buf));
+
+               offset = 23 - strlen(buf2);
+               if (offset < 0)
+                       offset = 0;
+
+               for (x = strlen(buf); x < offset; x++)
+                       buf[x] = ' ';
+
+               strncpy(&buf[offset], buf2, strlen(buf2));
+
+               nl_dump_line(p, "%s", buf);
+
+               if (++n == 3) {
+                       nl_dump(p, "\n");
+                       nl_dump_line(p, "      ");
+                       n = 0;
+               } else
+                       nl_dump(p, "  ");
+       }
+
+       if (n != 0)
+               nl_dump(p, "\n");
+}
+
+static void inet6_dump_stats(struct rtnl_link *link,
+                            struct nl_dump_params *p, void *data)
+{
+       double octets;
+       char *octetsUnit;
+
+       nl_dump(p, "    IPv6:       InPkts           InOctets     "
+                  "    InDiscards         InDelivers\n");
+       nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INPKTS]);
+
+       octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INOCTETS],
+                                     &octetsUnit);
+       if (octets)
+               nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+       else
+               nl_dump(p, "%16" PRIu64 " B ", 0);
+       
+       nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_IP6_INDISCARDS],
+               link->l_stats[RTNL_LINK_IP6_INDELIVERS]);
+
+       nl_dump(p, "               OutPkts          OutOctets     "
+                  "   OutDiscards        OutForwards\n");
+
+       nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTPKTS]);
+
+       octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTOCTETS],
+                                     &octetsUnit);
+       if (octets)
+               nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+       else
+               nl_dump(p, "%16" PRIu64 " B ", 0);
+
+       nl_dump(p, "%18" PRIu64 " %18" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_IP6_OUTDISCARDS],
+               link->l_stats[RTNL_LINK_IP6_OUTFORWDATAGRAMS]);
+
+       nl_dump(p, "           InMcastPkts      InMcastOctets     "
+                  "   InBcastPkts     InBcastOctests\n");
+
+       nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INMCASTPKTS]);
+
+       octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INMCASTOCTETS],
+                                     &octetsUnit);
+       if (octets)
+               nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+       else
+               nl_dump(p, "%16" PRIu64 " B ", 0);
+
+       nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_INBCASTPKTS]);
+       octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_INBCASTOCTETS],
+                                     &octetsUnit);
+       if (octets)
+               nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
+       else
+               nl_dump(p, "%16" PRIu64 " B\n", 0);
+
+       nl_dump(p, "          OutMcastPkts     OutMcastOctets     "
+                  "  OutBcastPkts    OutBcastOctests\n");
+
+       nl_dump(p, "    %18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTMCASTPKTS]);
+
+       octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTMCASTOCTETS],
+                                     &octetsUnit);
+       if (octets)
+               nl_dump(p, "%14.2f %3s ", octets, octetsUnit);
+       else
+               nl_dump(p, "%16" PRIu64 " B ", 0);
+
+       nl_dump(p, "%18" PRIu64 " ", link->l_stats[RTNL_LINK_IP6_OUTBCASTPKTS]);
+       octets = nl_cancel_down_bytes(link->l_stats[RTNL_LINK_IP6_OUTBCASTOCTETS],
+                                     &octetsUnit);
+       if (octets)
+               nl_dump(p, "%14.2f %3s\n", octets, octetsUnit);
+       else
+               nl_dump(p, "%16" PRIu64 " B\n", 0);
+
+       nl_dump(p, "              ReasmOKs         ReasmFails     "
+                  "    ReasmReqds       ReasmTimeout\n");
+       nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_IP6_REASMOKS],
+               link->l_stats[RTNL_LINK_IP6_REASMFAILS],
+               link->l_stats[RTNL_LINK_IP6_REASMREQDS],
+               link->l_stats[RTNL_LINK_IP6_REASMTIMEOUT]);
+
+       nl_dump(p, "               FragOKs          FragFails    "
+                  "    FragCreates\n");
+       nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_IP6_FRAGOKS],
+               link->l_stats[RTNL_LINK_IP6_FRAGFAILS],
+               link->l_stats[RTNL_LINK_IP6_FRAGCREATES]);
+
+       nl_dump(p, "           InHdrErrors      InTooBigErrors   "
+                  "     InNoRoutes       InAddrErrors\n");
+       nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_IP6_INHDRERRORS],
+               link->l_stats[RTNL_LINK_IP6_INTOOBIGERRORS],
+               link->l_stats[RTNL_LINK_IP6_INNOROUTES],
+               link->l_stats[RTNL_LINK_IP6_INADDRERRORS]);
+
+       nl_dump(p, "       InUnknownProtos     InTruncatedPkts   "
+                  "    OutNoRoutes\n");
+       nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_IP6_INUNKNOWNPROTOS],
+               link->l_stats[RTNL_LINK_IP6_INTRUNCATEDPKTS],
+               link->l_stats[RTNL_LINK_IP6_OUTNOROUTES]);
+
+       nl_dump(p, "    ICMPv6:     InMsgs           InErrors        "
+                  "    OutMsgs          OutErrors\n");
+       nl_dump(p, "    %18" PRIu64 " %18" PRIu64 " %18" PRIu64 " %18" PRIu64 "\n",
+               link->l_stats[RTNL_LINK_ICMP6_INMSGS],
+               link->l_stats[RTNL_LINK_ICMP6_INERRORS],
+               link->l_stats[RTNL_LINK_ICMP6_OUTMSGS],
+               link->l_stats[RTNL_LINK_ICMP6_OUTERRORS]);
+}
+
+static const struct nla_policy protinfo_policy = {
+       .type                   = NLA_NESTED,
+};
+
+static struct rtnl_link_af_ops inet6_ops = {
+       .ao_family                      = AF_INET6,
+       .ao_alloc                       = &inet6_alloc,
+       .ao_clone                       = &inet6_clone,
+       .ao_free                        = &inet6_free,
+       .ao_parse_protinfo              = &inet6_parse_protinfo,
+       .ao_parse_af                    = &inet6_parse_protinfo,
+       .ao_dump[NL_DUMP_DETAILS]       = &inet6_dump_details,
+       .ao_dump[NL_DUMP_STATS]         = &inet6_dump_stats,
+       .ao_protinfo_policy             = &protinfo_policy,
+};
+
+static void __init inet6_init(void)
+{
+       rtnl_link_af_register(&inet6_ops);
+}
+
+static void __exit inet6_exit(void)
+{
+       rtnl_link_af_unregister(&inet6_ops);
+}
diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c
new file mode 100644 (file)
index 0000000..9bbe7d5
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * lib/route/link/vlan.c       VLAN Link Info
+ *
+ *     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) 2003-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup vlan VLAN
+ * Virtual LAN link module
+ *
+ * @details
+ * \b Link Type Name: "vlan"
+ *
+ * @route_doc{link_vlan, VLAN Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/vlan.h>
+
+#include <linux/if_vlan.h>
+
+/** @cond SKIP */
+#define VLAN_HAS_ID            (1<<0)
+#define VLAN_HAS_FLAGS         (1<<1)
+#define VLAN_HAS_INGRESS_QOS   (1<<2)
+#define VLAN_HAS_EGRESS_QOS    (1<<3)
+
+struct vlan_info
+{
+       uint16_t                vi_vlan_id;
+       uint32_t                vi_flags;
+       uint32_t                vi_flags_mask;
+       uint32_t                vi_ingress_qos[VLAN_PRIO_MAX+1];
+       uint32_t                vi_negress;
+       uint32_t                vi_egress_size;
+       struct vlan_map *       vi_egress_qos;
+       uint32_t                vi_mask;
+};
+
+/** @endcond */
+
+static struct nla_policy vlan_policy[IFLA_VLAN_MAX+1] = {
+       [IFLA_VLAN_ID]          = { .type = NLA_U16 },
+       [IFLA_VLAN_FLAGS]       = { .minlen = sizeof(struct ifla_vlan_flags) },
+       [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
+       [IFLA_VLAN_EGRESS_QOS]  = { .type = NLA_NESTED },
+};
+
+static int vlan_alloc(struct rtnl_link *link)
+{
+       struct vlan_info *vi;
+
+       if ((vi = calloc(1, sizeof(*vi))) == NULL)
+               return -NLE_NOMEM;
+
+       link->l_info = vi;
+
+       return 0;
+}
+
+static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
+                     struct nlattr *xstats)
+{
+       struct nlattr *tb[IFLA_VLAN_MAX+1];
+       struct vlan_info *vi;
+       int err;
+
+       NL_DBG(3, "Parsing VLAN link info");
+
+       if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0)
+               goto errout;
+
+       if ((err = vlan_alloc(link)) < 0)
+               goto errout;
+
+       vi = link->l_info;
+
+       if (tb[IFLA_VLAN_ID]) {
+               vi->vi_vlan_id = nla_get_u16(tb[IFLA_VLAN_ID]);
+               vi->vi_mask |= VLAN_HAS_ID;
+       }
+
+       if (tb[IFLA_VLAN_FLAGS]) {
+               struct ifla_vlan_flags flags;
+               nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
+
+               vi->vi_flags = flags.flags;
+               vi->vi_mask |= VLAN_HAS_FLAGS;
+       }
+
+       if (tb[IFLA_VLAN_INGRESS_QOS]) {
+               struct ifla_vlan_qos_mapping *map;
+               struct nlattr *nla;
+               int remaining;
+
+               memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos));
+
+               nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
+                       if (nla_len(nla) < sizeof(*map))
+                               return -NLE_INVAL;
+
+                       map = nla_data(nla);
+                       if (map->from > VLAN_PRIO_MAX) {
+                               return -NLE_INVAL;
+                       }
+
+                       vi->vi_ingress_qos[map->from] = map->to;
+               }
+
+               vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
+       }
+
+       if (tb[IFLA_VLAN_EGRESS_QOS]) {
+               struct ifla_vlan_qos_mapping *map;
+               struct nlattr *nla;
+               int remaining, i = 0;
+
+               nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
+                       if (nla_len(nla) < sizeof(*map))
+                               return -NLE_INVAL;
+                       i++;
+               }
+
+               /* align to have a little reserve */
+               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 -NLE_NOMEM;
+
+               i = 0;
+               nla_for_each_nested(nla, tb[IFLA_VLAN_EGRESS_QOS], remaining) {
+                       map = nla_data(nla);
+                       NL_DBG(4, "Assigning egress qos mapping %d\n", i);
+                       vi->vi_egress_qos[i].vm_from = map->from;
+                       vi->vi_egress_qos[i++].vm_to = map->to;
+               }
+
+               vi->vi_negress = i;
+               vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
+       }
+
+       err = 0;
+errout:
+       return err;
+}
+
+static void vlan_free(struct rtnl_link *link)
+{
+       struct vlan_info *vi = link->l_info;
+
+       if (vi) {
+               free(vi->vi_egress_qos);
+               vi->vi_egress_qos = NULL;
+       }
+
+       free(vi);
+       link->l_info = NULL;
+}
+
+static void vlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+       struct vlan_info *vi = link->l_info;
+
+       nl_dump(p, "vlan-id %d", vi->vi_vlan_id);
+}
+
+static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+       struct vlan_info *vi = link->l_info;
+       int printed;
+       uint32_t i;
+       char buf[64];
+
+       rtnl_link_vlan_flags2str(vi->vi_flags, buf, sizeof(buf));
+       nl_dump_line(p, "    vlan-info id %d <%s>\n", vi->vi_vlan_id, buf);
+
+       if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
+               nl_dump_line(p, 
+               "      ingress vlan prio -> qos/socket prio mapping:\n");
+               for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) {
+                       if (vi->vi_ingress_qos[i]) {
+                               if (printed == 0)
+                                       nl_dump_line(p, "      ");
+                               nl_dump(p, "%x -> %#08x, ",
+                                       i, vi->vi_ingress_qos[i]);
+                               if (printed++ == 3) {
+                                       nl_dump(p, "\n");
+                                       printed = 0;
+                               }
+                       }
+               }
+
+               if (printed > 0 && printed != 4)
+                       nl_dump(p, "\n");
+       }
+
+       if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
+               nl_dump_line(p, 
+               "      egress qos/socket prio -> vlan prio mapping:\n");
+               for (i = 0, printed = 0; i < vi->vi_negress; i++) {
+                       if (printed == 0)
+                               nl_dump_line(p, "      ");
+                       nl_dump(p, "%#08x -> %x, ",
+                               vi->vi_egress_qos[i].vm_from,
+                               vi->vi_egress_qos[i].vm_to);
+                       if (printed++ == 3) {
+                               nl_dump(p, "\n");
+                               printed = 0;
+                       }
+               }
+
+               if (printed > 0 && printed != 4)
+                       nl_dump(p, "\n");
+       }
+}
+
+static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+       struct vlan_info *vdst, *vsrc = src->l_info;
+       int err;
+
+       dst->l_info = NULL;
+       if ((err = rtnl_link_set_type(dst, "vlan")) < 0)
+               return err;
+       vdst = dst->l_info;
+
+       vdst->vi_egress_qos = calloc(vsrc->vi_egress_size,
+                                    sizeof(struct vlan_map));
+       if (!vdst->vi_egress_qos)
+               return -NLE_NOMEM;
+
+       memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
+              vsrc->vi_egress_size * sizeof(struct vlan_map));
+
+       return 0;
+}
+
+static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+       struct vlan_info *vi = link->l_info;
+       struct nlattr *data;
+
+       if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+               return -NLE_MSGSIZE;
+
+       if (vi->vi_mask & VLAN_HAS_ID)
+               NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
+
+       if (vi->vi_mask & VLAN_HAS_FLAGS) {
+               struct ifla_vlan_flags flags = {
+                       .flags = vi->vi_flags,
+                       .mask = vi->vi_flags_mask,
+               };
+
+               NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags);
+       }
+
+       if (vi->vi_mask & VLAN_HAS_INGRESS_QOS) {
+               struct ifla_vlan_qos_mapping map;
+               struct nlattr *qos;
+               int i;
+
+               if (!(qos = nla_nest_start(msg, IFLA_VLAN_INGRESS_QOS)))
+                       goto nla_put_failure;
+
+               for (i = 0; i <= VLAN_PRIO_MAX; i++) {
+                       if (vi->vi_ingress_qos[i]) {
+                               map.from = i;
+                               map.to = vi->vi_ingress_qos[i];
+
+                               NLA_PUT(msg, i, sizeof(map), &map);
+                       }
+               }
+
+               nla_nest_end(msg, qos);
+       }
+
+       if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
+               struct ifla_vlan_qos_mapping map;
+               struct nlattr *qos;
+               uint32_t i;
+
+               if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
+                       goto nla_put_failure;
+
+               for (i = 0; i < vi->vi_negress; i++) {
+                       map.from = vi->vi_egress_qos[i].vm_from;
+                       map.to = vi->vi_egress_qos[i].vm_to;
+
+                       NLA_PUT(msg, i, sizeof(map), &map);
+               }
+
+               nla_nest_end(msg, qos);
+       }
+
+       nla_nest_end(msg, data);
+
+nla_put_failure:
+
+       return 0;
+}
+
+static struct rtnl_link_info_ops vlan_info_ops = {
+       .io_name                = "vlan",
+       .io_alloc               = vlan_alloc,
+       .io_parse               = vlan_parse,
+       .io_dump = {
+           [NL_DUMP_LINE]      = vlan_dump_line,
+           [NL_DUMP_DETAILS]   = vlan_dump_details,
+       },
+       .io_clone               = vlan_clone,
+       .io_put_attrs           = vlan_put_attrs,
+       .io_free                = vlan_free,
+};
+
+/** @cond SKIP */
+#define IS_VLAN_LINK_ASSERT(link) \
+       if ((link)->l_info_ops != &vlan_info_ops) { \
+               APPBUG("Link is not a vlan link. set type \"vlan\" first."); \
+               return -NLE_OPNOTSUPP; \
+       }
+/** @endcond */
+
+/**
+ * @name VLAN Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type VLAN
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_vlan_alloc(void)
+{
+       struct rtnl_link *link;
+       int err;
+
+       if (!(link = rtnl_link_alloc()))
+               return NULL;
+
+       if ((err = rtnl_link_set_type(link, "vlan")) < 0) {
+               rtnl_link_put(link);
+               return NULL;
+       }
+
+       return link;
+}
+
+/**
+ * Check if link is a VLAN link
+ * @arg link           Link object
+ *
+ * @return True if link is a VLAN link, otherwise false is returned.
+ */
+int rtnl_link_is_vlan(struct rtnl_link *link)
+{
+       return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vlan");
+}
+
+/**
+ * Set VLAN ID
+ * @arg link           Link object
+ * @arg id             VLAN identifier
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vlan_set_id(struct rtnl_link *link, uint16_t id)
+{
+       struct vlan_info *vi = link->l_info;
+
+       IS_VLAN_LINK_ASSERT(link);
+
+       vi->vi_vlan_id = id;
+       vi->vi_mask |= VLAN_HAS_ID;
+
+       return 0;
+}
+
+/**
+ * Get VLAN Id
+ * @arg link           Link object
+ *
+ * @return VLAN id, 0 if not set or a negative error code.
+ */
+int rtnl_link_vlan_get_id(struct rtnl_link *link)
+{
+       struct vlan_info *vi = link->l_info;
+
+       IS_VLAN_LINK_ASSERT(link);
+
+       if (vi->vi_mask & VLAN_HAS_ID)
+               return vi->vi_vlan_id;
+       else
+               return 0;
+}
+
+/**
+ * Set VLAN flags
+ * @arg link           Link object
+ * @arg flags          VLAN flags
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_vlan_set_flags(struct rtnl_link *link, unsigned int flags)
+{
+       struct vlan_info *vi = link->l_info;
+
+       IS_VLAN_LINK_ASSERT(link);
+
+       vi->vi_flags_mask |= flags;
+       vi->vi_flags |= flags;
+       vi->vi_mask |= VLAN_HAS_FLAGS;
+
+       return 0;
+}
+
+/**
+ * Unset VLAN flags
+ * @arg link           Link object
+ * @arg flags          VLAN flags
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_vlan_unset_flags(struct rtnl_link *link, unsigned int flags)
+{
+       struct vlan_info *vi = link->l_info;
+
+       IS_VLAN_LINK_ASSERT(link);
+
+       vi->vi_flags_mask |= flags;
+       vi->vi_flags &= ~flags;
+       vi->vi_mask |= VLAN_HAS_FLAGS;
+
+       return 0;
+}
+
+/**
+ * Get VLAN flags
+ * @arg link           Link object
+ *
+ * @return VLAN flags, 0 if none set, or a negative error code.
+ */
+int rtnl_link_vlan_get_flags(struct rtnl_link *link)
+{
+       struct vlan_info *vi = link->l_info;
+
+       IS_VLAN_LINK_ASSERT(link);
+
+       return vi->vi_flags;
+}
+
+/** @} */
+
+/**
+ * @name Quality of Service
+ * @{
+ */
+
+int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from,
+                                  uint32_t to)
+{
+       struct vlan_info *vi = link->l_info;
+
+       IS_VLAN_LINK_ASSERT(link);
+
+       if (from < 0 || from > VLAN_PRIO_MAX)
+               return -NLE_INVAL;
+
+       vi->vi_ingress_qos[from] = to;
+       vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
+
+       return 0;
+}
+
+uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *link)
+{
+       struct vlan_info *vi = link->l_info;
+
+       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;
+       else
+               return NULL;
+}
+
+int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
+{
+       struct vlan_info *vi = link->l_info;
+
+       if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
+               return -NLE_OPNOTSUPP;
+
+       if (to < 0 || to > VLAN_PRIO_MAX)
+               return -NLE_INVAL;
+
+       if (vi->vi_negress >= vi->vi_egress_size) {
+               int new_size = vi->vi_egress_size + 32;
+               void *ptr;
+
+               ptr = realloc(vi->vi_egress_qos, new_size);
+               if (!ptr)
+                       return -NLE_NOMEM;
+
+               vi->vi_egress_qos = ptr;
+               vi->vi_egress_size = new_size;
+       }
+
+       vi->vi_egress_qos[vi->vi_negress].vm_from = from;
+       vi->vi_egress_qos[vi->vi_negress].vm_to = to;
+       vi->vi_negress++;
+       vi->vi_mask |= VLAN_HAS_EGRESS_QOS;
+
+       return 0;
+}
+
+struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link,
+                                              int *negress)
+{
+       struct vlan_info *vi = link->l_info;
+
+       if (link->l_info_ops != &vlan_info_ops || !link->l_info_ops)
+               return NULL;
+
+       if (negress == NULL)
+               return NULL;
+
+       if (vi->vi_mask & VLAN_HAS_EGRESS_QOS) {
+               *negress = vi->vi_negress;
+               return vi->vi_egress_qos;
+       } else {
+               *negress = 0;
+               return NULL;
+       }
+}
+
+/** @} */
+
+static const struct trans_tbl vlan_flags[] = {
+       __ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr)
+};
+
+/**
+ * @name Flag Translation
+ * @{
+ */
+
+char *rtnl_link_vlan_flags2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, vlan_flags, ARRAY_SIZE(vlan_flags));
+}
+
+int rtnl_link_vlan_str2flags(const char *name)
+{
+       return __str2flags(name, vlan_flags, ARRAY_SIZE(vlan_flags));
+}
+
+/** @} */
+
+
+static void __init vlan_init(void)
+{
+       rtnl_link_register_info(&vlan_info_ops);
+}
+
+static void __exit vlan_exit(void)
+{
+       rtnl_link_unregister_info(&vlan_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/neigh.c b/lib/route/neigh.c
new file mode 100644 (file)
index 0000000..ad26b4d
--- /dev/null
@@ -0,0 +1,962 @@
+/*
+ * lib/route/neigh.c   Neighbours
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup neigh Neighbours
+ * @brief
+ *
+ * The neighbour table establishes bindings between protocol addresses and
+ * link layer addresses for hosts sharing the same physical link. This
+ * module allows you to access and manipulate the content of these tables.
+ *
+ * @par Neighbour States
+ * @code
+ * NUD_INCOMPLETE
+ * NUD_REACHABLE
+ * NUD_STALE
+ * NUD_DELAY
+ * NUD_PROBE
+ * NUD_FAILED
+ * NUD_NOARP
+ * NUD_PERMANENT
+ * @endcode
+ *
+ * @par Neighbour Flags
+ * @code
+ * NTF_USE
+ * NTF_PROXY
+ * NTF_ROUTER
+ * @endcode
+ *
+ * @par Neighbour Identification
+ * A neighbour is uniquely identified by the attributes listed below, whenever
+ * you refer to an existing neighbour all of the attributes must be set.
+ * Neighbours from caches automatically have all required attributes set.
+ *   - interface index (rtnl_neigh_set_ifindex())
+ *   - destination address (rtnl_neigh_set_dst())
+ *
+ * @par Changeable Attributes
+ * \anchor neigh_changeable
+ *  - state (rtnl_neigh_set_state())
+ *  - link layer address (rtnl_neigh_set_lladdr())
+ *
+ * @par Required Caches for Dumping
+ * In order to dump neighbour attributes you must provide the following
+ * caches via nl_cache_provide()
+ *  - link cache holding all links
+ *
+ * @par TODO
+ *   - Document proxy settings
+ *   - Document states and their influence
+ *
+ * @par 1) Retrieving information about configured neighbours
+ * @code
+ * // The first step is to retrieve a list of all available neighbour within
+ * // the kernel and put them into a cache.
+ * struct nl_cache *cache = rtnl_neigh_alloc_cache(sk);
+ *
+ * // Neighbours can then be looked up by the interface and destination
+ * // address:
+ * struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr);
+ * 
+ * // After successful usage, the object must be given back to the cache
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ *
+ * @par 2) Adding new neighbours
+ * @code
+ * // Allocate an empty neighbour handle to be filled out with the attributes
+ * // of the new neighbour.
+ * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
+ *
+ * // Fill out the attributes of the new neighbour
+ * rtnl_neigh_set_ifindex(neigh, ifindex);
+ * rtnl_neigh_set_dst(neigh, dst_addr);
+ * rtnl_neigh_set_state(neigh, rtnl_neigh_str2state("permanent"));
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_neigh_build_add_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
+ *
+ * // Free the memory
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ *
+ * @par 3) Deleting an existing neighbour
+ * @code
+ * // Allocate an empty neighbour object to be filled out with the attributes
+ * // matching the neighbour to be deleted. Alternatively a fully equipped
+ * // neighbour object out of a cache can be used instead.
+ * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
+ *
+ * // Neighbours are uniquely identified by their interface index and
+ * // destination address, you may fill out other attributes but they
+ * // will have no influence.
+ * rtnl_neigh_set_ifindex(neigh, ifindex);
+ * rtnl_neigh_set_dst(neigh, dst_addr);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_neigh_build_delete_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_neigh_delete(sk, neigh, 0);
+ *
+ * // Free the memory
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ *
+ * @par 4) Changing neighbour attributes
+ * @code
+ * // Allocate an empty neighbour object to be filled out with the attributes
+ * // matching the neighbour to be changed and the new parameters. Alternatively
+ * // a fully equipped modified neighbour object out of a cache can be used.
+ * struct rtnl_neigh *neigh = rtnl_neigh_alloc();
+ *
+ * // Identify the neighbour to be changed by its interface index and
+ * // destination address
+ * rtnl_neigh_set_ifindex(neigh, ifindex);
+ * rtnl_neigh_set_dst(neigh, dst_addr);
+ *
+ * // The link layer address may be modified, if so it is wise to change
+ * // its state to "permanent" in order to avoid having it overwritten.
+ * rtnl_neigh_set_lladdr(neigh, lladdr);
+ *
+ * // Secondly the state can be modified allowing normal neighbours to be
+ * // converted into permanent entries or to manually confirm a neighbour.
+ * rtnl_neigh_set_state(neigh, state);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively the required
+ * // netlink message can be built using rtnl_neigh_build_change_request()
+ * // to be sent out using nl_send_auto_complete().
+ * rtnl_neigh_add(sk, neigh, NLM_F_REPLACE);
+ *
+ * // Free the memory
+ * rtnl_neigh_put(neigh);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/hashtable.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/neighbour.h>
+#include <netlink/route/link.h>
+#include <netlink/hashtable.h>
+
+/** @cond SKIP */
+#define NEIGH_ATTR_FLAGS        0x01
+#define NEIGH_ATTR_STATE        0x02
+#define NEIGH_ATTR_LLADDR       0x04
+#define NEIGH_ATTR_DST          0x08
+#define NEIGH_ATTR_CACHEINFO    0x10
+#define NEIGH_ATTR_IFINDEX      0x20
+#define NEIGH_ATTR_FAMILY       0x40
+#define NEIGH_ATTR_TYPE         0x80
+#define NEIGH_ATTR_PROBES       0x100
+#define NEIGH_ATTR_MASTER       0x200
+
+static struct nl_cache_ops rtnl_neigh_ops;
+static struct nl_object_ops neigh_obj_ops;
+/** @endcond */
+
+static void neigh_free_data(struct nl_object *c)
+{
+       struct rtnl_neigh *neigh = nl_object_priv(c);
+
+       if (!neigh)
+               return;
+
+       nl_addr_put(neigh->n_lladdr);
+       nl_addr_put(neigh->n_dst);
+}
+
+static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct rtnl_neigh *dst = nl_object_priv(_dst);
+       struct rtnl_neigh *src = nl_object_priv(_src);
+
+       if (src->n_lladdr)
+               if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
+                       return -NLE_NOMEM;
+
+       if (src->n_dst)
+               if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
+                       return -NLE_NOMEM;
+
+       return 0;
+}
+
+static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey,
+                        uint32_t table_sz)
+{
+       struct rtnl_neigh *neigh = (struct rtnl_neigh *) obj;
+       unsigned int nkey_sz;
+       struct nl_addr *addr = NULL;
+       struct neigh_hash_key {
+               uint32_t        n_family;
+               uint32_t        n_ifindex;
+               char            n_addr[0];
+       } __attribute__((packed)) *nkey;
+#ifdef NL_DEBUG
+       char buf[INET6_ADDRSTRLEN+5];
+#endif
+
+       if (neigh->n_family == AF_BRIDGE) {
+               if (neigh->n_lladdr)
+                       addr = neigh->n_lladdr;
+       } else if (neigh->n_dst) {
+               addr = neigh->n_dst;
+       }
+
+       nkey_sz = sizeof(*nkey);
+       if (addr)
+               nkey_sz += nl_addr_get_len(addr);
+
+       nkey = calloc(1, nkey_sz);
+       if (!nkey) {
+               *hashkey = 0;
+               return;
+       }
+       nkey->n_family = neigh->n_family;
+       if (neigh->n_family == AF_BRIDGE)
+               nkey->n_ifindex = neigh->n_master;
+       else
+               nkey->n_ifindex = neigh->n_ifindex;
+       if (addr)
+               memcpy(nkey->n_addr,
+                       nl_addr_get_binary_addr(addr),
+                       nl_addr_get_len(addr));
+
+       *hashkey = nl_hash(nkey, nkey_sz, 0) % table_sz;
+
+       NL_DBG(5, "neigh %p key (fam %d dev %d addr %s) keysz %d hash 0x%x\n",
+               neigh, nkey->n_family, nkey->n_ifindex,
+               nl_addr2str(addr, buf, sizeof(buf)),
+               nkey_sz, *hashkey);
+
+       free(nkey);
+
+       return;
+}
+
+static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
+       struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
+       int diff = 0;
+
+#define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= NEIGH_DIFF(IFINDEX,     a->n_ifindex != b->n_ifindex);
+       diff |= NEIGH_DIFF(FAMILY,      a->n_family != b->n_family);
+       diff |= NEIGH_DIFF(TYPE,        a->n_type != b->n_type);
+       diff |= NEIGH_DIFF(LLADDR,      nl_addr_cmp(a->n_lladdr, b->n_lladdr));
+       diff |= NEIGH_DIFF(DST,         nl_addr_cmp(a->n_dst, b->n_dst));
+       diff |= NEIGH_DIFF(MASTER,      a->n_master != b->n_master);
+
+       if (flags & LOOSE_COMPARISON) {
+               diff |= NEIGH_DIFF(STATE,
+                                 (a->n_state ^ b->n_state) & b->n_state_mask);
+               diff |= NEIGH_DIFF(FLAGS,
+                                 (a->n_flags ^ b->n_flags) & b->n_flag_mask);
+       } else {
+               diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state);
+               diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags);
+       }
+
+#undef NEIGH_DIFF
+
+       return diff;
+}
+
+static const struct trans_tbl neigh_attrs[] = {
+       __ADD(NEIGH_ATTR_FLAGS, flags)
+       __ADD(NEIGH_ATTR_STATE, state)
+       __ADD(NEIGH_ATTR_LLADDR, lladdr)
+       __ADD(NEIGH_ATTR_DST, dst)
+       __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
+       __ADD(NEIGH_ATTR_IFINDEX, ifindex)
+       __ADD(NEIGH_ATTR_FAMILY, family)
+       __ADD(NEIGH_ATTR_TYPE, type)
+       __ADD(NEIGH_ATTR_PROBES, probes)
+};
+
+static char *neigh_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, neigh_attrs,
+                          ARRAY_SIZE(neigh_attrs));
+}
+
+static uint32_t neigh_id_attrs_get(struct nl_object *obj)
+{
+       struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj;
+
+       if (neigh->n_family == AF_BRIDGE)
+               return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_MASTER);
+       else
+               return (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY);
+}
+
+static struct nla_policy neigh_policy[NDA_MAX+1] = {
+       [NDA_CACHEINFO] = { .minlen = sizeof(struct nda_cacheinfo) },
+       [NDA_PROBES]    = { .type = NLA_U32 },
+};
+
+static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                           struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+       struct rtnl_neigh *neigh;
+       int err;
+
+       if ((err = rtnl_neigh_parse(n, &neigh)) < 0)
+               return err;
+
+       err = pp->pp_cb((struct nl_object *) neigh, pp);
+
+       rtnl_neigh_put(neigh);
+       return err;
+}
+
+
+int rtnl_neigh_parse(struct nlmsghdr *n, struct rtnl_neigh **result)
+{
+       struct rtnl_neigh *neigh;
+       struct nlattr *tb[NDA_MAX + 1];
+       struct ndmsg *nm;
+       int err;
+
+       neigh = rtnl_neigh_alloc();
+       if (!neigh) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       neigh->ce_msgtype = n->nlmsg_type;
+       nm = nlmsg_data(n);
+
+       err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy);
+       if (err < 0)
+               goto errout;
+
+       neigh->n_family  = nm->ndm_family;
+       neigh->n_ifindex = nm->ndm_ifindex;
+       neigh->n_state   = nm->ndm_state;
+       neigh->n_flags   = nm->ndm_flags;
+       neigh->n_type    = nm->ndm_type;
+
+       neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
+                          NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
+                          NEIGH_ATTR_TYPE);
+
+       if (tb[NDA_LLADDR]) {
+               neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC);
+               if (!neigh->n_lladdr) {
+                       err = -NLE_NOMEM;
+                       goto errout;
+               }
+               nl_addr_set_family(neigh->n_lladdr,
+                                  nl_addr_guess_family(neigh->n_lladdr));
+               neigh->ce_mask |= NEIGH_ATTR_LLADDR;
+       }
+
+       if (tb[NDA_DST]) {
+               neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family);
+               if (!neigh->n_dst) {
+                       err = -NLE_NOMEM;
+                       goto errout;
+               }
+               neigh->ce_mask |= NEIGH_ATTR_DST;
+       }
+
+       if (tb[NDA_CACHEINFO]) {
+               struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]);
+
+               neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
+               neigh->n_cacheinfo.nci_used = ci->ndm_used;
+               neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
+               neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
+               
+               neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
+       }
+
+       if (tb[NDA_PROBES]) {
+               neigh->n_probes = nla_get_u32(tb[NDA_PROBES]);
+               neigh->ce_mask |= NEIGH_ATTR_PROBES;
+       }
+
+       /*
+        * Get the bridge index for AF_BRIDGE family entries
+        */
+       if (neigh->n_family == AF_BRIDGE) {
+               struct nl_cache *lcache = nl_cache_mngt_require_safe("route/link");
+               if (lcache ) {
+                       struct rtnl_link *link = rtnl_link_get(lcache,
+                                                       neigh->n_ifindex);
+                       if (link) {
+                               neigh->n_master = link->l_master;
+                               rtnl_link_put(link);
+                               neigh->ce_mask |= NEIGH_ATTR_MASTER;
+                       }
+
+                       nl_cache_put(lcache);
+               }
+       }
+
+       *result = neigh;
+       return 0;
+
+errout:
+       rtnl_neigh_put(neigh);
+       return err;
+}
+
+static int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+       int family = c->c_iarg1;
+
+       return nl_rtgen_request(h, RTM_GETNEIGH, family, NLM_F_DUMP);
+}
+
+
+static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+       char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
+       struct rtnl_neigh *n = (struct rtnl_neigh *) a;
+       struct nl_cache *link_cache;
+       char state[128], flags[64];
+
+       link_cache = nl_cache_mngt_require_safe("route/link");
+
+       if (n->n_family != AF_BRIDGE)
+               nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
+
+       if (link_cache)
+               nl_dump(p, "dev %s ",
+                       rtnl_link_i2name(link_cache, n->n_ifindex,
+                                        state, sizeof(state)));
+       else
+               nl_dump(p, "dev %d ", n->n_ifindex);
+
+       if (n->ce_mask & NEIGH_ATTR_LLADDR)
+               nl_dump(p, "lladdr %s ",
+                       nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
+
+       rtnl_neigh_state2str(n->n_state, state, sizeof(state));
+       rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
+
+       if (state[0])
+               nl_dump(p, "<%s", state);
+       if (flags[0])
+               nl_dump(p, "%s%s", state[0] ? "," : "<", flags);
+       if (state[0] || flags[0])
+               nl_dump(p, ">");
+       nl_dump(p, "\n");
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+       char rtn_type[32];
+       struct rtnl_neigh *n = (struct rtnl_neigh *) a;
+       int hz = nl_get_user_hz();
+
+       neigh_dump_line(a, p);
+
+       nl_dump_line(p, "    refcnt %u type %s confirmed %u used "
+                               "%u updated %u\n",
+               n->n_cacheinfo.nci_refcnt,
+               nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
+               n->n_cacheinfo.nci_confirmed/hz,
+               n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
+}
+
+static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
+{
+       neigh_dump_details(a, p);
+}
+
+/**
+ * @name Neighbour Object Allocation/Freeage
+ * @{
+ */
+
+struct rtnl_neigh *rtnl_neigh_alloc(void)
+{
+       return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops);
+}
+
+void rtnl_neigh_put(struct rtnl_neigh *neigh)
+{
+       nl_object_put((struct nl_object *) neigh);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Cache Managament
+ * @{
+ */
+
+/**
+ * Build a neighbour cache including all neighbours currently configured in the kernel.
+ * @arg sock           Netlink socket.
+ * @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.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+       return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
+}
+
+/**
+ * Look up a neighbour by interface index and destination address
+ * @arg cache          neighbour cache
+ * @arg ifindex                interface index the neighbour is on
+ * @arg dst            destination address of the neighbour
+ *
+ * @return neighbour handle or NULL if no match was found.
+ */
+struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
+                                  struct nl_addr *dst)
+{
+       struct rtnl_neigh *neigh;
+
+       nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
+               if (neigh->n_ifindex == ifindex &&
+                   !nl_addr_cmp(neigh->n_dst, dst)) {
+                       nl_object_get((struct nl_object *) neigh);
+                       return neigh;
+               }
+       }
+
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Addition
+ * @{
+ */
+
+static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
+                          struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct ndmsg nhdr = {
+               .ndm_ifindex = tmpl->n_ifindex,
+               .ndm_state = NUD_PERMANENT,
+       };
+
+       if (tmpl->n_family != AF_BRIDGE) {
+               if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
+                       return -NLE_MISSING_ATTR;
+               nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
+       }
+       else
+               nhdr.ndm_family = AF_BRIDGE;
+
+       if (tmpl->ce_mask & NEIGH_ATTR_FLAGS)
+               nhdr.ndm_flags = tmpl->n_flags;
+
+       if (tmpl->ce_mask & NEIGH_ATTR_STATE)
+               nhdr.ndm_state = tmpl->n_state;
+
+       msg = nlmsg_alloc_simple(cmd, flags);
+       if (!msg)
+               return -NLE_NOMEM;
+
+       if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       if (tmpl->n_family != AF_BRIDGE)
+               NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
+
+       if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
+               NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       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
+ * all relevant fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed. \a tmpl must contain the attributes of the new
+ * neighbour set via \c rtnl_neigh_set_* functions.
+ * 
+ * The following attributes must be set in the template:
+ *  - Interface index (rtnl_neigh_set_ifindex())
+ *  - State (rtnl_neigh_set_state())
+ *  - Destination address (rtnl_neigh_set_dst())
+ *  - Link layer address (rtnl_neigh_set_lladdr())
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
+                                struct nl_msg **result)
+{
+       return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
+}
+
+/**
+ * Add a new neighbour
+ * @arg sk             Netlink socket.
+ * @arg tmpl           template with requested changes
+ * @arg flags          additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_neigh_build_add_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * The following attributes must be set in the template:
+ *  - Interface index (rtnl_neigh_set_ifindex())
+ *  - State (rtnl_neigh_set_state())
+ *  - Destination address (rtnl_neigh_set_dst())
+ *  - Link layer address (rtnl_neigh_set_lladdr())
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
+{
+       int err;
+       struct nl_msg *msg;
+       
+       if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Deletion
+ * @{
+ */
+
+/**
+ * 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
+ * fields and must thus be sent out via nl_send_auto_complete()
+ * or supplemented as needed. \a neigh must point to an existing
+ * neighbour.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
+                                   struct nl_msg **result)
+{
+       return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
+}
+
+/**
+ * Delete a neighbour
+ * @arg sk             Netlink socket.
+ * @arg neigh          neighbour to delete
+ * @arg flags          additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_neigh_build_delete_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
+                     int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour States Translations
+ * @{
+ */
+
+static const struct trans_tbl neigh_states[] = {
+       __ADD(NUD_INCOMPLETE, incomplete)
+       __ADD(NUD_REACHABLE, reachable)
+       __ADD(NUD_STALE, stale)
+       __ADD(NUD_DELAY, delay)
+       __ADD(NUD_PROBE, probe)
+       __ADD(NUD_FAILED, failed)
+       __ADD(NUD_NOARP, norarp)
+       __ADD(NUD_PERMANENT, permanent)
+};
+
+char * rtnl_neigh_state2str(int state, char *buf, size_t len)
+{
+       return __flags2str(state, buf, len, neigh_states,
+           ARRAY_SIZE(neigh_states));
+}
+
+int rtnl_neigh_str2state(const char *name)
+{
+       return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Flags Translations
+ * @{
+ */
+
+static const struct trans_tbl neigh_flags[] = {
+       __ADD(NTF_USE, use)
+       __ADD(NTF_PROXY, proxy)
+       __ADD(NTF_ROUTER, router)
+};
+
+char * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, neigh_flags,
+           ARRAY_SIZE(neigh_flags));
+}
+
+int rtnl_neigh_str2flag(const char *name)
+{
+       return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state)
+{
+       neigh->n_state_mask |= state;
+       neigh->n_state |= state;
+       neigh->ce_mask |= NEIGH_ATTR_STATE;
+}
+
+int rtnl_neigh_get_state(struct rtnl_neigh *neigh)
+{
+       if (neigh->ce_mask & NEIGH_ATTR_STATE)
+               return neigh->n_state;
+       else
+               return -1;
+}
+
+void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state)
+{
+       neigh->n_state_mask |= state;
+       neigh->n_state &= ~state;
+       neigh->ce_mask |= NEIGH_ATTR_STATE;
+}
+
+void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags)
+{
+       neigh->n_flag_mask |= flags;
+       neigh->n_flags |= flags;
+       neigh->ce_mask |= NEIGH_ATTR_FLAGS;
+}
+
+unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh)
+{
+       return neigh->n_flags;
+}
+
+void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags)
+{
+       neigh->n_flag_mask |= flags;
+       neigh->n_flags &= ~flags;
+       neigh->ce_mask |= NEIGH_ATTR_FLAGS;
+}
+
+void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
+{
+       neigh->n_ifindex = ifindex;
+       neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
+}
+
+int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
+{
+       return neigh->n_ifindex;
+}
+
+static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
+                               struct nl_addr *new, int flag, int nocheck)
+{
+       if (!nocheck) {
+               if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
+                       if (new->a_family != neigh->n_family)
+                               return -NLE_AF_MISMATCH;
+               } else {
+                       neigh->n_family = new->a_family;
+                       neigh->ce_mask |= NEIGH_ATTR_FAMILY;
+               }
+       }
+
+       if (*pos)
+               nl_addr_put(*pos);
+
+       nl_addr_get(new);
+       *pos = new;
+
+       neigh->ce_mask |= flag;
+
+       return 0;
+}
+
+void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr)
+{
+       __assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
+}
+
+struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh)
+{
+       if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
+               return neigh->n_lladdr;
+       else
+               return NULL;
+}
+
+int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr)
+{
+       return __assign_addr(neigh, &neigh->n_dst, addr,
+                            NEIGH_ATTR_DST, 0);
+}
+
+struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh)
+{
+       if (neigh->ce_mask & NEIGH_ATTR_DST)
+               return neigh->n_dst;
+       else
+               return NULL;
+}
+
+void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
+{
+       neigh->n_family = family;
+       neigh->ce_mask |= NEIGH_ATTR_FAMILY;
+}
+
+int rtnl_neigh_get_family(struct rtnl_neigh *neigh)
+{
+       return neigh->n_family;
+}
+
+void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
+{
+       neigh->n_type = type;
+       neigh->ce_mask = NEIGH_ATTR_TYPE;
+}
+
+int rtnl_neigh_get_type(struct rtnl_neigh *neigh)
+{
+       if (neigh->ce_mask & NEIGH_ATTR_TYPE)
+               return neigh->n_type;
+       else
+               return -1;
+}
+
+/** @} */
+
+static struct nl_object_ops neigh_obj_ops = {
+       .oo_name                = "route/neigh",
+       .oo_size                = sizeof(struct rtnl_neigh),
+       .oo_free_data           = neigh_free_data,
+       .oo_clone               = neigh_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = neigh_dump_line,
+           [NL_DUMP_DETAILS]   = neigh_dump_details,
+           [NL_DUMP_STATS]     = neigh_dump_stats,
+       },
+       .oo_compare             = neigh_compare,
+       .oo_keygen              = neigh_keygen,
+       .oo_attrs2str           = neigh_attrs2str,
+       .oo_id_attrs            = (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
+       .oo_id_attrs_get        = neigh_id_attrs_get
+};
+
+static struct nl_af_group neigh_groups[] = {
+       { AF_UNSPEC, RTNLGRP_NEIGH },
+       { AF_BRIDGE, RTNLGRP_NEIGH },
+       { END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_neigh_ops = {
+       .co_name                = "route/neigh",
+       .co_hdrsize             = sizeof(struct ndmsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWNEIGH, NL_ACT_NEW, "new" },
+                                       { RTM_DELNEIGH, NL_ACT_DEL, "del" },
+                                       { RTM_GETNEIGH, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_groups              = neigh_groups,
+       .co_request_update      = neigh_request_update,
+       .co_msg_parser          = neigh_msg_parser,
+       .co_obj_ops             = &neigh_obj_ops,
+};
+
+static void __init neigh_init(void)
+{
+       nl_cache_mngt_register(&rtnl_neigh_ops);
+}
+
+static void __exit neigh_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_neigh_ops);
+}
+
+/** @} */
diff --git a/lib/route/neightbl.c b/lib/route/neightbl.c
new file mode 100644 (file)
index 0000000..f9c9c27
--- /dev/null
@@ -0,0 +1,827 @@
+/*
+ * lib/route/neightbl.c         neighbour tables
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup neightbl Neighbour Tables
+ * @brief
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/neightbl.h>
+#include <netlink/route/link.h>
+
+/** @cond SKIP */
+#define NEIGHTBL_ATTR_FAMILY       0x001
+#define NEIGHTBL_ATTR_STATS        0x002
+#define NEIGHTBL_ATTR_NAME       0x004
+#define NEIGHTBL_ATTR_THRESH1    0x008
+#define NEIGHTBL_ATTR_THRESH2    0x010
+#define NEIGHTBL_ATTR_THRESH3    0x020
+#define NEIGHTBL_ATTR_CONFIG     0x040
+#define NEIGHTBL_ATTR_PARMS      0x080
+#define NEIGHTBL_ATTR_GC_INTERVAL  0x100
+
+#define NEIGHTBLPARM_ATTR_IFINDEX      0x0001
+#define NEIGHTBLPARM_ATTR_REFCNT               0x0002
+#define NEIGHTBLPARM_ATTR_QUEUE_LEN    0x0004
+#define NEIGHTBLPARM_ATTR_APP_PROBES   0x0008
+#define NEIGHTBLPARM_ATTR_UCAST_PROBES 0x0010
+#define NEIGHTBLPARM_ATTR_MCAST_PROBES 0x0020
+#define NEIGHTBLPARM_ATTR_PROXY_QLEN   0x0040
+#define NEIGHTBLPARM_ATTR_REACHABLE_TIME       0x0080
+#define NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME 0x0100
+#define NEIGHTBLPARM_ATTR_RETRANS_TIME 0x0200
+#define NEIGHTBLPARM_ATTR_GC_STALETIME 0x0400
+#define NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME 0x0800
+#define NEIGHTBLPARM_ATTR_ANYCAST_DELAY        0x1000
+#define NEIGHTBLPARM_ATTR_PROXY_DELAY  0x2000
+#define NEIGHTBLPARM_ATTR_LOCKTIME     0x4000
+
+static struct nl_cache_ops rtnl_neightbl_ops;
+static struct nl_object_ops neightbl_obj_ops;
+/** @endcond */
+
+static int neightbl_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       struct rtnl_neightbl *a = (struct rtnl_neightbl *) _a;
+       struct rtnl_neightbl *b = (struct rtnl_neightbl *) _b;
+       int diff = 0;
+
+#define NT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGHTBL_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= NT_DIFF(FAMILY,         a->nt_family != b->nt_family);
+       diff |= NT_DIFF(NAME,           strcmp(a->nt_name, b->nt_name));
+       diff |= NT_DIFF(THRESH1,        a->nt_gc_thresh1 != b->nt_gc_thresh1);
+       diff |= NT_DIFF(THRESH2,        a->nt_gc_thresh2 != b->nt_gc_thresh2);
+       diff |= NT_DIFF(THRESH3,        a->nt_gc_thresh3 != b->nt_gc_thresh3);
+       diff |= NT_DIFF(GC_INTERVAL,    a->nt_gc_interval != b->nt_gc_interval);
+
+#undef NT_DIFF
+
+       if (!(a->ce_mask & NEIGHTBL_ATTR_PARMS) &&
+           !(b->ce_mask & NEIGHTBL_ATTR_PARMS))
+               return diff;
+
+       /* XXX: FIXME: Compare parameter table */
+
+
+#if 0
+#define REQ(F) (fp->ntp_mask & NEIGHTBLPARM_ATTR_##F)
+#define AVAIL(F) (op->ntp_mask & NEIGHTBLPARM_ATTR_##F)
+#define _C(F, N) (REQ(F) && (!AVAIL(F) || (op->N != fp->N)))
+       if (_C(IFINDEX,                 ntp_ifindex)                    ||
+           _C(QUEUE_LEN,               ntp_queue_len)                  ||
+           _C(APP_PROBES,              ntp_app_probes)                 ||
+           _C(UCAST_PROBES,            ntp_ucast_probes)               ||
+           _C(MCAST_PROBES,            ntp_mcast_probes)               ||
+           _C(PROXY_QLEN,              ntp_proxy_qlen)                 ||
+           _C(LOCKTIME,                ntp_locktime)                   ||
+           _C(RETRANS_TIME,            ntp_retrans_time)               ||
+           _C(BASE_REACHABLE_TIME,     ntp_base_reachable_time)        ||
+           _C(GC_STALETIME,            ntp_gc_stale_time)              ||
+           _C(DELAY_PROBE_TIME,        ntp_probe_delay)                ||
+           _C(ANYCAST_DELAY,           ntp_anycast_delay)              ||
+           _C(PROXY_DELAY,             ntp_proxy_delay))
+               return 0;
+#undef REQ
+#undef AVAIL
+#undef _C
+#endif
+
+       return diff;
+}
+
+
+static struct nla_policy neightbl_policy[NDTA_MAX+1] = {
+       [NDTA_NAME]             = { .type = NLA_STRING,
+                                   .maxlen = NTBLNAMSIZ },
+       [NDTA_THRESH1]          = { .type = NLA_U32 },
+       [NDTA_THRESH2]          = { .type = NLA_U32 },
+       [NDTA_THRESH3]          = { .type = NLA_U32 },
+       [NDTA_GC_INTERVAL]      = { .type = NLA_U32 },
+       [NDTA_CONFIG]           = { .minlen = sizeof(struct ndt_config) },
+       [NDTA_STATS]            = { .minlen = sizeof(struct ndt_stats) },
+       [NDTA_PARMS]            = { .type = NLA_NESTED },
+};
+
+static int neightbl_msg_parser(struct nl_cache_ops *ops,
+                              struct sockaddr_nl *who, struct nlmsghdr *n,
+                              struct nl_parser_param *pp)
+{
+       struct rtnl_neightbl *ntbl;
+       struct nlattr *tb[NDTA_MAX + 1];
+       struct rtgenmsg *rtmsg;
+       int err;
+
+       ntbl = rtnl_neightbl_alloc();
+       if (!ntbl) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       ntbl->ce_msgtype = n->nlmsg_type;
+       rtmsg = nlmsg_data(n);
+       
+       err = nlmsg_parse(n, sizeof(*rtmsg), tb, NDTA_MAX, neightbl_policy);
+       if (err < 0)
+               goto errout;
+
+       ntbl->nt_family = rtmsg->rtgen_family;
+
+       if (tb[NDTA_NAME] == NULL) {
+               err = -NLE_MISSING_ATTR;
+               goto errout;
+       }
+
+       nla_strlcpy(ntbl->nt_name, tb[NDTA_NAME], NTBLNAMSIZ);
+       ntbl->ce_mask |= NEIGHTBL_ATTR_NAME;
+
+       if (tb[NDTA_THRESH1]) {
+               ntbl->nt_gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
+               ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1;
+       }
+
+       if (tb[NDTA_THRESH2]) {
+               ntbl->nt_gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
+               ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2;
+       }
+
+       if (tb[NDTA_THRESH3]) {
+               ntbl->nt_gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
+               ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3;
+       }
+
+       if (tb[NDTA_GC_INTERVAL]) {
+               ntbl->nt_gc_interval = nla_get_u32(tb[NDTA_GC_INTERVAL]);
+               ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL;
+       }
+
+       if (tb[NDTA_CONFIG]) {
+               nla_memcpy(&ntbl->nt_config, tb[NDTA_CONFIG],
+                          sizeof(ntbl->nt_config));
+               ntbl->ce_mask |= NEIGHTBL_ATTR_CONFIG;
+       }
+
+       if (tb[NDTA_STATS]) {
+               nla_memcpy(&ntbl->nt_stats, tb[NDTA_STATS],
+                          sizeof(ntbl->nt_stats));
+               ntbl->ce_mask |= NEIGHTBL_ATTR_STATS;
+       }
+
+       if (tb[NDTA_PARMS]) {
+               struct nlattr *tbp[NDTPA_MAX + 1];
+               struct rtnl_neightbl_parms *p = &ntbl->nt_parms;
+
+               err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], NULL);
+               if (err < 0)
+                       goto errout;
+
+#define COPY_ENTRY(name, var) \
+               if (tbp[NDTPA_ ##name]) { \
+                       p->ntp_ ##var = nla_get_u32(tbp[NDTPA_ ##name]); \
+                       p->ntp_mask |= NEIGHTBLPARM_ATTR_ ##name; \
+               }
+
+               COPY_ENTRY(IFINDEX, ifindex);
+               COPY_ENTRY(REFCNT, refcnt);
+               COPY_ENTRY(QUEUE_LEN, queue_len);
+               COPY_ENTRY(APP_PROBES, app_probes);
+               COPY_ENTRY(UCAST_PROBES, ucast_probes);
+               COPY_ENTRY(MCAST_PROBES, mcast_probes);
+               COPY_ENTRY(PROXY_QLEN, proxy_qlen);
+               COPY_ENTRY(PROXY_DELAY, proxy_delay);
+               COPY_ENTRY(ANYCAST_DELAY, anycast_delay);
+               COPY_ENTRY(LOCKTIME, locktime);
+               COPY_ENTRY(REACHABLE_TIME, reachable_time);
+               COPY_ENTRY(BASE_REACHABLE_TIME, base_reachable_time);
+               COPY_ENTRY(RETRANS_TIME, retrans_time);
+               COPY_ENTRY(GC_STALETIME, gc_stale_time);
+               COPY_ENTRY(DELAY_PROBE_TIME, probe_delay);
+#undef COPY_ENTRY
+
+               ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+       }
+
+       err = pp->pp_cb((struct nl_object *) ntbl, pp);
+errout:
+       rtnl_neightbl_put(ntbl);
+       return err;
+}
+
+static int neightbl_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+       return nl_rtgen_request(h, RTM_GETNEIGHTBL, AF_UNSPEC, NLM_F_DUMP);
+}
+
+
+static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p)
+{
+       struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+
+       nl_dump_line(p, "%s", ntbl->nt_name);
+
+       if (ntbl->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) {
+               struct nl_cache *link_cache;
+               
+               link_cache = nl_cache_mngt_require_safe("route/link");
+
+               if (link_cache) {
+                       char buf[32];
+                       nl_dump(p, "<%s> ",
+                               rtnl_link_i2name(link_cache,
+                                                ntbl->nt_parms.ntp_ifindex,
+                                                buf, sizeof(buf)));
+                       nl_cache_put(link_cache);
+               } else
+                       nl_dump(p, "<%u> ", ntbl->nt_parms.ntp_ifindex);
+       } else
+               nl_dump(p, " ");
+
+       if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG)
+               nl_dump(p, "entries %u ", ntbl->nt_config.ndtc_entries);
+
+       if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
+               char rt[32], rt2[32];
+               struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
+
+               nl_dump(p, "reachable-time %s retransmit-time %s",
+                       nl_msec2str(pa->ntp_reachable_time, rt, sizeof(rt)),
+                       nl_msec2str(pa->ntp_retrans_time, rt2, sizeof(rt2)));
+       }
+
+       nl_dump(p, "\n");
+}
+
+static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *p)
+{
+       char x[32], y[32], z[32];
+       struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+
+       neightbl_dump_line(arg, p);
+
+       if (ntbl->ce_mask & NEIGHTBL_ATTR_CONFIG) {
+               nl_dump_line(p, "    key-len %u entry-size %u last-flush %s\n",
+                       ntbl->nt_config.ndtc_key_len,
+                       ntbl->nt_config.ndtc_entry_size,
+                       nl_msec2str(ntbl->nt_config.ndtc_last_flush,
+                                     x, sizeof(x)));
+
+               nl_dump_line(p, "    gc threshold %u/%u/%u interval %s " \
+                           "chain-position %u\n",
+                       ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2,
+                       ntbl->nt_gc_thresh3,
+                       nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)),
+                       ntbl->nt_config.ndtc_hash_chain_gc);
+
+               nl_dump_line(p, "    hash-rand 0x%08X/0x%08X last-rand %s\n",
+                       ntbl->nt_config.ndtc_hash_rnd,
+                       ntbl->nt_config.ndtc_hash_mask,
+                       nl_msec2str(ntbl->nt_config.ndtc_last_rand,
+                                     x, sizeof(x)));
+       }
+
+       if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
+               struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
+
+               nl_dump_line(p, "    refcnt %u pending-queue-limit %u " \
+                           "proxy-delayed-queue-limit %u\n",
+                       pa->ntp_refcnt,
+                       pa->ntp_queue_len,
+                       pa->ntp_proxy_qlen);
+
+               nl_dump_line(p, "    num-userspace-probes %u num-unicast-probes " \
+                           "%u num-multicast-probes %u\n",
+                       pa->ntp_app_probes,
+                       pa->ntp_ucast_probes,
+                       pa->ntp_mcast_probes);
+
+               nl_dump_line(p, "    min-age %s base-reachable-time %s " \
+                           "stale-check-interval %s\n",
+                       nl_msec2str(pa->ntp_locktime, x, sizeof(x)),
+                       nl_msec2str(pa->ntp_base_reachable_time,
+                                     y, sizeof(y)),
+                       nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z)));
+
+               nl_dump_line(p, "    initial-probe-delay %s answer-delay %s " \
+                           "proxy-answer-delay %s\n",
+                       nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)),
+                       nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)),
+                       nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z)));
+       }
+}
+
+static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
+{
+       struct rtnl_neightbl *ntbl = (struct rtnl_neightbl *) arg;
+
+       neightbl_dump_details(arg, p);
+
+       if (!(ntbl->ce_mask & NEIGHTBL_ATTR_STATS))
+               return;
+
+       nl_dump_line(p, "   " \
+                    " lookups %" PRIu64 \
+                    " hits %" PRIu64 \
+                    " failed %" PRIu64 \
+                   " allocations %" PRIu64 \
+                    " destroys %" PRIu64 \
+                    "\n",
+               ntbl->nt_stats.ndts_lookups,
+               ntbl->nt_stats.ndts_hits,
+               ntbl->nt_stats.ndts_res_failed,
+               ntbl->nt_stats.ndts_allocs,
+               ntbl->nt_stats.ndts_destroys);
+
+       nl_dump_line(p, "   " \
+                        " hash-grows %" PRIu64 \
+                        " forced-gc-runs %" PRIu64 \
+                        " periodic-gc-runs %" PRIu64 \
+                        "\n",
+               ntbl->nt_stats.ndts_hash_grows,
+               ntbl->nt_stats.ndts_forced_gc_runs,
+               ntbl->nt_stats.ndts_periodic_gc_runs);
+
+       nl_dump_line(p, "   " \
+                        " rcv-unicast-probes %" PRIu64 \
+                        " rcv-multicast-probes %" PRIu64 \
+                        "\n",
+               ntbl->nt_stats.ndts_rcv_probes_ucast,
+               ntbl->nt_stats.ndts_rcv_probes_mcast);
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_neightbl *rtnl_neightbl_alloc(void)
+{
+       return (struct rtnl_neightbl *) nl_object_alloc(&neightbl_obj_ops);
+}
+
+void rtnl_neightbl_put(struct rtnl_neightbl *neightbl)
+{
+       nl_object_put((struct nl_object *) neightbl);
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Table Cache Management
+ * @{
+ */
+
+/**
+ * Build a neighbour table cache including all neighbour tables currently configured in the kernel.
+ * @arg sk             Netlink socket.
+ * @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.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neightbl_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+       return nl_cache_alloc_and_fill(&rtnl_neightbl_ops, sk, result);
+}
+
+/**
+ * Lookup neighbour table by name and optional interface index
+ * @arg cache          neighbour table cache
+ * @arg name           name of table
+ * @arg ifindex                optional interface index
+ *
+ * Looks up the neighbour table matching the specified name and
+ * optionally the specified ifindex to retrieve device specific
+ * parameter sets.
+ *
+ * @return ptr to neighbour table inside the cache or NULL if no
+ *         match was found.
+ */
+struct rtnl_neightbl *rtnl_neightbl_get(struct nl_cache *cache,
+                                       const char *name, int ifindex)
+{
+       struct rtnl_neightbl *nt;
+
+       if (cache->c_ops != &rtnl_neightbl_ops)
+               return NULL;
+
+       nl_list_for_each_entry(nt, &cache->c_items, ce_list) {
+               if (!strcasecmp(nt->nt_name, name) &&
+                   ((!ifindex && !nt->nt_parms.ntp_ifindex) ||
+                    (ifindex && ifindex == nt->nt_parms.ntp_ifindex))) {
+                       nl_object_get((struct nl_object *) nt);
+                       return nt;
+               }
+       }
+
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Neighbour Table Modifications
+ * @{
+ */
+
+/**
+ * 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
+ * relevant fields and must be sent out via nl_send_auto_complete() or
+ * supplemented as needed.
+ * \a old must point to a neighbour table currently configured in the
+ * kernel and \a tmpl must contain the attributes to be changed set via
+ * \c rtnl_neightbl_set_* functions.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neightbl_build_change_request(struct rtnl_neightbl *old,
+                                      struct rtnl_neightbl *tmpl,
+                                      struct nl_msg **result)
+{
+       struct nl_msg *m, *parms = NULL;
+       struct ndtmsg ndt = {
+               .ndtm_family = old->nt_family,
+       };
+
+       m = nlmsg_alloc_simple(RTM_SETNEIGHTBL, 0);
+       if (!m)
+               return -NLE_NOMEM;
+
+       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);
+
+       if (tmpl->ce_mask & NEIGHTBL_ATTR_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);
+
+       if (tmpl->ce_mask & NEIGHTBL_ATTR_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;
+
+               parms = nlmsg_alloc();
+               if (!parms)
+                       goto nla_put_failure;
+
+               if (old->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_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);
+
+               if (p->ntp_mask & NEIGHTBLPARM_ATTR_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,
+                                   p->ntp_ucast_probes);
+
+               if (p->ntp_mask & NEIGHTBLPARM_ATTR_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,
+                                   p->ntp_proxy_qlen);
+
+               if (p->ntp_mask & NEIGHTBLPARM_ATTR_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,
+                                   p->ntp_retrans_time);
+
+               if (p->ntp_mask & NEIGHTBLPARM_ATTR_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,
+                                   p->ntp_proxy_delay);
+
+               if (p->ntp_mask & NEIGHTBLPARM_ATTR_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,
+                                             p->ntp_proxy_delay);
+
+               if (p->ntp_mask & NEIGHTBLPARM_ATTR_LOCKTIME)
+                       NLA_PUT_U64(parms, NDTPA_LOCKTIME, p->ntp_locktime);
+
+               if (nla_put_nested(m, NDTA_PARMS, parms) < 0)
+                       goto nla_put_failure;
+
+               nlmsg_free(parms);
+       }
+
+       *result = m;
+       return 0;
+
+nla_put_failure:
+       if (parms)
+               nlmsg_free(parms);
+       nlmsg_free(m);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * Change neighbour table attributes
+ * @arg sk             Netlink socket.
+ * @arg old            neighbour table to be changed
+ * @arg tmpl           template with requested changes
+ *
+ * Builds a new netlink message by calling
+ * rtnl_neightbl_build_change_request(), sends the request to the
+ * kernel and waits for the next ACK to be received, i.e. blocks
+ * until the request has been processed.
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_neightbl_change(struct nl_sock *sk, struct rtnl_neightbl *old,
+                        struct rtnl_neightbl *tmpl)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_neightbl_build_change_request(old, tmpl, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+void rtnl_neightbl_set_family(struct rtnl_neightbl *ntbl, int family)
+{
+       ntbl->nt_family = family;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_FAMILY;
+}
+
+void rtnl_neightbl_set_gc_interval(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+       ntbl->nt_gc_interval = ms;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_GC_INTERVAL;
+}
+
+void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *ntbl, int thresh)
+{
+       ntbl->nt_gc_thresh1 = thresh;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH1;
+}
+
+void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *ntbl, int thresh)
+{
+       ntbl->nt_gc_thresh2 = thresh;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH2;
+}
+
+void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *ntbl, int thresh)
+{
+       ntbl->nt_gc_thresh3 = thresh;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_THRESH3;
+}
+
+void rtnl_neightbl_set_name(struct rtnl_neightbl *ntbl, const char *name)
+{
+       strncpy(ntbl->nt_name, name, sizeof(ntbl->nt_name) - 1);
+       ntbl->ce_mask |= NEIGHTBL_ATTR_NAME;
+}
+
+void rtnl_neightbl_set_dev(struct rtnl_neightbl *ntbl, int ifindex)
+{
+       ntbl->nt_parms.ntp_ifindex = ifindex;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_IFINDEX;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the queue length for pending requests of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg len            new queue len
+ */
+void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *ntbl, int len)
+{
+       ntbl->nt_parms.ntp_queue_len = len;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_QUEUE_LEN;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the queue length for delay proxy arp requests of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg len            new queue len
+ */
+void rtnl_neightbl_set_proxy_queue_len(struct rtnl_neightbl *ntbl, int len)
+{
+       ntbl->nt_parms.ntp_proxy_qlen = len;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_QLEN;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the number of application probes of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg probes         new probes value
+ */
+void rtnl_neightbl_set_app_probes(struct rtnl_neightbl *ntbl, int probes)
+{
+       ntbl->nt_parms.ntp_app_probes = probes;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_APP_PROBES;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the number of unicast probes of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg probes         new probes value
+ */
+void rtnl_neightbl_set_ucast_probes(struct rtnl_neightbl *ntbl, int probes)
+{
+       ntbl->nt_parms.ntp_ucast_probes = probes;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_UCAST_PROBES;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the number of multicast probes of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg probes         new probes value
+ */
+void rtnl_neightbl_set_mcast_probes(struct rtnl_neightbl *ntbl, int probes)
+{
+       ntbl->nt_parms.ntp_mcast_probes = probes;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_MCAST_PROBES;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the base reachable time of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg ms             new base reachable time in milliseconds
+ */
+void rtnl_neightbl_set_base_reachable_time(struct rtnl_neightbl *ntbl,
+                                          uint64_t ms)
+{
+       ntbl->nt_parms.ntp_base_reachable_time = ms;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_BASE_REACHABLE_TIME;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the retransmit time of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg ms             new retransmit time
+ */
+void rtnl_neightbl_set_retrans_time(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+       ntbl->nt_parms.ntp_retrans_time = ms;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_RETRANS_TIME;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the gc stale time of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg ms             new gc stale time in milliseconds
+ */
+void rtnl_neightbl_set_gc_stale_time(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+       ntbl->nt_parms.ntp_gc_stale_time = ms;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_GC_STALETIME;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the first probe delay time of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg ms             new first probe delay time in milliseconds
+ */
+void rtnl_neightbl_set_delay_probe_time(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+       ntbl->nt_parms.ntp_probe_delay = ms;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_DELAY_PROBE_TIME;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the anycast delay of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg ms             new anycast delay in milliseconds
+ */
+void rtnl_neightbl_set_anycast_delay(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+       ntbl->nt_parms.ntp_anycast_delay = ms;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_ANYCAST_DELAY;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the proxy delay of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg ms             new proxy delay in milliseconds
+ */
+void rtnl_neightbl_set_proxy_delay(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+       ntbl->nt_parms.ntp_proxy_delay = ms;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_PROXY_DELAY;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/**
+ * Set the locktime of a neighbour table to the specified value
+ * @arg ntbl           neighbour table to change
+ * @arg ms             new locktime in milliseconds
+ */
+void rtnl_neightbl_set_locktime(struct rtnl_neightbl *ntbl, uint64_t ms)
+{
+       ntbl->nt_parms.ntp_locktime = ms;
+       ntbl->nt_parms.ntp_mask |= NEIGHTBLPARM_ATTR_LOCKTIME;
+       ntbl->ce_mask |= NEIGHTBL_ATTR_PARMS;
+}
+
+/** @} */
+
+static struct nl_object_ops neightbl_obj_ops = {
+       .oo_name                = "route/neightbl",
+       .oo_size                = sizeof(struct rtnl_neightbl),
+       .oo_dump = {
+           [NL_DUMP_LINE]      = neightbl_dump_line,
+           [NL_DUMP_DETAILS]   = neightbl_dump_details,
+           [NL_DUMP_STATS]     = neightbl_dump_stats,
+       },
+       .oo_compare             = neightbl_compare,
+};
+
+static struct nl_cache_ops rtnl_neightbl_ops = {
+       .co_name                = "route/neightbl",
+       .co_hdrsize             = sizeof(struct rtgenmsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWNEIGHTBL, NL_ACT_NEW, "new" },
+                                       { RTM_SETNEIGHTBL, NL_ACT_SET, "set" },
+                                       { RTM_GETNEIGHTBL, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_request_update      = neightbl_request_update,
+       .co_msg_parser          = neightbl_msg_parser,
+       .co_obj_ops             = &neightbl_obj_ops,
+};
+
+static void __init neightbl_init(void)
+{
+       nl_cache_mngt_register(&rtnl_neightbl_ops);
+}
+
+static void __exit neightbl_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_neightbl_ops);
+}
+
+/** @} */
diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c
new file mode 100644 (file)
index 0000000..d3ca499
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * lib/route/nexthop.c Routing Nexthop
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup route_obj
+ * @defgroup nexthop Nexthop
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+
+/** @cond SKIP */
+#define NH_ATTR_FLAGS   0x000001
+#define NH_ATTR_WEIGHT  0x000002
+#define NH_ATTR_IFINDEX 0x000004
+#define NH_ATTR_GATEWAY 0x000008
+#define NH_ATTR_REALMS  0x000010
+/** @endcond */
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_nexthop *rtnl_route_nh_alloc(void)
+{
+       struct rtnl_nexthop *nh;
+
+       nh = calloc(1, sizeof(*nh));
+       if (!nh)
+               return NULL;
+
+       nl_init_list_head(&nh->rtnh_list);
+
+       return nh;
+}
+
+struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
+{
+       struct rtnl_nexthop *nh;
+
+       nh = rtnl_route_nh_alloc();
+       if (!nh)
+               return NULL;
+
+       nh->rtnh_flags = src->rtnh_flags;
+       nh->rtnh_flag_mask = src->rtnh_flag_mask;
+       nh->rtnh_weight = src->rtnh_weight;
+       nh->rtnh_ifindex = src->rtnh_ifindex;
+       nh->ce_mask = src->ce_mask;
+
+       if (src->rtnh_gateway) {
+               nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
+               if (!nh->rtnh_gateway) {
+                       free(nh);
+                       return NULL;
+               }
+       }
+
+       return nh;
+}
+
+void rtnl_route_nh_free(struct rtnl_nexthop *nh)
+{
+       nl_addr_put(nh->rtnh_gateway);
+       free(nh);
+}
+
+/** @} */
+
+int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
+                         uint32_t attrs, int loose)
+{
+       int diff = 0;
+
+#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= NH_DIFF(IFINDEX,        a->rtnh_ifindex != b->rtnh_ifindex);
+       diff |= NH_DIFF(WEIGHT,         a->rtnh_weight != b->rtnh_weight);
+       diff |= NH_DIFF(REALMS,         a->rtnh_realms != b->rtnh_realms);
+       diff |= NH_DIFF(GATEWAY,        nl_addr_cmp(a->rtnh_gateway,
+                                                   b->rtnh_gateway));
+
+       if (loose)
+               diff |= NH_DIFF(FLAGS,
+                         (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask);
+       else
+               diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags);
+       
+#undef NH_DIFF
+
+       return diff;
+}
+
+static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+       struct nl_cache *link_cache;
+       char buf[128];
+
+       link_cache = nl_cache_mngt_require_safe("route/link");
+
+       nl_dump(dp, "via");
+
+       if (nh->ce_mask & NH_ATTR_GATEWAY)
+               nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
+                                                  buf, sizeof(buf)));
+
+       if(nh->ce_mask & NH_ATTR_IFINDEX) {
+               if (link_cache) {
+                       nl_dump(dp, " dev %s",
+                               rtnl_link_i2name(link_cache,
+                                                nh->rtnh_ifindex,
+                                                buf, sizeof(buf)));
+               } else
+                       nl_dump(dp, " dev %d", nh->rtnh_ifindex);
+       }
+
+       nl_dump(dp, " ");
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+       struct nl_cache *link_cache;
+       char buf[128];
+
+       link_cache = nl_cache_mngt_require_safe("route/link");
+
+       nl_dump(dp, "nexthop");
+
+       if (nh->ce_mask & NH_ATTR_GATEWAY)
+               nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
+                                                  buf, sizeof(buf)));
+
+       if(nh->ce_mask & NH_ATTR_IFINDEX) {
+               if (link_cache) {
+                       nl_dump(dp, " dev %s",
+                               rtnl_link_i2name(link_cache,
+                                                nh->rtnh_ifindex,
+                                                buf, sizeof(buf)));
+               } else
+                       nl_dump(dp, " dev %d", nh->rtnh_ifindex);
+       }
+
+       if (nh->ce_mask & NH_ATTR_WEIGHT)
+               nl_dump(dp, " weight %u", nh->rtnh_weight);
+
+       if (nh->ce_mask & NH_ATTR_REALMS)
+               nl_dump(dp, " realm %04x:%04x",
+                       RTNL_REALM_FROM(nh->rtnh_realms),
+                       RTNL_REALM_TO(nh->rtnh_realms));
+
+       if (nh->ce_mask & NH_ATTR_FLAGS)
+               nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
+                                                       buf, sizeof(buf)));
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
+{
+       switch (dp->dp_type) {
+       case NL_DUMP_LINE:
+               nh_dump_line(nh, dp);
+               break;
+
+       case NL_DUMP_DETAILS:
+       case NL_DUMP_STATS:
+               if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
+                       nh_dump_details(nh, dp);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
+{
+       nh->rtnh_weight = weight;
+       nh->ce_mask |= NH_ATTR_WEIGHT;
+}
+
+uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
+{
+       return nh->rtnh_weight;
+}
+
+void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
+{
+       nh->rtnh_ifindex = ifindex;
+       nh->ce_mask |= NH_ATTR_IFINDEX;
+}
+
+int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
+{
+       return nh->rtnh_ifindex;
+}      
+
+/* FIXME: Convert to return an int */
+void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
+{
+       struct nl_addr *old = nh->rtnh_gateway;
+
+       if (addr) {
+               nh->rtnh_gateway = nl_addr_get(addr);
+               nh->ce_mask |= NH_ATTR_GATEWAY;
+       } else {
+               nh->ce_mask &= ~NH_ATTR_GATEWAY;
+               nh->rtnh_gateway = NULL;
+       }
+
+       if (old)
+               nl_addr_put(old);
+}
+
+struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
+{
+       return nh->rtnh_gateway;
+}
+
+void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
+{
+       nh->rtnh_flag_mask |= flags;
+       nh->rtnh_flags |= flags;
+       nh->ce_mask |= NH_ATTR_FLAGS;
+}
+
+void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
+{
+       nh->rtnh_flag_mask |= flags;
+       nh->rtnh_flags &= ~flags;
+       nh->ce_mask |= NH_ATTR_FLAGS;
+}
+
+unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
+{
+       return nh->rtnh_flags;
+}
+
+void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
+{
+       nh->rtnh_realms = realms;
+       nh->ce_mask |= NH_ATTR_REALMS;
+}
+
+uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
+{
+       return nh->rtnh_realms;
+}
+
+/** @} */
+
+/**
+ * @name Nexthop Flags Translations
+ * @{
+ */
+
+static const struct trans_tbl nh_flags[] = {
+       __ADD(RTNH_F_DEAD, dead)
+       __ADD(RTNH_F_PERVASIVE, pervasive)
+       __ADD(RTNH_F_ONLINK, onlink)
+};
+
+char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
+{
+       return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
+}
+
+int rtnl_route_nh_str2flags(const char *name)
+{
+       return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/route/pktloc.c b/lib/route/pktloc.c
new file mode 100644 (file)
index 0000000..9fcf4a4
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * lib/route/pktloc.c     Packet Location Aliasing
+ *
+ *     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-2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup pktloc Packet Location Aliasing
+ * Packet Location Aliasing
+ *
+ * The packet location aliasing interface eases the use of offset definitions
+ * inside packets by allowing them to be referenced by name. Known positions
+ * of protocol fields are stored in a configuration file and associated with
+ * a name for later reference. The configuration file is distributed with the
+ * library and provides a well defined set of definitions for most common
+ * protocol fields.
+ *
+ * @section pktloc_examples Examples
+ * @par Example 1.1 Looking up a packet location
+ * @code
+ * struct rtnl_pktloc *loc;
+ *
+ * rtnl_pktloc_lookup("ip.src", &loc);
+ * @endcode
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+
+#include "pktloc_syntax.h"
+#include "pktloc_grammar.h"
+
+/** @cond SKIP */
+#define PKTLOC_NAME_HT_SIZ 256
+
+static struct nl_list_head pktloc_name_ht[PKTLOC_NAME_HT_SIZ];
+
+/* djb2 */
+static unsigned int pktloc_hash(const char *str)
+{
+       unsigned long hash = 5381;
+       int c;
+
+       while ((c = *str++))
+               hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+       return hash % PKTLOC_NAME_HT_SIZ;
+}
+
+static int __pktloc_lookup(const char *name, struct rtnl_pktloc **result)
+{
+       struct rtnl_pktloc *loc;
+       int hash;
+
+       hash = pktloc_hash(name);
+       nl_list_for_each_entry(loc, &pktloc_name_ht[hash], list) {
+               if (!strcasecmp(loc->name, name)) {
+                       loc->refcnt++;
+                       *result = loc;
+                       return 0;
+               }
+       }
+
+       return -NLE_OBJ_NOTFOUND;
+}
+
+extern int pktloc_parse(void *scanner);
+
+static void rtnl_pktloc_free(struct rtnl_pktloc *loc)
+{
+       if (!loc)
+               return;
+
+       free(loc->name);
+       free(loc);
+}
+
+static int read_pktlocs(void)
+{
+       YY_BUFFER_STATE buf = NULL;
+       yyscan_t scanner = NULL;
+       static time_t last_read;
+       struct stat st;
+       char *path;
+       int i, err;
+       FILE *fd;
+
+       if (build_sysconf_path(&path, "pktloc") < 0)
+               return -NLE_NOMEM;
+
+       /* if stat fails, just try to read the file */
+       if (stat(path, &st) == 0) {
+               /* Don't re-read file if file is unchanged */
+               if (last_read == st.st_mtime)
+                       return 0;
+       }
+
+       NL_DBG(2, "Reading packet location file \"%s\"\n", path);
+
+       if (!(fd = fopen(path, "r"))) {
+               err = -NLE_PKTLOC_FILE;
+               goto errout;
+       }
+
+       for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++) {
+               struct rtnl_pktloc *loc, *n;
+
+               nl_list_for_each_entry_safe(loc, n, &pktloc_name_ht[i], list)
+                       rtnl_pktloc_put(loc);
+
+               nl_init_list_head(&pktloc_name_ht[i]);
+       }
+
+       if ((err = pktloc_lex_init(&scanner)) < 0) {
+               err = -NLE_FAILURE;
+               goto errout_close;
+       }
+
+       buf = pktloc__create_buffer(fd, YY_BUF_SIZE, scanner);
+       pktloc__switch_to_buffer(buf, scanner);
+
+       if ((err = pktloc_parse(scanner)) != 0) {
+               pktloc__delete_buffer(buf, scanner);
+               err = -NLE_PARSE_ERR;
+               goto errout_scanner;
+       }
+
+       last_read = st.st_mtime;
+
+errout_scanner:
+       if (scanner)
+               pktloc_lex_destroy(scanner);
+errout_close:
+       fclose(fd);
+errout:
+       free(path);
+
+       return 0;
+}
+
+/** @endcond */
+
+/**
+ * Lookup packet location alias
+ * @arg name           Name of packet location.
+ * @arg result         Result pointer
+ *
+ * Tries to find a matching packet location alias for the supplied
+ * packet location name.
+ *
+ * The file containing the packet location definitions is automatically
+ * re-read if its modification time has changed since the last call.
+ *
+ * The returned packet location has to be returned after use by calling
+ * rtnl_pktloc_put() in order to allow freeing its memory after the last
+ * user has abandoned it.
+ *
+ * @return 0 on success or a negative error code.
+ * @retval NLE_PKTLOC_FILE Unable to open packet location file.
+ * @retval NLE_OBJ_NOTFOUND No matching packet location alias found.
+ */
+int rtnl_pktloc_lookup(const char *name, struct rtnl_pktloc **result)
+{
+       int err;
+
+       if ((err = read_pktlocs()) < 0)
+               return err;
+       
+       return __pktloc_lookup(name, result);
+}
+
+/**
+ * Allocate packet location object
+ */
+struct rtnl_pktloc *rtnl_pktloc_alloc(void)
+{
+       struct rtnl_pktloc *loc;
+
+       if (!(loc = calloc(1, sizeof(*loc))))
+               return NULL;
+
+       loc->refcnt = 1;
+       nl_init_list_head(&loc->list);
+
+       return loc;
+}
+
+/**
+ * Return reference of a packet location
+ * @arg loc            packet location object.
+ */
+void rtnl_pktloc_put(struct rtnl_pktloc *loc)
+{
+       if (!loc)
+               return;
+
+       loc->refcnt--;
+       if (loc->refcnt <= 0)
+               rtnl_pktloc_free(loc);
+}
+
+/**
+ * Add a packet location to the hash table
+ * @arg loc            packet location object
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_pktloc_add(struct rtnl_pktloc *loc)
+{
+       struct rtnl_pktloc *l;
+
+       if (__pktloc_lookup(loc->name, &l) == 0) {
+               rtnl_pktloc_put(l);
+               return -NLE_EXIST;
+       }
+
+       NL_DBG(2, "New packet location entry \"%s\" align=%u layer=%u "
+                 "offset=%u mask=%#x shift=%u refnt=%u\n",
+                 loc->name, loc->align, loc->layer, loc->offset,
+                 loc->mask, loc->shift, loc->refcnt);
+
+       nl_list_add_tail(&loc->list, &pktloc_name_ht[pktloc_hash(loc->name)]);
+
+       return 0;
+}
+
+void rtnl_pktloc_foreach(void (*cb)(struct rtnl_pktloc *, void *), void *arg)
+{
+       struct rtnl_pktloc *loc;
+       int i;
+
+       /* ignore errors */
+       read_pktlocs();
+
+       for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
+               nl_list_for_each_entry(loc, &pktloc_name_ht[i], list)
+                       cb(loc, arg);
+}
+
+static int __init pktloc_init(void)
+{
+       int i;
+
+       for (i = 0; i < PKTLOC_NAME_HT_SIZ; i++)
+               nl_init_list_head(&pktloc_name_ht[i]);
+       
+       return 0;
+}
+
+/** @} */
diff --git a/lib/route/pktloc_grammar.l b/lib/route/pktloc_grammar.l
new file mode 100644 (file)
index 0000000..cbb42b3
--- /dev/null
@@ -0,0 +1,51 @@
+%{
+ #include <netlink-private/netlink.h>
+ #include <netlink-private/tc.h>
+ #include <netlink/netlink.h>
+ #include <netlink/utils.h>
+ #include <netlink/route/pktloc.h>
+ #include "pktloc_syntax.h"
+%}
+
+%option 8bit
+%option reentrant
+%option warn
+%option noyywrap
+%option noinput
+%option nounput
+%option bison-bridge
+%option bison-locations
+%option prefix="pktloc_"
+
+%%
+
+[ \t\r\n]+
+
+"#".*
+
+[[:digit:]]+           |
+0[xX][[:xdigit:]]+     {
+                               yylval->i = strtoul(yytext, NULL, 0);
+                               return NUMBER;
+                       }
+
+"+"                    { return yylval->i = yytext[0]; }
+
+[uU]8                  { yylval->i = TCF_EM_ALIGN_U8; return ALIGN; }
+[uU]16                 { yylval->i = TCF_EM_ALIGN_U16; return ALIGN; }
+[uU]32                 { yylval->i = TCF_EM_ALIGN_U32; return ALIGN; }
+
+[lL][iI][nN][kK]       |
+[eE][tT][hH]           { yylval->i = TCF_LAYER_LINK; return LAYER; }
+[nN][eE][tT]           |
+[iI][pP]               { yylval->i = TCF_LAYER_NETWORK; return LAYER; }
+[tT][rR][aA][nN][sS][pP][oO][rR][tT] |
+[tT][cC][pP]           { yylval->i = TCF_LAYER_TRANSPORT; return LAYER; }
+
+
+[^ \t\r\n+]+           {
+                               yylval->s = strdup(yytext);
+                               if (yylval->s == NULL)
+                                       return ERROR;
+                               return NAME;
+                       }
diff --git a/lib/route/pktloc_syntax.y b/lib/route/pktloc_syntax.y
new file mode 100644 (file)
index 0000000..25d8710
--- /dev/null
@@ -0,0 +1,103 @@
+%{
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/pktloc.h>
+%}
+
+%locations
+%error-verbose
+%define api.pure
+%name-prefix "pktloc_"
+
+%parse-param {void *scanner}
+%lex-param {void *scanner}
+%expect 1
+
+%union {
+       struct rtnl_pktloc *l;
+       uint32_t i;
+       char *s;
+}
+
+%{
+extern int pktloc_lex(YYSTYPE *, YYLTYPE *, void *);
+
+static void yyerror(YYLTYPE *locp, void *scanner, const char *msg)
+{
+       NL_DBG(1, "Error while parsing packet location file: %s\n", msg);
+}
+%}
+
+%token <i> ERROR NUMBER LAYER ALIGN
+%token <s> NAME
+
+%type <i> mask layer align shift
+%type <l> location
+
+%destructor { free($$); } NAME
+
+%start input
+
+%%
+
+input:
+       /* empty */
+       | location input
+       ;
+
+location:
+       NAME align layer NUMBER mask shift
+               {
+                       struct rtnl_pktloc *loc;
+
+                       if (!(loc = rtnl_pktloc_alloc())) {
+                               NL_DBG(1, "Allocating a packet location "
+                                         "object failed.\n");
+                               YYABORT;
+                       }
+
+                       loc->name = $1;
+                       loc->align = $2;
+                       loc->layer = $3;
+                       loc->offset = $4;
+                       loc->mask = $5;
+                       loc->shift = $6;
+
+                       if (rtnl_pktloc_add(loc) < 0) {
+                               NL_DBG(1, "Duplicate packet location entry "
+                                         "\"%s\"\n", $1);
+                       }
+
+                       $$ = loc;
+               }
+       ;
+
+align:
+       ALIGN
+               { $$ = $1; }
+       | NUMBER
+               { $$ = $1; }
+       ;
+
+layer:
+       /* empty */
+               { $$ = TCF_LAYER_NETWORK; }
+       | LAYER '+' 
+               { $$ = $1; }
+       ;
+
+mask:
+       /* empty */
+               { $$ = 0; }
+       | NUMBER
+               { $$ = $1; }
+       ;
+
+shift:
+       /* empty */
+               { $$ = 0; }
+       | NUMBER
+               { $$ = $1; }
+       ;
diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c
new file mode 100644 (file)
index 0000000..250d191
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * lib/route/qdisc.c            Queueing Disciplines
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup tc
+ * @defgroup qdisc Queueing Disciplines
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/link.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/classifier.h>
+
+static struct nl_cache_ops rtnl_qdisc_ops;
+static struct nl_object_ops qdisc_obj_ops;
+
+static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                           struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+       struct rtnl_qdisc *qdisc;
+       int err;
+
+       if (!(qdisc = rtnl_qdisc_alloc()))
+               return -NLE_NOMEM;
+
+       if ((err = rtnl_tc_msg_parse(n, TC_CAST(qdisc))) < 0)
+               goto errout;
+
+       err = pp->pp_cb(OBJ_CAST(qdisc), pp);
+errout:
+       rtnl_qdisc_put(qdisc);
+
+       return err;
+}
+
+static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk)
+{
+       struct tcmsg tchdr = {
+               .tcm_family = AF_UNSPEC,
+               .tcm_ifindex = c->c_iarg1,
+       };
+
+       return nl_send_simple(sk, RTM_GETQDISC, NLM_F_DUMP, &tchdr,
+                             sizeof(tchdr));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_qdisc *rtnl_qdisc_alloc(void)
+{
+       struct rtnl_tc *tc;
+
+       tc = TC_CAST(nl_object_alloc(&qdisc_obj_ops));
+       if (tc)
+               tc->tc_type = RTNL_TC_TYPE_QDISC;
+
+       return (struct rtnl_qdisc *) tc;
+}
+
+void rtnl_qdisc_put(struct rtnl_qdisc *qdisc)
+{
+       nl_object_put((struct nl_object *) qdisc);
+}
+
+/** @} */
+
+/**
+ * @name Addition / Modification / Deletion
+ * @{
+ */
+
+static int build_qdisc_msg(struct rtnl_qdisc *qdisc, int type, int flags,
+                          struct nl_msg **result)
+{
+       if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
+               APPBUG("ifindex must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       return rtnl_tc_msg_build(TC_CAST(qdisc), type, flags, result);
+}
+
+/**
+ * Build a netlink message requesting the addition of a qdisc
+ * @arg qdisc          Qdisc to add 
+ * @arg flags          Additional netlink message flags
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_qdisc_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
+ *
+ * @see rtnl_qdisc_add()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags,
+                                struct nl_msg **result)
+{
+       if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
+               APPBUG("handle or parent must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       return build_qdisc_msg(qdisc, RTM_NEWQDISC, flags, result);
+}
+
+/**
+ * Add qdisc
+ * @arg sk             Netlink socket
+ * @arg qdisc          Qdisc to add 
+ * @arg flags          Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWQDISC netlink message requesting the addition
+ * of a new qdisc and sends the message to the kernel. The configuration
+ * of the qdisc is derived from the attributes of the specified qdisc.
+ *
+ * The following flags may be specified:
+ *  - \c NLM_F_CREATE:  Create qdisc if it does not exist, otherwise 
+ *                      -NLE_OBJ_NOTFOUND is returned.
+ *  - \c NLM_F_REPLACE: If another qdisc is already attached to the
+ *                      parent, replace it even if the handles mismatch.
+ *  - \c NLM_F_EXCL:    Return -NLE_EXISTS if a qdisc with matching
+ *                      handle exists already.
+ *
+ * Existing qdiscs with matching handles will be updated, unless the
+ * flag \c NLM_F_EXCL is specified. If their handles do not match, the
+ * error -NLE_EXISTS is returned unless the flag \c NLM_F_REPLACE is
+ * specified in which case the existing qdisc is replaced with the new
+ * one.  If no matching qdisc exists, it will be created if the flag
+ * \c NLM_F_CREATE is set, otherwise the error -NLE_OBJ_NOTFOUND is
+ * returned. 
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_qdisc_build_add_request(qdisc, flags, &msg)) < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the update of a qdisc
+ * @arg qdisc          Qdisc to update
+ * @arg new            Qdisc with updated attributes
+ * @arg flags          Additional netlink message flags
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_qdisc_update() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_qdisc_update()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_build_update_request(struct rtnl_qdisc *qdisc,
+                                   struct rtnl_qdisc *new, int flags,
+                                   struct nl_msg **result)
+{
+       if (flags & (NLM_F_CREATE | NLM_F_EXCL)) {
+               APPBUG("NLM_F_CREATE and NLM_F_EXCL may not be used here, "
+                      "use rtnl_qdisc_add()");
+               return -NLE_INVAL;
+       }
+
+       if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) {
+               APPBUG("ifindex must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) {
+               APPBUG("handle or parent must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       rtnl_tc_set_ifindex(TC_CAST(new), qdisc->q_ifindex);
+
+       if (qdisc->ce_mask & TCA_ATTR_HANDLE)
+               rtnl_tc_set_handle(TC_CAST(new), qdisc->q_handle);
+
+       if (qdisc->ce_mask & TCA_ATTR_PARENT)
+               rtnl_tc_set_parent(TC_CAST(new), qdisc->q_parent);
+
+       return build_qdisc_msg(new, RTM_NEWQDISC, flags, result);
+}
+
+/**
+ * Update qdisc
+ * @arg sk             Netlink socket
+ * @arg qdisc          Qdisc to update
+ * @arg new            Qdisc with updated attributes
+ * @arg flags          Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWQDISC netlink message requesting the update
+ * of an existing qdisc and sends the message to the kernel.
+ *
+ * This function is a varation of rtnl_qdisc_add() to update qdiscs
+ * if the qdisc to be updated is available as qdisc object. The
+ * behaviour is identical to the one of rtnl_qdisc_add except that
+ * before constructing the message, it copies the \c ifindex,
+ * \c handle, and \c parent from the original \p qdisc to the \p new
+ * qdisc.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_update(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
+                     struct rtnl_qdisc *new, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       err = rtnl_qdisc_build_update_request(qdisc, new, flags, &msg);
+       if (err < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/**
+ * Build netlink message requesting the deletion of a qdisc
+ * @arg qdisc          Qdisc to delete
+ * @arg result         Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_qdisc_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_qdisc_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc,
+                                   struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct tcmsg tchdr;
+       uint32_t required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
+
+       if ((qdisc->ce_mask & required) != required) {
+               APPBUG("ifindex and parent must be specified");
+               return -NLE_MISSING_ATTR;
+       }
+
+       if (!(msg = nlmsg_alloc_simple(RTM_DELQDISC, 0)))
+               return -NLE_NOMEM;
+
+       memset(&tchdr, 0, sizeof(tchdr));
+
+       tchdr.tcm_family = AF_UNSPEC;
+       tchdr.tcm_ifindex = qdisc->q_ifindex;
+       tchdr.tcm_parent = qdisc->q_parent;
+
+       if (qdisc->ce_mask & TCA_ATTR_HANDLE)
+               tchdr.tcm_handle = qdisc->q_handle;
+
+       if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       if (qdisc->ce_mask & TCA_ATTR_KIND)
+               NLA_PUT_STRING(msg, TCA_KIND, qdisc->q_kind);
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * Delete qdisc
+ * @arg sk             Netlink socket
+ * @arg qdisc          Qdisc to add 
+ *
+ * Builds a \c RTM_NEWQDISC netlink message requesting the deletion
+ * of a qdisc and sends the message to the kernel.
+ *
+ * The message is constructed out of the following attributes:
+ * - \c ifindex and \c parent
+ * - \c handle (optional, must match if provided)
+ * - \c kind (optional, must match if provided)
+ *
+ * All other qdisc attributes including all qdisc type specific
+ * attributes are ignored.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note It is not possible to delete default qdiscs.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ *       this function to return immediately after sending. In this case,
+ *       it is the responsibility of the caller to handle any error
+ *       messages returned.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_qdisc_build_delete_request(qdisc, &msg)) < 0)
+               return err;
+
+       return nl_send_sync(sk, msg);
+}
+
+/** @} */
+
+/**
+ * @name Cache Related Functions
+ * @{
+ */
+
+/**
+ * Allocate a cache and fill it with all configured qdiscs
+ * @arg sk             Netlink socket
+ * @arg result         Pointer to store the created cache
+ *
+ * Allocates a new qdisc cache and fills it with a list of all configured
+ * qdiscs on all network devices. Release the cache with nl_cache_free().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+       return nl_cache_alloc_and_fill(&rtnl_qdisc_ops, sk, result);
+}
+
+/**
+ * Search qdisc by interface index and parent
+ * @arg cache          Qdisc cache
+ * @arg ifindex                Interface index
+ * @arg parent         Handle of parent qdisc
+ *
+ * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache()
+ * and searches for a qdisc matching the interface index and parent qdisc.
+ *
+ * The reference counter is incremented before returning the qdisc, therefore
+ * the reference must be given back with rtnl_qdisc_put() after usage.
+ *
+ * @return pointer to qdisc inside the cache or NULL if no match was found.
+ */
+struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *cache,
+                                           int ifindex, uint32_t parent)
+{
+       struct rtnl_qdisc *q;
+
+       if (cache->c_ops != &rtnl_qdisc_ops)
+               return NULL;
+
+       nl_list_for_each_entry(q, &cache->c_items, ce_list) {
+               if (q->q_parent == parent && q->q_ifindex == ifindex) {
+                       nl_object_get((struct nl_object *) q);
+                       return q;
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * Search qdisc by interface index and handle
+ * @arg cache          Qdisc cache
+ * @arg ifindex                Interface index
+ * @arg handle         Handle
+ *
+ * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache()
+ * and searches for a qdisc matching the interface index and handle.
+ *
+ * The reference counter is incremented before returning the qdisc, therefore
+ * the reference must be given back with rtnl_qdisc_put() after usage.
+ *
+ * @return Qdisc or NULL if no match was found.
+ */
+struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int ifindex,
+                                 uint32_t handle)
+{
+       struct rtnl_qdisc *q;
+
+       if (cache->c_ops != &rtnl_qdisc_ops)
+               return NULL;
+
+       nl_list_for_each_entry(q, &cache->c_items, ce_list) {
+               if (q->q_handle == handle && q->q_ifindex == ifindex) {
+                       nl_object_get((struct nl_object *) q);
+                       return q;
+               }
+       }
+
+       return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Deprecated Functions
+ * @{
+ */
+
+/**
+ * Call a callback for each child class of a qdisc (deprecated)
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_qdisc_foreach_child(struct rtnl_qdisc *qdisc, struct nl_cache *cache,
+                             void (*cb)(struct nl_object *, void *), void *arg)
+{
+       struct rtnl_class *filter;
+       
+       filter = rtnl_class_alloc();
+       if (!filter)
+               return;
+
+       rtnl_tc_set_parent(TC_CAST(filter), qdisc->q_handle);
+       rtnl_tc_set_ifindex(TC_CAST(filter), qdisc->q_ifindex);
+       rtnl_tc_set_kind(TC_CAST(filter), qdisc->q_kind);
+
+       nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
+
+       rtnl_class_put(filter);
+}
+
+/**
+ * Call a callback for each filter attached to the qdisc (deprecated)
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ *             to handle the out of memory situation that can occur.
+ */
+void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, struct nl_cache *cache,
+                           void (*cb)(struct nl_object *, void *), void *arg)
+{
+       struct rtnl_cls *filter;
+
+       if (!(filter = rtnl_cls_alloc()))
+               return;
+
+       rtnl_tc_set_ifindex(TC_CAST(filter), qdisc->q_ifindex);
+       rtnl_tc_set_parent(TC_CAST(filter), qdisc->q_parent);
+
+       nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
+       rtnl_cls_put(filter);
+}
+
+/**
+ * Build a netlink message requesting the update of a qdisc
+ *
+ * @deprecated Use of this function is deprecated in favour of
+ *             rtnl_qdisc_build_update_request() due to the missing
+ *             possibility of specifying additional flags.
+ */
+int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc,
+                                   struct rtnl_qdisc *new,
+                                   struct nl_msg **result)
+{
+       return rtnl_qdisc_build_update_request(qdisc, new, NLM_F_REPLACE,
+                                              result);
+}
+
+/**
+ * Change attributes of a qdisc
+ *
+ * @deprecated Use of this function is deprecated in favour of
+ *             rtnl_qdisc_update() due to the missing possibility of
+ *             specifying additional flags.
+ */
+int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc,
+                     struct rtnl_qdisc *new)
+{
+       return rtnl_qdisc_update(sk, qdisc, new, NLM_F_REPLACE);
+}
+
+/** @} */
+
+static void qdisc_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
+{
+       struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+       nl_dump(p, "refcnt %u ", qdisc->q_info);
+}
+
+static struct rtnl_tc_type_ops qdisc_ops = {
+       .tt_type                = RTNL_TC_TYPE_QDISC,
+       .tt_dump_prefix         = "qdisc",
+       .tt_dump = {
+           [NL_DUMP_DETAILS]   = qdisc_dump_details,
+       },
+};
+
+static struct nl_cache_ops rtnl_qdisc_ops = {
+       .co_name                = "route/qdisc",
+       .co_hdrsize             = sizeof(struct tcmsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWQDISC, NL_ACT_NEW, "new" },
+                                       { RTM_DELQDISC, NL_ACT_DEL, "del" },
+                                       { RTM_GETQDISC, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_request_update      = qdisc_request_update,
+       .co_msg_parser          = qdisc_msg_parser,
+       .co_obj_ops             = &qdisc_obj_ops,
+};
+
+static struct nl_object_ops qdisc_obj_ops = {
+       .oo_name                = "route/qdisc",
+       .oo_size                = sizeof(struct rtnl_qdisc),
+       .oo_free_data           = rtnl_tc_free_data,
+       .oo_clone               = rtnl_tc_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = rtnl_tc_dump_line,
+           [NL_DUMP_DETAILS]   = rtnl_tc_dump_details,
+           [NL_DUMP_STATS]     = rtnl_tc_dump_stats,
+       },
+       .oo_compare             = rtnl_tc_compare,
+       .oo_id_attrs            = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE),
+};
+
+static void __init qdisc_init(void)
+{
+       rtnl_tc_type_register(&qdisc_ops);
+       nl_cache_mngt_register(&rtnl_qdisc_ops);
+}
+
+static void __exit qdisc_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_qdisc_ops);
+       rtnl_tc_type_unregister(&qdisc_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/blackhole.c b/lib/route/qdisc/blackhole.c
new file mode 100644 (file)
index 0000000..339cf78
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * lib/route/qdisc/blackhole.c Blackhole Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_blackhole Blackhole
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/tc-api.h>
+
+static struct rtnl_tc_ops blackhole_ops = {
+       .to_kind                = "blackhole",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+};
+
+static void __init blackhole_init(void)
+{
+       rtnl_tc_register(&blackhole_ops);
+}
+
+static void __exit blackhole_exit(void)
+{
+       rtnl_tc_unregister(&blackhole_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/cbq.c b/lib/route/qdisc/cbq.c
new file mode 100644 (file)
index 0000000..95f1761
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * lib/route/qdisc/cbq.c       Class Based Queueing
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/cbq.h>
+#include <netlink/route/cls/police.h>
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_cbq Class Based Queueing (CBQ)
+ * @{
+ */
+
+static const struct trans_tbl ovl_strategies[] = {
+       __ADD(TC_CBQ_OVL_CLASSIC,classic)
+       __ADD(TC_CBQ_OVL_DELAY,delay)
+       __ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
+       __ADD(TC_CBQ_OVL_DROP,drop)
+       __ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
+};
+
+/**
+ * Convert a CBQ OVL strategy to a character string
+ * @arg type           CBQ OVL strategy
+ * @arg buf            destination buffer
+ * @arg len            length of destination buffer
+ *
+ * Converts a CBQ OVL strategy to a character string and stores in the
+ * provided buffer. Returns the destination buffer or the type
+ * encoded in hex if no match was found.
+ */
+char *nl_ovl_strategy2str(int type, char *buf, size_t len)
+{
+       return __type2str(type, buf, len, ovl_strategies,
+                           ARRAY_SIZE(ovl_strategies));
+}
+
+/**
+ * Convert a string to a CBQ OVL strategy
+ * @arg name           CBQ OVL stragegy name
+ *
+ * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy
+ * type. Returns the type or -1 if none was found.
+ */
+int nl_str2ovl_strategy(const char *name)
+{
+       return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies));
+}
+
+static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = {
+       [TCA_CBQ_LSSOPT]        = { .minlen = sizeof(struct tc_cbq_lssopt) },
+       [TCA_CBQ_RATE]          = { .minlen = sizeof(struct tc_ratespec) },
+       [TCA_CBQ_WRROPT]        = { .minlen = sizeof(struct tc_cbq_wrropt) },
+       [TCA_CBQ_OVL_STRATEGY]  = { .minlen = sizeof(struct tc_cbq_ovl) },
+       [TCA_CBQ_FOPT]          = { .minlen = sizeof(struct tc_cbq_fopt) },
+       [TCA_CBQ_POLICE]        = { .minlen = sizeof(struct tc_cbq_police) },
+};
+
+static int cbq_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_CBQ_MAX + 1];
+       struct rtnl_cbq *cbq = data;
+       int err;
+
+       err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy);
+       if (err < 0)
+               return err;
+
+       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));
+       nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr));
+       nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt));
+       nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY],
+                  sizeof(cbq->cbq_ovl));
+       nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE],
+                   sizeof(cbq->cbq_police));
+       
+       return 0;
+}
+
+static void cbq_dump_line(struct rtnl_tc *tc, void *data,
+                         struct nl_dump_params *p)
+{
+       struct rtnl_cbq *cbq = data;
+       double r, rbit;
+       char *ru, *rubit;
+
+       if (!cbq)
+               return;
+
+       r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru);
+       rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit);
+
+       nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u",
+               r, ru, rbit, rubit, cbq->cbq_wrr.priority);
+}
+
+static void cbq_dump_details(struct rtnl_tc *tc, void *data,
+                            struct nl_dump_params *p)
+{
+       struct rtnl_cbq *cbq = data;
+       char *unit, buf[32];
+       double w;
+       uint32_t el;
+
+       if (!cbq)
+               return;
+
+       w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit);
+
+       nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n",
+               cbq->cbq_lss.avpkt,
+               cbq->cbq_rate.mpu,
+               1 << cbq->cbq_rate.cell_log,
+               cbq->cbq_wrr.allot, w, unit);
+
+       el = cbq->cbq_lss.ewma_log;
+       nl_dump_line(p, "  minidle %uus maxidle %uus offtime "
+                               "%uus level %u ewma_log %u\n",
+               nl_ticks2us(cbq->cbq_lss.minidle >> el),
+               nl_ticks2us(cbq->cbq_lss.maxidle >> el),
+               nl_ticks2us(cbq->cbq_lss.offtime >> el),
+               cbq->cbq_lss.level,
+               cbq->cbq_lss.ewma_log);
+
+       nl_dump_line(p, "  penalty %uus strategy %s ",
+               nl_ticks2us(cbq->cbq_ovl.penalty),
+               nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf)));
+
+       nl_dump(p, "split %s defmap 0x%08x ",
+               rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)),
+               cbq->cbq_fopt.defmap);
+       
+       nl_dump(p, "police %s",
+               nl_police2str(cbq->cbq_police.police, buf, sizeof(buf)));
+}
+
+static void cbq_dump_stats(struct rtnl_tc *tc, void *data,
+                          struct nl_dump_params *p)
+{
+       struct tc_cbq_xstats *x;
+       
+       if (!(x = tca_xstats(tc)))
+               return;
+
+       nl_dump_line(p, "            borrows    overact  "
+                       "  avgidle  undertime\n");
+       nl_dump_line(p, "         %10u %10u %10u %10u\n",
+                    x->borrows, x->overactions, x->avgidle, x->undertime);
+}
+
+static struct rtnl_tc_ops cbq_qdisc_ops = {
+       .to_kind                = "cbq",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_cbq),
+       .to_msg_parser          = cbq_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = cbq_dump_line,
+           [NL_DUMP_DETAILS]   = cbq_dump_details,
+           [NL_DUMP_STATS]     = cbq_dump_stats,
+       },
+};
+
+static struct rtnl_tc_ops cbq_class_ops = {
+       .to_kind                = "cbq",
+       .to_type                = RTNL_TC_TYPE_CLASS,
+       .to_size                = sizeof(struct rtnl_cbq),
+       .to_msg_parser          = cbq_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = cbq_dump_line,
+           [NL_DUMP_DETAILS]   = cbq_dump_details,
+           [NL_DUMP_STATS]     = cbq_dump_stats,
+       },
+};
+
+static void __init cbq_init(void)
+{
+       rtnl_tc_register(&cbq_qdisc_ops);
+       rtnl_tc_register(&cbq_class_ops);
+}
+
+static void __exit cbq_exit(void)
+{
+       rtnl_tc_unregister(&cbq_qdisc_ops);
+       rtnl_tc_unregister(&cbq_class_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/dsmark.c b/lib/route/qdisc/dsmark.c
new file mode 100644 (file)
index 0000000..fd9553d
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * lib/route/qdisc/dsmark.c    DSMARK
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_dsmark Differentiated Services Marker (DSMARK)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/qdisc.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/class.h>
+#include <netlink/route/qdisc/dsmark.h>
+
+/** @cond SKIP */
+#define SCH_DSMARK_ATTR_INDICES                0x1
+#define SCH_DSMARK_ATTR_DEFAULT_INDEX  0x2
+#define SCH_DSMARK_ATTR_SET_TC_INDEX   0x4
+
+#define SCH_DSMARK_ATTR_MASK           0x1
+#define SCH_DSMARK_ATTR_VALUE          0x2
+/** @endcond */
+
+static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = {
+       [TCA_DSMARK_INDICES]            = { .type = NLA_U16 },
+       [TCA_DSMARK_DEFAULT_INDEX]      = { .type = NLA_U16 },
+       [TCA_DSMARK_SET_TC_INDEX]       = { .type = NLA_FLAG },
+       [TCA_DSMARK_VALUE]              = { .type = NLA_U8 },
+       [TCA_DSMARK_MASK]               = { .type = NLA_U8 },
+};
+
+static int dsmark_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_dsmark_qdisc *dsmark = data;
+       struct nlattr *tb[TCA_DSMARK_MAX + 1];
+       int err;
+
+       err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_DSMARK_INDICES]) {
+               dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]);
+               dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
+       }
+
+       if (tb[TCA_DSMARK_DEFAULT_INDEX]) {
+               dsmark->qdm_default_index =
+                               nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]);
+               dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
+       }
+
+       if (tb[TCA_DSMARK_SET_TC_INDEX]) {
+               dsmark->qdm_set_tc_index = 1;
+               dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
+       }
+
+       return 0;
+}
+
+static int dsmark_class_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_dsmark_class *dsmark = data;
+       struct nlattr *tb[TCA_DSMARK_MAX + 1];
+       int err;
+
+       err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_DSMARK_MASK]) {
+               dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]);
+               dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
+       }
+
+       if (tb[TCA_DSMARK_VALUE]) {
+               dsmark->cdm_value = nla_get_u8(tb[TCA_DSMARK_VALUE]);
+               dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
+       }
+
+       return 0;
+}
+
+static void dsmark_qdisc_dump_line(struct rtnl_tc *tc, void *data,
+                                  struct nl_dump_params *p)
+{
+       struct rtnl_dsmark_qdisc *dsmark = data;
+
+       if (dsmark && (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES))
+               nl_dump(p, " indices 0x%04x", dsmark->qdm_indices);
+}
+
+static void dsmark_qdisc_dump_details(struct rtnl_tc *tc, void *data,
+                                     struct nl_dump_params *p)
+{
+       struct rtnl_dsmark_qdisc *dsmark = data;
+
+       if (!dsmark)
+               return;
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
+               nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index);
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
+               nl_dump(p, " set-tc-index");
+}
+
+static void dsmark_class_dump_line(struct rtnl_tc *tc, void *data,
+                                  struct nl_dump_params *p)
+{
+       struct rtnl_dsmark_class *dsmark = data;
+
+       if (!dsmark)
+               return;
+
+       if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
+               nl_dump(p, " value 0x%02x", dsmark->cdm_value);
+
+       if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
+               nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask);
+}
+
+static int dsmark_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
+                                struct nl_msg *msg)
+{
+       struct rtnl_dsmark_qdisc *dsmark = data;
+
+       if (!dsmark)
+               return 0;
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
+               NLA_PUT_U16(msg, TCA_DSMARK_INDICES, dsmark->qdm_indices);
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
+               NLA_PUT_U16(msg, TCA_DSMARK_DEFAULT_INDEX,
+                           dsmark->qdm_default_index);
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
+               NLA_PUT_FLAG(msg, TCA_DSMARK_SET_TC_INDEX);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+static int dsmark_class_msg_fill(struct rtnl_tc *tc, void *data,
+                                struct nl_msg *msg)
+{
+       struct rtnl_dsmark_class *dsmark = data;
+
+       if (!dsmark)
+               return 0;
+
+       if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
+               NLA_PUT_U8(msg, TCA_DSMARK_MASK, dsmark->cdm_bmask);
+
+       if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
+               NLA_PUT_U8(msg, TCA_DSMARK_VALUE, dsmark->cdm_value);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Class Attribute Access
+ * @{
+ */
+
+/**
+ * Set bitmask of DSMARK class.
+ * @arg class          DSMARK class to be modified.
+ * @arg mask           New bitmask.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask)
+{
+       struct rtnl_dsmark_class *dsmark;
+       
+       if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+               return -NLE_NOMEM;
+
+       dsmark->cdm_bmask = mask;
+       dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
+
+       return 0;
+}
+
+/**
+ * Get bitmask of DSMARK class.
+ * @arg class          DSMARK class.
+ * @return Bitmask or a negative error code.
+ */
+int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class)
+{
+       struct rtnl_dsmark_class *dsmark;
+       
+       if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+               return -NLE_NOMEM;
+
+       if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
+               return dsmark->cdm_bmask;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set value of DSMARK class.
+ * @arg class          DSMARK class to be modified.
+ * @arg value          New value.
+ * @return 0 on success or a negative errror code.
+ */
+int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value)
+{
+       struct rtnl_dsmark_class *dsmark;
+       
+       if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+               return -NLE_NOMEM;
+
+       dsmark->cdm_value = value;
+       dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
+
+       return 0;
+}
+
+/**
+ * Get value of DSMARK class.
+ * @arg class          DSMARK class.
+ * @return Value or a negative error code.
+ */
+int rtnl_class_dsmark_get_value(struct rtnl_class *class)
+{
+       struct rtnl_dsmark_class *dsmark;
+       
+       if (!(dsmark = rtnl_tc_data(TC_CAST(class))))
+               return -NLE_NOMEM;
+
+       if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
+               return dsmark->cdm_value;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Qdisc Attribute Access
+ * @{
+ */
+
+/**
+ * Set indices of DSMARK qdisc.
+ * @arg qdisc          DSMARK qdisc to be modified.
+ * @arg indices                New indices.
+ */
+int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices)
+{
+       struct rtnl_dsmark_qdisc *dsmark;
+
+       if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       dsmark->qdm_indices = indices;
+       dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
+
+       return 0;
+}
+
+/**
+ * Get indices of DSMARK qdisc.
+ * @arg qdisc          DSMARK qdisc.
+ * @return Indices or a negative error code.
+ */
+int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_dsmark_qdisc *dsmark;
+
+       if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
+               return dsmark->qdm_indices;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set default index of DSMARK qdisc.
+ * @arg qdisc          DSMARK qdisc to be modified.
+ * @arg default_index  New default index.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc,
+                                       uint16_t default_index)
+{
+       struct rtnl_dsmark_qdisc *dsmark;
+
+       if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       dsmark->qdm_default_index = default_index;
+       dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
+
+       return 0;
+}
+
+/**
+ * Get default index of DSMARK qdisc.
+ * @arg qdisc          DSMARK qdisc.
+ * @return Default index or a negative error code.
+ */
+int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_dsmark_qdisc *dsmark;
+
+       if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
+               return dsmark->qdm_default_index;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set set-tc-index flag of DSMARK qdisc.
+ * @arg qdisc          DSMARK qdisc to be modified.
+ * @arg flag           Flag indicating whether to enable or disable.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag)
+{
+       struct rtnl_dsmark_qdisc *dsmark;
+
+       if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       dsmark->qdm_set_tc_index = !!flag;
+       dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
+
+       return 0;
+}
+
+/**
+ * Get set-tc-index flag of DSMARK qdisc.
+ * @arg qdisc          DSMARK qdisc to be modified.
+ * @return 1 or 0 to indicate wehther the flag is enabled or a negative
+ *         error code.
+ */
+int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_dsmark_qdisc *dsmark;
+
+       if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
+               return dsmark->qdm_set_tc_index;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops dsmark_qdisc_ops = {
+       .to_kind                = "dsmark",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_dsmark_qdisc),
+       .to_msg_parser          = dsmark_qdisc_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = dsmark_qdisc_dump_line,
+           [NL_DUMP_DETAILS]   = dsmark_qdisc_dump_details,
+       },
+       .to_msg_fill            = dsmark_qdisc_msg_fill,
+};
+
+static struct rtnl_tc_ops dsmark_class_ops = {
+       .to_kind                = "dsmark",
+       .to_type                = RTNL_TC_TYPE_CLASS,
+       .to_size                = sizeof(struct rtnl_dsmark_class),
+       .to_msg_parser          = dsmark_class_msg_parser,
+       .to_dump[NL_DUMP_LINE]  = dsmark_class_dump_line,
+       .to_msg_fill            = dsmark_class_msg_fill,
+};
+
+static void __init dsmark_init(void)
+{
+       rtnl_tc_register(&dsmark_qdisc_ops);
+       rtnl_tc_register(&dsmark_class_ops);
+}
+
+static void __exit dsmark_exit(void)
+{
+       rtnl_tc_unregister(&dsmark_qdisc_ops);
+       rtnl_tc_unregister(&dsmark_class_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/fifo.c b/lib/route/qdisc/fifo.c
new file mode 100644 (file)
index 0000000..d94c007
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * lib/route/qdisc/fifo.c              (p|b)fifo
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_fifo Packet/Bytes FIFO (pfifo/bfifo)
+ * @brief
+ *
+ * The FIFO qdisc comes in two flavours:
+ * @par bfifo (Byte FIFO)
+ * Allows enqueuing until the currently queued volume in bytes exceeds
+ * the configured limit.backlog contains currently enqueued volume in bytes.
+ *
+ * @par pfifo (Packet FIFO)
+ * Allows enquueing until the currently queued number of packets
+ * exceeds the configured limit.
+ *
+ * The configuration is exactly the same, the decision which of
+ * the two variations is going to be used is made based on the
+ * kind of the qdisc (rtnl_tc_set_kind()).
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/fifo.h>
+#include <netlink/utils.h>
+
+/** @cond SKIP */
+#define SCH_FIFO_ATTR_LIMIT 1
+/** @endcond */
+
+static int fifo_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_fifo *fifo = data;
+       struct tc_fifo_qopt *opt;
+
+       if (tc->tc_opts->d_size < sizeof(struct tc_fifo_qopt))
+               return -NLE_INVAL;
+
+       opt = (struct tc_fifo_qopt *) tc->tc_opts->d_data;
+       fifo->qf_limit = opt->limit;
+       fifo->qf_mask = SCH_FIFO_ATTR_LIMIT;
+
+       return 0;
+}
+
+static void pfifo_dump_line(struct rtnl_tc *tc, void *data,
+                           struct nl_dump_params *p)
+{
+       struct rtnl_fifo *fifo = data;
+
+       if (fifo)
+               nl_dump(p, " limit %u packets", fifo->qf_limit);
+}
+
+static void bfifo_dump_line(struct rtnl_tc *tc, void *data,
+                           struct nl_dump_params *p)
+{
+       struct rtnl_fifo *fifo = data;
+       char *unit;
+       double r;
+
+       if (!fifo)
+               return;
+
+       r = nl_cancel_down_bytes(fifo->qf_limit, &unit);
+       nl_dump(p, " limit %.1f%s", r, unit);
+}
+
+static int fifo_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       struct rtnl_fifo *fifo = data;
+       struct tc_fifo_qopt opts = {0};
+
+       if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT))
+               return -NLE_INVAL;
+
+       opts.limit = fifo->qf_limit;
+
+       return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Set limit of FIFO qdisc.
+ * @arg qdisc          FIFO qdisc to be modified.
+ * @arg limit          New limit.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+       struct rtnl_fifo *fifo;
+       
+       if (!(fifo = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+               
+       fifo->qf_limit = limit;
+       fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT;
+
+       return 0;
+}
+
+/**
+ * Get limit of a FIFO qdisc.
+ * @arg qdisc          FIFO qdisc.
+ * @return Numeric limit or a negative error code.
+ */
+int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_fifo *fifo;
+       
+       if (!(fifo = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+       
+       if (fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)
+               return fifo->qf_limit;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops pfifo_ops = {
+       .to_kind                = "pfifo",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_fifo),
+       .to_msg_parser          = fifo_msg_parser,
+       .to_dump[NL_DUMP_LINE]  = pfifo_dump_line,
+       .to_msg_fill            = fifo_msg_fill,
+};
+
+static struct rtnl_tc_ops bfifo_ops = {
+       .to_kind                = "bfifo",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_fifo),
+       .to_msg_parser          = fifo_msg_parser,
+       .to_dump[NL_DUMP_LINE]  = bfifo_dump_line,
+       .to_msg_fill            = fifo_msg_fill,
+};
+
+static void __init fifo_init(void)
+{
+       rtnl_tc_register(&pfifo_ops);
+       rtnl_tc_register(&bfifo_ops);
+}
+
+static void __exit fifo_exit(void)
+{
+       rtnl_tc_unregister(&pfifo_ops);
+       rtnl_tc_unregister(&bfifo_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/htb.c b/lib/route/qdisc/htb.c
new file mode 100644 (file)
index 0000000..5a61a4e
--- /dev/null
@@ -0,0 +1,643 @@
+/*
+ * lib/route/qdisc/htb.c       HTB Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
+ * Copyright (c) 2005-2006 Siemens AG Oesterreich
+ */
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_htb Hierachical Token Bucket (HTB)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/htb.h>
+
+/** @cond SKIP */
+#define SCH_HTB_HAS_RATE2QUANTUM       0x01
+#define SCH_HTB_HAS_DEFCLS             0x02
+
+#define SCH_HTB_HAS_PRIO               0x001
+#define SCH_HTB_HAS_RATE               0x002
+#define SCH_HTB_HAS_CEIL               0x004
+#define SCH_HTB_HAS_RBUFFER            0x008
+#define SCH_HTB_HAS_CBUFFER            0x010
+#define SCH_HTB_HAS_QUANTUM            0x020
+#define SCH_HTB_HAS_LEVEL              0x040
+/** @endcond */
+
+static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
+       [TCA_HTB_INIT]  = { .minlen = sizeof(struct tc_htb_glob) },
+       [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
+};
+
+static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_HTB_MAX + 1];
+       struct rtnl_htb_qdisc *htb = data;
+       int err;
+
+       if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
+               return err;
+       
+       if (tb[TCA_HTB_INIT]) {
+               struct tc_htb_glob opts;
+
+               nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts));
+               htb->qh_rate2quantum = opts.rate2quantum;
+               htb->qh_defcls = opts.defcls;
+               htb->qh_direct_pkts = opts.direct_pkts;
+
+               htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
+       }
+
+       return 0;
+}
+
+static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_HTB_MAX + 1];
+       struct rtnl_htb_class *htb = data;
+       int err;
+
+       if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
+               return err;
+       
+       if (tb[TCA_HTB_PARMS]) {
+               struct tc_htb_opt opts;
+
+               nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts));
+               htb->ch_prio = opts.prio;
+               rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
+               rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
+               htb->ch_rbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
+                                                      opts.rate.rate);
+               htb->ch_cbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.cbuffer),
+                                                      opts.ceil.rate);
+               htb->ch_quantum = opts.quantum;
+               htb->ch_level = opts.level;
+
+               rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu);
+               rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead);
+
+               htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
+                               SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
+                               SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM |
+                               SCH_HTB_HAS_LEVEL);
+       }
+
+       return 0;
+}
+
+static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data,
+                               struct nl_dump_params *p)
+{
+       struct rtnl_htb_qdisc *htb = data;
+
+       if (!htb)
+               return;
+
+       if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
+               nl_dump(p, " r2q %u", htb->qh_rate2quantum);
+
+       if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
+               char buf[64];
+               nl_dump(p, " default-class %s",
+                       rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf)));
+       }
+}
+
+static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
+                               struct nl_dump_params *p)
+{
+       struct rtnl_htb_class *htb = data;
+
+       if (!htb)
+               return;
+
+       if (htb->ch_mask & SCH_HTB_HAS_RATE) {
+               double r, rbit;
+               char *ru, *rubit;
+
+               r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru);
+               rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit);
+
+               nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
+                       r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
+       }
+}
+
+static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
+                                  struct nl_dump_params *p)
+{
+       struct rtnl_htb_class *htb = data;
+
+       if (!htb)
+               return;
+
+       /* line 1 */
+       if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
+               double r, rbit;
+               char *ru, *rubit;
+
+               r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru);
+               rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit);
+
+               nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
+                       r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
+       }
+
+       if (htb->ch_mask & SCH_HTB_HAS_PRIO)
+               nl_dump(p, " prio %u", htb->ch_prio);
+
+       if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
+               double b;
+               char *bu;
+
+               b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu);
+               nl_dump(p, " rbuffer %.2f%s", b, bu);
+       }
+
+       if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
+               double b;
+               char *bu;
+
+               b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu);
+               nl_dump(p, " cbuffer %.2f%s", b, bu);
+       }
+
+       if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
+               nl_dump(p, " quantum %u", htb->ch_quantum);
+}
+
+static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
+                             struct nl_msg *msg)
+{
+       struct rtnl_htb_qdisc *htb = data;
+       struct tc_htb_glob opts = {
+               .version = TC_HTB_PROTOVER,
+               .rate2quantum = 10,
+        };
+
+       if (htb) {
+               if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
+                       opts.rate2quantum = htb->qh_rate2quantum;
+
+               if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
+                       opts.defcls = htb->qh_defcls;
+       }
+
+       return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts);
+}
+
+static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
+                             struct nl_msg *msg)
+{
+       struct rtnl_htb_class *htb = data;
+       uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
+       struct tc_htb_opt opts;
+       int buffer, cbuffer;
+
+       if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
+               BUG();
+
+       memset(&opts, 0, sizeof(opts));
+
+       /* if not set, zero (0) is used as priority */
+       if (htb->ch_mask & SCH_HTB_HAS_PRIO)
+               opts.prio = htb->ch_prio;
+
+       mtu = rtnl_tc_get_mtu(tc);
+
+       rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
+       rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
+
+       if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
+               rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
+               rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
+       } else {
+               /*
+                * If not set, configured rate is used as ceil, which implies
+                * no borrowing.
+                */
+               memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
+       }
+
+       if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
+               buffer = htb->ch_rbuffer;
+       else
+               buffer = opts.rate.rate / nl_get_psched_hz() + mtu; /* XXX */
+
+       opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime(buffer, opts.rate.rate));
+
+       if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
+               cbuffer = htb->ch_cbuffer;
+       else
+               cbuffer = opts.ceil.rate / nl_get_psched_hz() + mtu; /* XXX */
+
+       opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate));
+
+       if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
+               opts.quantum = htb->ch_quantum;
+
+       NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
+       NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
+       NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+static struct rtnl_tc_ops htb_qdisc_ops;
+static struct rtnl_tc_ops htb_class_ops;
+
+static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc)
+{
+       return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops);
+}
+
+static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class)
+{
+       return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops);
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+/**
+ * Return rate/quantum ratio of HTB qdisc
+ * @arg qdisc          htb qdisc object
+ *
+ * @return rate/quantum ratio or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_htb_qdisc *htb;
+
+       if ((htb = htb_qdisc_data(qdisc)) &&
+           htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
+               return htb->qh_rate2quantum;
+
+       return 0;
+}
+
+int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
+{
+       struct rtnl_htb_qdisc *htb;
+
+       if (!(htb = htb_qdisc_data(qdisc)))
+               return -NLE_OPNOTSUPP;
+
+       htb->qh_rate2quantum = rate2quantum;
+       htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
+
+       return 0;
+}
+
+/**
+ * Return default class of HTB qdisc
+ * @arg qdisc          htb qdisc object
+ *
+ * Returns the classid of the class where all unclassified traffic
+ * goes to.
+ *
+ * @return classid or TC_H_UNSPEC if unspecified.
+ */
+uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_htb_qdisc *htb;
+
+       if ((htb = htb_qdisc_data(qdisc)) &&
+           htb->qh_mask & SCH_HTB_HAS_DEFCLS)
+               return htb->qh_defcls;
+
+       return TC_H_UNSPEC;
+}
+
+/**
+ * Set default class of the htb qdisc to the specified value
+ * @arg qdisc          qdisc to change
+ * @arg defcls         new default class
+ */
+int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
+{
+       struct rtnl_htb_qdisc *htb;
+
+       if (!(htb = htb_qdisc_data(qdisc)))
+               return -NLE_OPNOTSUPP;
+
+       htb->qh_defcls = defcls;
+       htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
+
+       return 0;
+}
+
+uint32_t rtnl_htb_get_prio(struct rtnl_class *class)
+{
+       struct rtnl_htb_class *htb;
+
+       if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_PRIO)
+               return htb->ch_prio;
+
+       return 0;
+}
+
+int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
+{
+       struct rtnl_htb_class *htb;
+
+       if (!(htb = htb_class_data(class)))
+               return -NLE_OPNOTSUPP;
+
+       htb->ch_prio = prio;
+       htb->ch_mask |= SCH_HTB_HAS_PRIO;
+
+       return 0;
+}
+
+/**
+ * Return rate of HTB class
+ * @arg class          htb class object
+ *
+ * @return Rate in bytes/s or 0 if unspecified.
+ */
+uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
+{
+       struct rtnl_htb_class *htb;
+
+       if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_RATE)
+               return htb->ch_rate.rs_rate;
+
+       return 0;
+}
+
+/**
+ * Set rate of HTB class
+ * @arg class          htb class object
+ * @arg rate           new rate in bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
+{
+       struct rtnl_htb_class *htb;
+
+       if (!(htb = htb_class_data(class)))
+               return -NLE_OPNOTSUPP;
+
+       htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */
+       htb->ch_rate.rs_rate = rate;
+       htb->ch_mask |= SCH_HTB_HAS_RATE;
+
+       return 0;
+}
+
+/**
+ * Return ceil rate of HTB class
+ * @arg class          htb class object
+ *
+ * @return Ceil rate in bytes/s or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
+{
+       struct rtnl_htb_class *htb;
+
+       if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_CEIL)
+               return htb->ch_ceil.rs_rate;
+
+       return 0;
+}
+
+/**
+ * Set ceil rate of HTB class
+ * @arg class          htb class object
+ * @arg ceil           new ceil rate number of bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
+{
+       struct rtnl_htb_class *htb;
+
+       if (!(htb = htb_class_data(class)))
+               return -NLE_OPNOTSUPP;
+
+       htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */
+       htb->ch_ceil.rs_rate = ceil;
+       htb->ch_mask |= SCH_HTB_HAS_CEIL;
+
+       return 0;
+}
+
+/**
+ * Return burst buffer size of HTB class
+ * @arg class          htb class object
+ *
+ * @return Burst buffer size or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
+{
+       struct rtnl_htb_class *htb;
+
+       if ((htb = htb_class_data(class)) &&
+            htb->ch_mask & SCH_HTB_HAS_RBUFFER)
+               return htb->ch_rbuffer;
+
+       return 0;
+}
+
+/**
+ * Set size of the rate bucket of HTB class.
+ * @arg class          HTB class to be modified.
+ * @arg rbuffer                New size in bytes.
+ */
+int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
+{
+       struct rtnl_htb_class *htb;
+
+       if (!(htb = htb_class_data(class)))
+               return -NLE_OPNOTSUPP;
+
+       htb->ch_rbuffer = rbuffer;
+       htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
+
+       return 0;
+}
+
+/**
+ * Return ceil burst buffer size of HTB class
+ * @arg class          htb class object
+ *
+ * @return Ceil burst buffer size or 0 if unspecified
+ */
+uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
+{
+       struct rtnl_htb_class *htb;
+
+       if ((htb = htb_class_data(class)) &&
+            htb->ch_mask & SCH_HTB_HAS_CBUFFER)
+               return htb->ch_cbuffer;
+
+       return 0;
+}
+
+/**
+ * Set size of the ceil bucket of HTB class.
+ * @arg class          HTB class to be modified.
+ * @arg cbuffer                New size in bytes.
+ */
+int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
+{
+       struct rtnl_htb_class *htb;
+
+       if (!(htb = htb_class_data(class)))
+               return -NLE_OPNOTSUPP;
+
+       htb->ch_cbuffer = cbuffer;
+       htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
+
+       return 0;
+}
+
+/**
+ * Return quantum of HTB class
+ * @arg class          htb class object
+ *
+ * See XXX[quantum def]
+ *
+ * @return Quantum or 0 if unspecified.
+ */
+uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
+{
+       struct rtnl_htb_class *htb;
+
+       if ((htb = htb_class_data(class)) &&
+           htb->ch_mask & SCH_HTB_HAS_QUANTUM)
+               return htb->ch_quantum;
+
+       return 0;
+}
+
+/**
+ * Set quantum of HTB class (overwrites value calculated based on r2q)
+ * @arg class          htb class object
+ * @arg quantum                new quantum in number of bytes
+ *
+ * See XXX[quantum def]
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
+{
+       struct rtnl_htb_class *htb;
+
+       if (!(htb = htb_class_data(class)))
+               return -NLE_OPNOTSUPP;
+
+       htb->ch_quantum = quantum;
+       htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
+
+       return 0;
+}
+
+/**
+ * Return level of HTB class
+ * @arg class          htb class object
+ *
+ * Returns the level of the HTB class. Leaf classes are assigned level
+ * 0, root classes have level (TC_HTB_MAXDEPTH - 1). Interior classes
+ * have a level of one less than their parent.
+ *
+ * @return Level or -NLE_OPNOTSUPP
+ */
+int rtnl_htb_get_level(struct rtnl_class *class)
+{
+       struct rtnl_htb_class *htb;
+
+       if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_LEVEL)
+               return htb->ch_level;
+
+       return -NLE_OPNOTSUPP;
+}
+
+/**
+ * Set level of HTB class
+ * @arg class          htb class object
+ * @arg level          new level of HTB class
+ *
+ * Sets the level of a HTB class. Note that changing the level of a HTB
+ * class does not change the level of its in kernel counterpart. This
+ * function is provided only to create HTB objects which can be compared
+ * against or filtered upon.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_level(struct rtnl_class *class, int level)
+{
+       struct rtnl_htb_class *htb;
+
+       if (!(htb = htb_class_data(class)))
+               return -NLE_OPNOTSUPP;
+
+       htb->ch_level = level;
+       htb->ch_mask |= SCH_HTB_HAS_LEVEL;
+
+       return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops htb_qdisc_ops = {
+       .to_kind                = "htb",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_htb_qdisc),
+       .to_msg_parser          = htb_qdisc_msg_parser,
+       .to_dump[NL_DUMP_LINE]  = htb_qdisc_dump_line,
+       .to_msg_fill            = htb_qdisc_msg_fill,
+};
+
+static struct rtnl_tc_ops htb_class_ops = {
+       .to_kind                = "htb",
+       .to_type                = RTNL_TC_TYPE_CLASS,
+       .to_size                = sizeof(struct rtnl_htb_class),
+       .to_msg_parser          = htb_class_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = htb_class_dump_line,
+           [NL_DUMP_DETAILS]   = htb_class_dump_details,
+       },
+       .to_msg_fill            = htb_class_msg_fill,
+};
+
+static void __init htb_init(void)
+{
+       rtnl_tc_register(&htb_qdisc_ops);
+       rtnl_tc_register(&htb_class_ops);
+}
+
+static void __exit htb_exit(void)
+{
+       rtnl_tc_unregister(&htb_qdisc_ops);
+       rtnl_tc_unregister(&htb_class_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/netem.c b/lib/route/qdisc/netem.c
new file mode 100644 (file)
index 0000000..06d9fe8
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * lib/route/qdisc/netem.c             Network Emulator Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_netem Network Emulator
+ * @brief
+ *
+ * For further documentation see http://linux-net.osdl.org/index.php/Netem
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/netem.h>
+
+/** @cond SKIP */
+#define SCH_NETEM_ATTR_LATENCY         0x0001
+#define SCH_NETEM_ATTR_LIMIT           0x0002
+#define SCH_NETEM_ATTR_LOSS                    0x0004
+#define SCH_NETEM_ATTR_GAP                     0x0008
+#define SCH_NETEM_ATTR_DUPLICATE       0x0010
+#define SCH_NETEM_ATTR_JITTER          0x0020
+#define SCH_NETEM_ATTR_DELAY_CORR      0x0040
+#define SCH_NETEM_ATTR_LOSS_CORR       0x0080
+#define SCH_NETEM_ATTR_DUP_CORR                0x0100
+#define SCH_NETEM_ATTR_RO_PROB         0x0200
+#define SCH_NETEM_ATTR_RO_CORR         0x0400
+#define SCH_NETEM_ATTR_CORRUPT_PROB    0x0800
+#define SCH_NETEM_ATTR_CORRUPT_CORR    0x1000
+#define SCH_NETEM_ATTR_DIST         0x2000
+/** @endcond */
+
+static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = {
+       [TCA_NETEM_CORR]        = { .minlen = sizeof(struct tc_netem_corr) },
+       [TCA_NETEM_REORDER]     = { .minlen = sizeof(struct tc_netem_reorder) },
+       [TCA_NETEM_CORRUPT]     = { .minlen = sizeof(struct tc_netem_corrupt) },
+};
+
+static int netem_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_netem *netem = data;
+       struct tc_netem_qopt *opts;
+       int len, err = 0;
+
+       if (tc->tc_opts->d_size < sizeof(*opts))
+               return -NLE_INVAL;
+
+       opts = (struct tc_netem_qopt *) tc->tc_opts->d_data;
+       netem->qnm_latency = opts->latency;
+       netem->qnm_limit = opts->limit;
+       netem->qnm_loss = opts->loss;
+       netem->qnm_gap = opts->gap;
+       netem->qnm_duplicate = opts->duplicate;
+       netem->qnm_jitter = opts->jitter;
+
+       netem->qnm_mask = (SCH_NETEM_ATTR_LATENCY | SCH_NETEM_ATTR_LIMIT |
+                          SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP |
+                          SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER);
+
+       len = tc->tc_opts->d_size - sizeof(*opts);
+
+       if (len > 0) {
+               struct nlattr *tb[TCA_NETEM_MAX+1];
+
+               err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *)
+                               (tc->tc_opts->d_data + sizeof(*opts)),
+                               len, netem_policy);
+               if (err < 0) {
+                       free(netem);
+                       return err;
+               }
+
+               if (tb[TCA_NETEM_CORR]) {
+                       struct tc_netem_corr cor;
+
+                       nla_memcpy(&cor, tb[TCA_NETEM_CORR], sizeof(cor));
+                       netem->qnm_corr.nmc_delay = cor.delay_corr;
+                       netem->qnm_corr.nmc_loss = cor.loss_corr;
+                       netem->qnm_corr.nmc_duplicate = cor.dup_corr;
+
+                       netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR |
+                                           SCH_NETEM_ATTR_LOSS_CORR |
+                                       SCH_NETEM_ATTR_DUP_CORR);
+               }
+
+               if (tb[TCA_NETEM_REORDER]) {
+                       struct tc_netem_reorder ro;
+
+                       nla_memcpy(&ro, tb[TCA_NETEM_REORDER], sizeof(ro));
+                       netem->qnm_ro.nmro_probability = ro.probability;
+                       netem->qnm_ro.nmro_correlation = ro.correlation;
+
+                       netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB |
+                                           SCH_NETEM_ATTR_RO_CORR);
+               }
+                       
+               if (tb[TCA_NETEM_CORRUPT]) {
+                       struct tc_netem_corrupt corrupt;
+                                               
+                       nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt));
+                       netem->qnm_crpt.nmcr_probability = corrupt.probability;
+                       netem->qnm_crpt.nmcr_correlation = corrupt.correlation;
+       
+                       netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB |
+                                               SCH_NETEM_ATTR_CORRUPT_CORR);
+               }
+               
+               /* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */
+               netem->qnm_dist.dist_data = NULL;
+               netem->qnm_dist.dist_size = 0;
+       }
+
+       return 0;
+}
+
+static void netem_free_data(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_netem *netem = data;
+       
+       if (!netem)
+               return;
+       
+       free(netem->qnm_dist.dist_data);
+}
+
+static void netem_dump_line(struct rtnl_tc *tc, void *data,
+                           struct nl_dump_params *p)
+{
+       struct rtnl_netem *netem = data;
+
+       if (netem)
+               nl_dump(p, "limit %d", netem->qnm_limit);
+}
+
+static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data,
+                             struct nl_msg *msg)
+{
+       int err = 0;
+       struct tc_netem_qopt opts;
+       struct tc_netem_corr cor;
+       struct tc_netem_reorder reorder;
+       struct tc_netem_corrupt corrupt;
+       struct rtnl_netem *netem = data;
+       
+       unsigned char set_correlation = 0, set_reorder = 0,
+               set_corrupt = 0, set_dist = 0;
+
+       if (!netem)
+               BUG();
+
+       memset(&opts, 0, sizeof(opts));
+       memset(&cor, 0, sizeof(cor));
+       memset(&reorder, 0, sizeof(reorder));
+       memset(&corrupt, 0, sizeof(corrupt));
+
+       msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST;
+       
+       if ( netem->qnm_ro.nmro_probability != 0 ) {
+               if (netem->qnm_latency == 0) {
+                       return -NLE_MISSING_ATTR;
+               }
+               if (netem->qnm_gap == 0) netem->qnm_gap = 1;
+       }
+       else if ( netem->qnm_gap ) { 
+               return -NLE_MISSING_ATTR;
+       }
+
+       if ( netem->qnm_corr.nmc_delay != 0 ) {
+               if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
+                       return -NLE_MISSING_ATTR;
+               }
+               set_correlation = 1;
+       }
+       
+       if ( netem->qnm_corr.nmc_loss != 0 ) {
+               if ( netem->qnm_loss == 0 ) {
+                       return -NLE_MISSING_ATTR;
+               }
+               set_correlation = 1;
+       }
+
+       if ( netem->qnm_corr.nmc_duplicate != 0 ) {
+               if ( netem->qnm_duplicate == 0 ) {
+                       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 -NLE_MISSING_ATTR;
+       }
+       
+       if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1;
+       else if ( netem->qnm_crpt.nmcr_correlation != 0 ) {
+                       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 -NLE_MISSING_ATTR;
+       }
+       else {
+               /* Resize to accomodate the large distribution table */
+               int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size *
+                       sizeof(netem->qnm_dist.dist_data[0]);
+               
+               msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len);
+               if ( msg->nm_nlh == NULL )
+                       return -NLE_NOMEM;
+               msg->nm_size = new_msg_len;
+                       set_dist = 1;
+               }
+       }
+       
+       opts.latency = netem->qnm_latency;
+       opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000;
+       opts.loss = netem->qnm_loss;
+       opts.gap = netem->qnm_gap;
+       opts.duplicate = netem->qnm_duplicate;
+       opts.jitter = netem->qnm_jitter;
+       
+       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;
+
+               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;
+
+               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;
+
+               NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
+       }
+       
+       if ( set_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);
+       }
+
+       /* Length specified in the TCA_OPTIONS section must span the entire
+        * remainder of the message. That's just the way that sch_netem expects it.
+        * Maybe there's a more succinct way to do this at a higher level.
+        */
+       struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) +
+               NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO);
+               
+       struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) +
+               NLMSG_ALIGN(msg->nm_nlh->nlmsg_len));
+       
+       int old_len = head->nla_len;
+       head->nla_len = (void *)tail - (void *)head;
+       msg->nm_nlh->nlmsg_len += (head->nla_len - old_len);
+       
+       return err;
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Queue Limit
+ * @{
+ */
+
+/**
+ * Set limit of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg limit          New limit in bytes.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+       
+       netem->qnm_limit = limit;
+       netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT;
+}
+
+/**
+ * Get limit of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Limit in bytes or a negative error code.
+ */
+int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT)
+               return netem->qnm_limit;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Re-ordering
+ * @{
+ */
+
+/**
+ * Set re-ordering gap of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg gap            New gap in number of packets.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_gap = gap;
+       netem->qnm_mask |= SCH_NETEM_ATTR_GAP;
+}
+
+/**
+ * Get re-ordering gap of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Re-ordering gap in packets or a negative error code.
+ */
+int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_GAP)
+               return netem->qnm_gap;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set re-ordering probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob           New re-ordering probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_ro.nmro_probability = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB;
+}
+
+/**
+ * Get re-ordering probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Re-ordering probability or a negative error code.
+ */
+int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB)
+               return netem->qnm_ro.nmro_probability;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set re-order correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob           New re-ordering correlation probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_ro.nmro_correlation = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR;
+}
+
+/**
+ * Get re-ordering correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Re-ordering correlation probability or a negative error code.
+ */
+int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR)
+               return netem->qnm_ro.nmro_correlation;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Corruption
+ * @{
+ */
+/**
+ * Set corruption probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob           New corruption probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_crpt.nmcr_probability = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB;
+}
+
+/**
+ * Get corruption probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Corruption probability or a negative error code.
+ */
+int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB)
+               return netem->qnm_crpt.nmcr_probability;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set corruption correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob           New corruption correlation probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_crpt.nmcr_correlation = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR;
+}
+
+/**
+ * Get corruption correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Corruption correlation probability or a negative error code.
+ */
+int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR)
+               return netem->qnm_crpt.nmcr_correlation;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Loss
+ * @{
+ */
+
+/**
+ * Set packet loss probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob           New packet loss probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_loss = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_LOSS;
+}
+
+/**
+ * Get packet loss probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Packet loss probability or a negative error code.
+ */
+int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS)
+               return netem->qnm_loss;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set packet loss correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob   New packet loss correlation.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_corr.nmc_loss = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR;
+}
+
+/**
+ * Get packet loss correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Packet loss correlation probability or a negative error code.
+ */
+int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR)
+               return netem->qnm_corr.nmc_loss;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Duplication
+ * @{
+ */
+
+/**
+ * Set packet duplication probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob   New packet duplication probability.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_duplicate = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE;
+}
+
+/**
+ * Get packet duplication probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Packet duplication probability or a negative error code.
+ */
+int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE)
+               return netem->qnm_duplicate;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set packet duplication correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob           New packet duplication correlation probability.
+ * @return 0 on sucess or a negative error code.
+ */
+void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_corr.nmc_duplicate = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR;
+}
+
+/**
+ * Get packet duplication correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Packet duplication correlation probability or a negative error code.
+ */
+int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR)
+               return netem->qnm_corr.nmc_duplicate;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+/**
+ * @name Packet Delay
+ * @{
+ */
+
+/**
+ * Set packet delay of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg delay          New packet delay in micro seconds.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_latency = nl_us2ticks(delay);
+       netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY;
+}
+
+/**
+ * Get packet delay of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Packet delay in micro seconds or a negative error code.
+ */
+int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY)
+               return nl_ticks2us(netem->qnm_latency);
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set packet delay jitter of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg jitter         New packet delay jitter in micro seconds.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_jitter = nl_us2ticks(jitter);
+       netem->qnm_mask |= SCH_NETEM_ATTR_JITTER;
+}
+
+/**
+ * Get packet delay jitter of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Packet delay jitter in micro seconds or a negative error code.
+ */
+int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER)
+               return nl_ticks2us(netem->qnm_jitter);
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set packet delay correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc to be modified.
+ * @arg prob           New packet delay correlation probability.
+ */
+void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       netem->qnm_corr.nmc_delay = prob;
+       netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR;
+}
+
+/**
+ * Get packet delay correlation probability of netem qdisc.
+ * @arg qdisc          Netem qdisc.
+ * @return Packet delay correlation probability or a negative error code.
+ */
+int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR)
+               return netem->qnm_corr.nmc_delay;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Get the size of the distribution table.
+ * @arg qdisc          Netem qdisc.
+ * @return Distribution table size or a negative error code.
+ */
+int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_DIST)
+               return netem->qnm_dist.dist_size;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Get a pointer to the distribution table.
+ * @arg qdisc          Netem qdisc.
+ * @arg dist_ptr       The pointer to set.
+ * @return Negative error code on failure or 0 on success.
+ */
+int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr)
+{
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) {
+               *dist_ptr = netem->qnm_dist.dist_data;
+               return 0;
+       } else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set the delay distribution. Latency/jitter must be set before applying.
+ * @arg qdisc Netem qdisc.
+ * @arg dist_type The name of the distribution (type, file, path/file).
+ * @return 0 on success, error code on failure.
+ */
+int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) {
+       struct rtnl_netem *netem;
+
+       if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+               
+       FILE *f;
+       int n = 0;
+       size_t i;
+       size_t len = 2048;
+       char *line;
+       char name[NAME_MAX];
+       char dist_suffix[] = ".dist";
+       
+       /* If the given filename already ends in .dist, don't append it later */
+       char *test_suffix = strstr(dist_type, dist_suffix);
+       if (test_suffix != NULL && strlen(test_suffix) == 5)
+               strcpy(dist_suffix, "");
+       
+       /* Check several locations for the dist file */
+       char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" };
+       
+       for (i = 0; i < ARRAY_SIZE(test_path); i++) {
+               snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix);
+               if ((f = fopen(name, "r")))
+                       break;
+       }
+       
+       if ( f == NULL )
+               return -nl_syserr2nlerr(errno);
+       
+       netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
+       
+       line = (char *) calloc (sizeof(char), len + 1);
+       
+       while (getline(&line, &len, f) != -1) {
+               char *p, *endp;
+               
+               if (*line == '\n' || *line == '#')
+                       continue;
+
+               for (p = line; ; p = endp) {
+                       long x = strtol(p, &endp, 0);
+                       if (endp == p) break;
+
+                       if (n >= MAXDIST) {
+                               free(line);
+                               fclose(f);
+                               return -NLE_INVAL;
+                       }
+                       netem->qnm_dist.dist_data[n++] = x;
+               }               
+       }
+       
+       free(line);
+       
+       netem->qnm_dist.dist_size = n;
+       netem->qnm_mask |= SCH_NETEM_ATTR_DIST;
+       
+       fclose(f);
+       return 0;       
+}
+
+/** @} */
+
+static struct rtnl_tc_ops netem_ops = {
+       .to_kind                = "netem",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_netem),
+       .to_msg_parser          = netem_msg_parser,
+       .to_free_data           = netem_free_data,
+       .to_dump[NL_DUMP_LINE]  = netem_dump_line,
+       .to_msg_fill_raw        = netem_msg_fill_raw,
+};
+
+static void __init netem_init(void)
+{
+       rtnl_tc_register(&netem_ops);
+}
+
+static void __exit netem_exit(void)
+{
+       rtnl_tc_unregister(&netem_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/plug.c b/lib/route/qdisc/plug.c
new file mode 100644 (file)
index 0000000..9f53637
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * lib/route/qdisc/plug.c              PLUG Qdisc
+ *
+ *     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) 2012 Shriram Rajagopalan <rshriram@cs.ubc.ca>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_plug Plug/Unplug Traffic (PLUG)
+ * @brief
+ *
+ * Queue traffic until an explicit release command.
+ *
+ * There are two ways to use this qdisc:
+ * 1. A simple "instantaneous" plug/unplug operation, by issuing an alternating
+ *    sequence of TCQ_PLUG_BUFFER & TCQ_PLUG_RELEASE_INDEFINITE commands.
+ *
+ * 2. For network output buffering (a.k.a output commit) functionality.
+ *    Output commit property is commonly used by applications using checkpoint
+ *    based fault-tolerance to ensure that the checkpoint from which a system
+ *    is being restored is consistent w.r.t outside world.
+ *
+ *    Consider for e.g. Remus - a Virtual Machine checkpointing system,
+ *    wherein a VM is checkpointed, say every 50ms. The checkpoint is replicated
+ *    asynchronously to the backup host, while the VM continues executing the
+ *    next epoch speculatively.
+ *
+ *    The following is a typical sequence of output buffer operations:
+ *       1.At epoch i, start_buffer(i)
+ *       2. At end of epoch i (i.e. after 50ms):
+ *          2.1 Stop VM and take checkpoint(i).
+ *          2.2 start_buffer(i+1) and Resume VM
+ *       3. While speculatively executing epoch(i+1), asynchronously replicate
+ *          checkpoint(i) to backup host.
+ *       4. When checkpoint_ack(i) is received from backup, release_buffer(i)
+ *    Thus, this Qdisc would receive the following sequence of commands:
+ *       TCQ_PLUG_BUFFER (epoch i)
+ *       .. TCQ_PLUG_BUFFER (epoch i+1)
+ *       ....TCQ_PLUG_RELEASE_ONE (epoch i)
+ *       ......TCQ_PLUG_BUFFER (epoch i+2)
+ *       ........
+ *
+ *
+ * State of the queue, when used for network output buffering:
+ *
+ *                 plug(i+1)            plug(i)          head
+ * ------------------+--------------------+---------------->
+ *                   |                    |
+ *                   |                    |
+ * pkts_current_epoch| pkts_last_epoch    |pkts_to_release
+ * ----------------->|<--------+--------->|+--------------->
+ *                   v                    v
+ *
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc/plug.h>
+
+static int plug_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       struct rtnl_plug *plug = data;
+       struct tc_plug_qopt opts;
+
+       if (!plug)
+               return -NLE_INVAL;
+
+       opts.action = plug->action;
+       opts.limit  = plug->limit;
+
+       return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Insert a plug into the qdisc and buffer any incoming
+ * network traffic.
+ * @arg qdisc          PLUG qdisc to be modified.
+ */
+int rtnl_qdisc_plug_buffer(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_plug *plug;
+
+       if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       plug->action = TCQ_PLUG_BUFFER;
+       return 0;
+}
+
+/**
+ * Unplug the qdisc, releasing packets from queue head
+ * to the last complete buffer, while new traffic
+ * continues to be buffered.
+ * @arg qdisc          PLUG qdisc to be modified.
+ */
+int rtnl_qdisc_plug_release_one(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_plug *plug;
+
+       if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       plug->action = TCQ_PLUG_RELEASE_ONE;
+       return 0;
+}
+
+/**
+ * Indefinitely unplug the qdisc, releasing all packets.
+ * Network traffic will not be buffered until the next
+ * buffer command is issued.
+ * @arg qdisc          PLUG qdisc to be modified.
+ */
+int rtnl_qdisc_plug_release_indefinite(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_plug *plug;
+
+       if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+
+       plug->action = TCQ_PLUG_RELEASE_INDEFINITE;
+       return 0;
+}
+
+/**
+ * Set limit of PLUG qdisc.
+ * @arg qdisc          PLUG qdisc to be modified.
+ * @arg limit          New limit.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_plug_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+       struct rtnl_plug *plug;
+       
+       if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
+               return -NLE_NOMEM;
+               
+       plug->action = TCQ_PLUG_LIMIT;
+       plug->limit  = limit;
+
+       return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops plug_ops = {
+       .to_kind                = "plug",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_plug),
+       .to_msg_fill            = plug_msg_fill,
+};
+
+static void __init plug_init(void)
+{
+       rtnl_tc_register(&plug_ops);
+}
+
+static void __exit plug_exit(void)
+{
+       rtnl_tc_unregister(&plug_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/prio.c b/lib/route/qdisc/prio.c
new file mode 100644 (file)
index 0000000..54a46f0
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * lib/route/qdisc/prio.c              PRIO Qdisc/Class
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_prio (Fast) Prio
+ * @brief
+ *
+ * @par 1) Typical PRIO configuration
+ * @code
+ * // Specify the maximal number of bands to be used for this PRIO qdisc.
+ * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
+ *
+ * // Provide a map assigning each priority to a band number.
+ * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
+ * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
+ * @endcode
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/prio.h>
+
+/** @cond SKIP */
+#define SCH_PRIO_ATTR_BANDS    1
+#define SCH_PRIO_ATTR_PRIOMAP  2
+/** @endcond */
+
+static int prio_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_prio *prio = data;
+       struct tc_prio_qopt *opt;
+
+       if (tc->tc_opts->d_size < sizeof(*opt))
+               return -NLE_INVAL;
+
+       opt = (struct tc_prio_qopt *) tc->tc_opts->d_data;
+       prio->qp_bands = opt->bands;
+       memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
+       prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
+       
+       return 0;
+}
+
+static void prio_dump_line(struct rtnl_tc *tc, void *data,
+                          struct nl_dump_params *p)
+{
+       struct rtnl_prio *prio = data;
+
+       if (prio)
+               nl_dump(p, " bands %u", prio->qp_bands);
+}
+
+static void prio_dump_details(struct rtnl_tc *tc, void *data,
+                             struct nl_dump_params *p)
+{
+       struct rtnl_prio *prio = data;
+       int i, hp;
+
+       if (!prio)
+               return;
+
+       nl_dump(p, "priomap [");
+       
+       for (i = 0; i <= TC_PRIO_MAX; i++)
+               nl_dump(p, "%u%s", prio->qp_priomap[i],
+                       i < TC_PRIO_MAX ? " " : "");
+
+       nl_dump(p, "]\n");
+       nl_new_line(p);
+
+       hp = (((TC_PRIO_MAX/2) + 1) & ~1);
+
+       for (i = 0; i < hp; i++) {
+               char a[32];
+               nl_dump(p, "    %18s => %u",
+                       rtnl_prio2str(i, a, sizeof(a)),
+                       prio->qp_priomap[i]);
+               if (hp+i <= TC_PRIO_MAX) {
+                       nl_dump(p, " %18s => %u",
+                               rtnl_prio2str(hp+i, a, sizeof(a)),
+                               prio->qp_priomap[hp+i]);
+                       if (i < (hp - 1)) {
+                               nl_dump(p, "\n");
+                               nl_new_line(p);
+                       }
+               }
+       }
+}
+
+static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       struct rtnl_prio *prio = data;
+       struct tc_prio_qopt opts;
+
+       if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
+               BUG();
+
+       opts.bands = prio->qp_bands;
+       memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
+
+       return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Set number of bands of PRIO qdisc.
+ * @arg qdisc          PRIO qdisc to be modified.
+ * @arg bands          New number of bands.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
+{
+       struct rtnl_prio *prio;
+
+       if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       prio->qp_bands = bands;
+       prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
+}
+
+/**
+ * Get number of bands of PRIO qdisc.
+ * @arg qdisc          PRIO qdisc.
+ * @return Number of bands or a negative error code.
+ */
+int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_prio *prio;
+
+       if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (prio->qp_mask & SCH_PRIO_ATTR_BANDS)
+               return prio->qp_bands;
+       else
+               return -NLE_NOMEM;
+}
+
+/**
+ * Set priomap of the PRIO qdisc.
+ * @arg qdisc          PRIO qdisc to be modified.
+ * @arg priomap                New priority mapping.
+ * @arg len            Length of priomap (# of elements).
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
+                               int len)
+{
+       struct rtnl_prio *prio;
+       int i;
+
+       if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
+               return -NLE_MISSING_ATTR;
+
+       if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
+               return -NLE_RANGE;
+
+       for (i = 0; i <= TC_PRIO_MAX; i++) {
+               if (priomap[i] > prio->qp_bands)
+                       return -NLE_RANGE;
+       }
+
+       memcpy(prio->qp_priomap, priomap, len);
+       prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
+
+       return 0;
+}
+
+/**
+ * Get priomap of a PRIO qdisc.
+ * @arg qdisc          PRIO qdisc.
+ * @return Priority mapping as array of size TC_PRIO_MAX+1
+ *         or NULL if an error occured.
+ */
+uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_prio *prio;
+
+       if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
+               return prio->qp_priomap;
+       else
+               return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Priority Band Translations
+ * @{
+ */
+
+static const struct trans_tbl prios[] = {
+       __ADD(TC_PRIO_BESTEFFORT,besteffort)
+       __ADD(TC_PRIO_FILLER,filler)
+       __ADD(TC_PRIO_BULK,bulk)
+       __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
+       __ADD(TC_PRIO_INTERACTIVE,interactive)
+       __ADD(TC_PRIO_CONTROL,control)
+};
+
+/**
+ * Convert priority to character string.
+ * @arg prio           Priority.
+ * @arg buf            Destination buffer
+ * @arg size           Size of destination buffer.
+ *
+ * Converts a priority to a character string and stores the result in
+ * the specified destination buffer.
+ *
+ * @return Name of priority as character string.
+ */
+char * rtnl_prio2str(int prio, char *buf, size_t size)
+{
+       return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
+}
+
+/**
+ * Convert character string to priority.
+ * @arg name           Name of priority.
+ *
+ * Converts the provided character string specifying a priority
+ * to the corresponding numeric value.
+ *
+ * @return Numeric priority or a negative value if no match was found.
+ */
+int rtnl_str2prio(const char *name)
+{
+       return __str2type(name, prios, ARRAY_SIZE(prios));
+}
+
+/** @} */
+
+static struct rtnl_tc_ops prio_ops = {
+       .to_kind                = "prio",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_prio),
+       .to_msg_parser          = prio_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = prio_dump_line,
+           [NL_DUMP_DETAILS]   = prio_dump_details,
+       },
+       .to_msg_fill            = prio_msg_fill,
+};
+
+static struct rtnl_tc_ops pfifo_fast_ops = {
+       .to_kind                = "pfifo_fast",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_prio),
+       .to_msg_parser          = prio_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = prio_dump_line,
+           [NL_DUMP_DETAILS]   = prio_dump_details,
+       },
+       .to_msg_fill            = prio_msg_fill,
+};
+
+static void __init prio_init(void)
+{
+       rtnl_tc_register(&prio_ops);
+       rtnl_tc_register(&pfifo_fast_ops);
+}
+
+static void __exit prio_exit(void)
+{
+       rtnl_tc_unregister(&prio_ops);
+       rtnl_tc_unregister(&pfifo_fast_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/red.c b/lib/route/qdisc/red.c
new file mode 100644 (file)
index 0000000..f05626e
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * lib/route/qdisc/red.c               RED Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_red Random Early Detection (RED)
+ * @brief
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/red.h>
+
+/** @cond SKIP */
+#define RED_ATTR_LIMIT         0x01
+#define RED_ATTR_QTH_MIN       0x02
+#define RED_ATTR_QTH_MAX       0x04
+#define RED_ATTR_FLAGS         0x08
+#define RED_ATTR_WLOG          0x10
+#define RED_ATTR_PLOG          0x20
+#define RED_ATTR_SCELL_LOG     0x40
+/** @endcond */
+
+static struct nla_policy red_policy[TCA_RED_MAX+1] = {
+       [TCA_RED_PARMS]         = { .minlen = sizeof(struct tc_red_qopt) },
+};
+
+static int red_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_RED_MAX+1];
+       struct rtnl_red *red = data;
+       struct tc_red_qopt *opts;
+       int err;
+
+       if (!(tc->ce_mask & TCA_ATTR_OPTS))
+               return 0;
+
+       err = tca_parse(tb, TCA_RED_MAX, tc, red_policy);
+       if (err < 0)
+               return err;
+
+       if (!tb[TCA_RED_PARMS])
+               return -NLE_MISSING_ATTR;
+
+       opts = nla_data(tb[TCA_RED_PARMS]);
+
+       red->qr_limit = opts->limit;
+       red->qr_qth_min = opts->qth_min;
+       red->qr_qth_max = opts->qth_max;
+       red->qr_flags = opts->flags;
+       red->qr_wlog = opts->Wlog;
+       red->qr_plog = opts->Plog;
+       red->qr_scell_log = opts->Scell_log;
+
+       red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX |
+                       RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG |
+                       RED_ATTR_SCELL_LOG);
+
+       return 0;
+}
+
+static void red_dump_line(struct rtnl_tc *tc, void *data,
+                         struct nl_dump_params *p)
+{
+       struct rtnl_red *red = data;
+
+       if (red) {
+               /* XXX: limit, min, max, flags */
+       }
+}
+
+static void red_dump_details(struct rtnl_tc *tc, void *data,
+                            struct nl_dump_params *p)
+{
+       struct rtnl_red *red = data;
+
+       if (red) {
+               /* XXX: wlog, plog, scell_log */
+       }
+}
+
+static void red_dump_stats(struct rtnl_tc *tc, void *data,
+                          struct nl_dump_params *p)
+{
+       struct rtnl_red *red = data;
+
+       if (red) {
+               /* XXX: xstats */
+       }
+}
+
+static int red_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       struct rtnl_red *red = data;
+
+       if (!red)
+               BUG();
+
+#if 0
+       memset(&opts, 0, sizeof(opts));
+       opts.quantum = sfq->qs_quantum;
+       opts.perturb_period = sfq->qs_perturb;
+       opts.limit = sfq->qs_limit;
+
+       if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0)
+               goto errout;
+#endif
+
+       return -NLE_OPNOTSUPP;
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set limit of RED qdisc.
+ * @arg qdisc          RED qdisc to be modified.
+ * @arg limit          New limit in number of packets.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+       struct rtnl_red *red;
+
+       if (!(red = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       red->qr_limit = limit;
+       red->qr_mask |= RED_ATTR_LIMIT;
+}
+
+/**
+ * Get limit of RED qdisc.
+ * @arg qdisc          RED qdisc.
+ * @return Limit or a negative error code.
+ */
+int rtnl_red_get_limit(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_red *red;
+
+       if (!(red = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (red->qr_mask & RED_ATTR_LIMIT)
+               return red->qr_limit;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops red_ops = {
+       .to_kind                = "red",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_red),
+       .to_msg_parser          = red_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = red_dump_line,
+           [NL_DUMP_DETAILS]   = red_dump_details,
+           [NL_DUMP_STATS]     = red_dump_stats,
+       },
+       .to_msg_fill            = red_msg_fill,
+};
+
+static void __init red_init(void)
+{
+       rtnl_tc_register(&red_ops);
+}
+
+static void __exit red_exit(void)
+{
+       rtnl_tc_unregister(&red_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/sfq.c b/lib/route/qdisc/sfq.c
new file mode 100644 (file)
index 0000000..acbb4ef
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * lib/route/qdisc/sfq.c               SFQ Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_sfq Stochastic Fairness Queueing (SFQ)
+ * @brief
+ *
+ * @par Parameter Description
+ * - \b Quantum: Number of bytes to send out per slot and round.
+ * - \b Perturbation: Timer period between changing the hash function.
+ * - \b Limit:  Upper limit of queue in number of packets before SFQ starts
+ *             dropping packets.
+ * - \b Divisor: Hash table divisor, i.e. size of hash table.
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/sfq.h>
+
+/** @cond SKIP */
+#define SCH_SFQ_ATTR_QUANTUM   0x01
+#define SCH_SFQ_ATTR_PERTURB   0x02
+#define SCH_SFQ_ATTR_LIMIT     0x04
+#define SCH_SFQ_ATTR_DIVISOR   0x08
+#define SCH_SFQ_ATTR_FLOWS     0x10
+/** @endcond */
+
+static int sfq_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct rtnl_sfq *sfq = data;
+       struct tc_sfq_qopt *opts;
+
+       if (!(tc->ce_mask & TCA_ATTR_OPTS))
+               return 0;
+
+       if (tc->tc_opts->d_size < sizeof(*opts))
+               return -NLE_INVAL;
+
+       opts = (struct tc_sfq_qopt *) tc->tc_opts->d_data;
+
+       sfq->qs_quantum = opts->quantum;
+       sfq->qs_perturb = opts->perturb_period;
+       sfq->qs_limit = opts->limit;
+       sfq->qs_divisor = opts->divisor;
+       sfq->qs_flows = opts->flows;
+
+       sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB |
+                       SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR |
+                       SCH_SFQ_ATTR_FLOWS);
+
+       return 0;
+}
+
+static void sfq_dump_line(struct rtnl_tc *tc, void *data,
+                         struct nl_dump_params *p)
+{
+       struct rtnl_sfq *sfq = data;
+
+       if (sfq)
+               nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum,
+                       sfq->qs_perturb);
+}
+
+static void sfq_dump_details(struct rtnl_tc *tc, void *data,
+                            struct nl_dump_params *p)
+{
+       struct rtnl_sfq *sfq = data;
+
+       if (sfq)
+               nl_dump(p, "limit %u divisor %u",
+                       sfq->qs_limit, sfq->qs_divisor);
+}
+
+static int sfq_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       struct rtnl_sfq *sfq = data;
+       struct tc_sfq_qopt opts = {0};
+
+       if (!sfq)
+               BUG();
+
+       opts.quantum = sfq->qs_quantum;
+       opts.perturb_period = sfq->qs_perturb;
+       opts.limit = sfq->qs_limit;
+
+       return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set quantum of SFQ qdisc.
+ * @arg qdisc          SFQ qdisc to be modified.
+ * @arg quantum                New quantum in bytes.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum)
+{
+       struct rtnl_sfq *sfq;
+       
+       if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       sfq->qs_quantum = quantum;
+       sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM;
+}
+
+/**
+ * Get quantum of SFQ qdisc.
+ * @arg qdisc          SFQ qdisc.
+ * @return Quantum in bytes or a negative error code.
+ */
+int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_sfq *sfq;
+       
+       if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM)
+               return sfq->qs_quantum;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set limit of SFQ qdisc.
+ * @arg qdisc          SFQ qdisc to be modified.
+ * @arg limit          New limit in number of packets.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+       struct rtnl_sfq *sfq;
+       
+       if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       sfq->qs_limit = limit;
+       sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT;
+}
+
+/**
+ * Get limit of SFQ qdisc.
+ * @arg qdisc          SFQ qdisc.
+ * @return Limit or a negative error code.
+ */
+int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_sfq *sfq;
+       
+       if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (sfq->qs_mask & SCH_SFQ_ATTR_LIMIT)
+               return sfq->qs_limit;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Set perturbation interval of SFQ qdisc.
+ * @arg qdisc          SFQ qdisc to be modified.
+ * @arg perturb                New perturbation interval in seconds.
+ * @note A value of 0 disables perturbation altogether.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb)
+{
+       struct rtnl_sfq *sfq;
+       
+       if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       sfq->qs_perturb = perturb;
+       sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB;
+}
+
+/**
+ * Get perturbation interval of SFQ qdisc.
+ * @arg qdisc          SFQ qdisc.
+ * @return Perturbation interval in seconds or a negative error code.
+ */
+int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_sfq *sfq;
+       
+       if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (sfq->qs_mask & SCH_SFQ_ATTR_PERTURB)
+               return sfq->qs_perturb;
+       else
+               return -NLE_NOATTR;
+}
+
+/**
+ * Get divisor of SFQ qdisc.
+ * @arg qdisc          SFQ qdisc.
+ * @return Divisor in number of entries or a negative error code.
+ */
+int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_sfq *sfq;
+       
+       if (!(sfq = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR)
+               return sfq->qs_divisor;
+       else
+               return -NLE_NOATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops sfq_ops = {
+       .to_kind                = "sfq",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_sfq),
+       .to_msg_parser          = sfq_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = sfq_dump_line,
+           [NL_DUMP_DETAILS]   = sfq_dump_details,
+       },
+       .to_msg_fill            = sfq_msg_fill,
+};
+
+static void __init sfq_init(void)
+{
+       rtnl_tc_register(&sfq_ops);
+}
+
+static void __exit sfq_exit(void)
+{
+       rtnl_tc_unregister(&sfq_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/tbf.c b/lib/route/qdisc/tbf.c
new file mode 100644 (file)
index 0000000..eb574d9
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * lib/route/qdisc/tbf.c               TBF Qdisc
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup qdisc
+ * @defgroup qdisc_tbf Token Bucket Filter (TBF)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/tbf.h>
+
+/** @cond SKIP */
+#define TBF_ATTR_LIMIT                 0x01
+#define TBF_ATTR_RATE                  0x02
+#define TBF_ATTR_PEAKRATE              0x10
+/** @endcond */
+
+static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = {
+       [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) },
+};
+
+static int tbf_msg_parser(struct rtnl_tc *tc, void *data)
+{
+       struct nlattr *tb[TCA_TBF_MAX + 1];
+       struct rtnl_tbf *tbf = data;
+       int err;
+
+       if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
+               return err;
+       
+       if (tb[TCA_TBF_PARMS]) {
+               struct tc_tbf_qopt opts;
+               int bufsize;
+
+               nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
+               tbf->qt_limit = opts.limit;
+       
+               rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
+               tbf->qt_rate_txtime = opts.buffer;
+               bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
+                                              opts.rate.rate);
+               tbf->qt_rate_bucket = bufsize;
+
+               rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
+               tbf->qt_peakrate_txtime = opts.mtu;
+               bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu),
+                                              opts.peakrate.rate);
+               tbf->qt_peakrate_bucket = bufsize;
+
+               rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu);
+               rtnl_tc_set_overhead(tc, tbf->qt_rate.rs_overhead);
+
+               tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE);
+       }
+
+       return 0;
+}
+
+static void tbf_dump_line(struct rtnl_tc *tc, void *data,
+                         struct nl_dump_params *p)
+{
+       double r, rbit, lim;
+       char *ru, *rubit, *limu;
+       struct rtnl_tbf *tbf = data;
+
+       if (!tbf)
+               return;
+
+       r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
+       rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
+       lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
+
+       nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
+               r, ru, rbit, rubit, lim, limu);
+}
+
+static void tbf_dump_details(struct rtnl_tc *tc, void *data,
+                            struct nl_dump_params *p)
+{
+       struct rtnl_tbf *tbf = data;
+
+       if (!tbf)
+               return;
+
+       if (1) {
+               char *bu, *cu;
+               double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu);
+               double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log,
+                                                &cu);
+
+               nl_dump(p, "rate-bucket-size %1.f%s "
+                          "rate-cell-size %.1f%s\n",
+                       bs, bu, cl, cu);
+
+       }
+
+       if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
+               char *pru, *prbu, *bsu, *clu;
+               double pr, prb, bs, cl;
+               
+               pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru);
+               prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu);
+               bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
+               cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
+                                        &clu);
+
+               nl_dump_line(p, "    peak-rate %.2f%s/s (%.0f%s) "
+                               "bucket-size %.1f%s cell-size %.1f%s"
+                               "latency %.1f%s",
+                            pr, pru, prb, prbu, bs, bsu, cl, clu);
+       }
+}
+
+static int tbf_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+       uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE];
+       struct tc_tbf_qopt opts;
+       struct rtnl_tbf *tbf = data;
+       int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT;
+
+       if ((tbf->qt_mask & required) != required)
+               return -NLE_MISSING_ATTR;
+
+       memset(&opts, 0, sizeof(opts));
+       opts.limit = tbf->qt_limit;
+       opts.buffer = tbf->qt_rate_txtime;
+
+       rtnl_tc_build_rate_table(tc, &tbf->qt_rate, rtab);
+       rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate);
+
+       if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
+               opts.mtu = tbf->qt_peakrate_txtime;
+               rtnl_tc_build_rate_table(tc, &tbf->qt_peakrate, ptab);
+               rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate);
+
+       }
+
+       NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts);
+       NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab);
+
+       if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+               NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab);
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * @name Attribute Access
+ * @{
+ */
+
+/**
+ * Set limit of TBF qdisc.
+ * @arg qdisc          TBF qdisc to be modified.
+ * @arg limit          New limit in bytes.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit)
+{
+       struct rtnl_tbf *tbf;
+       
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       tbf->qt_limit = limit;
+       tbf->qt_mask |= TBF_ATTR_LIMIT;
+}
+
+static inline double calc_limit(struct rtnl_ratespec *spec, int latency,
+                               int bucket)
+{
+       double limit;
+
+       limit = (double) spec->rs_rate * ((double) latency / 1000000.);
+       limit += bucket;
+
+       return limit;
+}
+
+/**
+ * Set limit of TBF qdisc by latency.
+ * @arg qdisc          TBF qdisc to be modified.
+ * @arg latency                Latency in micro seconds.
+ *
+ * Calculates and sets the limit based on the desired latency and the
+ * configured rate and peak rate. In order for this operation to succeed,
+ * the rate and if required the peak rate must have been set in advance.
+ *
+ * @f[
+ *   limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n
+ * @f]
+ * @f[
+ *   limit = min(limit_{rate},limit_{peak})
+ * @f]
+ * 
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency)
+{
+       struct rtnl_tbf *tbf;
+       double limit, limit2;
+
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (!(tbf->qt_mask & TBF_ATTR_RATE))
+               return -NLE_MISSING_ATTR;
+
+       limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket);
+
+       if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
+               limit2 = calc_limit(&tbf->qt_peakrate, latency,
+                                   tbf->qt_peakrate_bucket);
+
+               if (limit2 < limit)
+                       limit = limit2;
+       }
+
+       rtnl_qdisc_tbf_set_limit(qdisc, (int) limit);
+
+       return 0;
+}
+
+/**
+ * Get limit of TBF qdisc.
+ * @arg qdisc          TBF qdisc.
+ * @return Limit in bytes or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_tbf *tbf;
+       
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (tbf->qt_mask & TBF_ATTR_LIMIT)
+               return tbf->qt_limit;
+       else
+               return -NLE_NOATTR;
+}
+
+static inline int calc_cell_log(int cell, int bucket)
+{
+               cell = rtnl_tc_calc_cell_log(cell);
+       return cell;
+}
+
+/**
+ * Set rate of TBF qdisc.
+ * @arg qdisc          TBF qdisc to be modified.
+ * @arg rate           New rate in bytes per second.
+ * @arg bucket         Size of bucket in bytes.
+ * @arg cell           Size of a rate cell or 0 to get default value.
+ * @return 0 on success or a negative error code.
+ */
+void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
+                           int cell)
+{
+       struct rtnl_tbf *tbf;
+       int cell_log;
+       
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (!cell)
+               cell_log = UINT8_MAX;
+       else
+               cell_log = rtnl_tc_calc_cell_log(cell);
+
+       tbf->qt_rate.rs_rate = rate;
+       tbf->qt_rate_bucket = bucket;
+       tbf->qt_rate.rs_cell_log = cell_log;
+       tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
+       tbf->qt_mask |= TBF_ATTR_RATE;
+}
+
+/**
+ * Get rate of TBF qdisc.
+ * @arg qdisc          TBF qdisc.
+ * @return Rate in bytes per seconds or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_tbf *tbf;
+
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (tbf->qt_mask & TBF_ATTR_RATE)
+               return tbf->qt_rate.rs_rate;
+       else
+               return -1;
+}
+
+/**
+ * Get rate bucket size of TBF qdisc.
+ * @arg qdisc          TBF qdisc.
+ * @return Size of rate bucket or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_tbf *tbf;
+
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (tbf->qt_mask & TBF_ATTR_RATE)
+               return tbf->qt_rate_bucket;
+       else
+               return -1;
+}
+
+/**
+ * Get rate cell size of TBF qdisc.
+ * @arg qdisc          TBF qdisc.
+ * @return Size of rate cell in bytes or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_tbf *tbf;
+
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (tbf->qt_mask & TBF_ATTR_RATE)
+               return (1 << tbf->qt_rate.rs_cell_log);
+       else
+               return -1;
+}
+
+/**
+ * Set peak rate of TBF qdisc.
+ * @arg qdisc          TBF qdisc to be modified.
+ * @arg rate           New peak rate in bytes per second.
+ * @arg bucket         Size of peakrate bucket.
+ * @arg cell           Size of a peakrate cell or 0 to get default value.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
+                               int cell)
+{
+       struct rtnl_tbf *tbf;
+       int cell_log;
+       
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       cell_log = calc_cell_log(cell, bucket);
+       if (cell_log < 0)
+               return cell_log;
+
+       tbf->qt_peakrate.rs_rate = rate;
+       tbf->qt_peakrate_bucket = bucket;
+       tbf->qt_peakrate.rs_cell_log = cell_log;
+       tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
+       
+       tbf->qt_mask |= TBF_ATTR_PEAKRATE;
+
+       return 0;
+}
+
+/**
+ * Get peak rate of TBF qdisc.
+ * @arg qdisc          TBF qdisc.
+ * @return Peak rate in bytes per seconds or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_tbf *tbf;
+
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+               return tbf->qt_peakrate.rs_rate;
+       else
+               return -1;
+}
+
+/**
+ * Get peak rate bucket size of TBF qdisc.
+ * @arg qdisc          TBF qdisc.
+ * @return Size of peak rate bucket or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_tbf *tbf;
+
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+               return tbf->qt_peakrate_bucket;
+       else
+               return -1;
+}
+
+/**
+ * Get peak rate cell size of TBF qdisc.
+ * @arg qdisc          TBF qdisc.
+ * @return Size of peak rate cell in bytes or a negative error code.
+ */
+int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc)
+{
+       struct rtnl_tbf *tbf;
+
+       if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
+               BUG();
+
+       if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
+               return (1 << tbf->qt_peakrate.rs_cell_log);
+       else
+               return -1;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops tbf_tc_ops = {
+       .to_kind                = "tbf",
+       .to_type                = RTNL_TC_TYPE_QDISC,
+       .to_size                = sizeof(struct rtnl_tbf),
+       .to_msg_parser          = tbf_msg_parser,
+       .to_dump = {
+           [NL_DUMP_LINE]      = tbf_dump_line,
+           [NL_DUMP_DETAILS]   = tbf_dump_details,
+       },
+       .to_msg_fill            = tbf_msg_fill,
+};
+
+static void __init tbf_init(void)
+{
+       rtnl_tc_register(&tbf_tc_ops);
+}
+
+static void __exit tbf_exit(void)
+{
+       rtnl_tc_unregister(&tbf_tc_ops);
+}
+
+/** @} */
diff --git a/lib/route/route.c b/lib/route/route.c
new file mode 100644 (file)
index 0000000..2985187
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * lib/route/route.c   Routes
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup route Routing
+ * @brief
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink/data.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/link.h>
+
+static struct nl_cache_ops rtnl_route_ops;
+
+static int route_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                           struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+       struct rtnl_route *route;
+       int err;
+
+       if ((err = rtnl_route_parse(nlh, &route)) < 0)
+               return err;
+
+       err = pp->pp_cb((struct nl_object *) route, pp);
+
+       rtnl_route_put(route);
+       return err;
+}
+
+static int route_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+       struct rtmsg rhdr = {
+               .rtm_family = c->c_iarg1,
+       };
+
+       if (c->c_iarg2 & ROUTE_CACHE_CONTENT)
+               rhdr.rtm_flags |= RTM_F_CLONED;
+
+       return nl_send_simple(h, RTM_GETROUTE, NLM_F_DUMP, &rhdr, sizeof(rhdr));
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Build a route cache holding all routes currently configured in the kernel
+ * @arg sk             Netlink socket.
+ * @arg family         Address family of routes to cover or AF_UNSPEC
+ * @arg flags          Flags
+ * @arg result         Result pointer
+ *
+ * Allocates a new cache, initializes it properly and updates it to
+ * contain all routes currently configured in the kernel.
+ *
+ * Valid flags:
+ *   * ROUTE_CACHE_CONTENT - Cache will contain contents of routing cache
+ *                           instead of actual routes.
+ *
+ * @note The caller is responsible for destroying and freeing the
+ *       cache after using it.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_route_alloc_cache(struct nl_sock *sk, int family, int flags,
+                          struct nl_cache **result)
+{
+       struct nl_cache *cache;
+       int err;
+
+       if (!(cache = nl_cache_alloc(&rtnl_route_ops)))
+               return -NLE_NOMEM;
+
+       cache->c_iarg1 = family;
+       cache->c_iarg2 = flags;
+
+       if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
+               free(cache);
+               return err;
+       }
+
+       *result = cache;
+       return 0;
+}
+
+/** @} */
+
+/**
+ * @name Route Addition
+ * @{
+ */
+
+static int build_route_msg(struct rtnl_route *tmpl, int cmd, int flags,
+                          struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if (!(msg = nlmsg_alloc_simple(cmd, flags)))
+               return -NLE_NOMEM;
+
+       if ((err = rtnl_route_build_msg(msg, tmpl)) < 0) {
+               nlmsg_free(msg);
+               return err;
+       }
+
+       *result = msg;
+       return 0;
+}
+
+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,
+                              result);
+}
+
+int rtnl_route_add(struct nl_sock *sk, struct rtnl_route *route, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_route_build_add_request(route, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+int rtnl_route_build_del_request(struct rtnl_route *tmpl, int flags,
+                                struct nl_msg **result)
+{
+       return build_route_msg(tmpl, RTM_DELROUTE, flags, result);
+}
+
+int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+
+       if ((err = rtnl_route_build_del_request(route, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+static struct nl_af_group route_groups[] = {
+       { AF_INET,      RTNLGRP_IPV4_ROUTE },
+       { AF_INET6,     RTNLGRP_IPV6_ROUTE },
+       { AF_DECnet,    RTNLGRP_DECnet_ROUTE },
+       { END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_route_ops = {
+       .co_name                = "route/route",
+       .co_hdrsize             = sizeof(struct rtmsg),
+       .co_msgtypes            = {
+                                       { RTM_NEWROUTE, NL_ACT_NEW, "new" },
+                                       { RTM_DELROUTE, NL_ACT_DEL, "del" },
+                                       { RTM_GETROUTE, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_groups              = route_groups,
+       .co_request_update      = route_request_update,
+       .co_msg_parser          = route_msg_parser,
+       .co_obj_ops             = &route_obj_ops,
+};
+
+static void __init route_init(void)
+{
+       nl_cache_mngt_register(&rtnl_route_ops);
+}
+
+static void __exit route_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_route_ops);
+}
+
+/** @} */
diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
new file mode 100644 (file)
index 0000000..f2de523
--- /dev/null
@@ -0,0 +1,1315 @@
+/*
+ * lib/route/route_obj.c       Route Object
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup route
+ * @defgroup route_obj Route Object
+ *
+ * @par Attributes
+ * @code
+ * Name                                           Default
+ * -------------------------------------------------------------
+ * routing table                                  RT_TABLE_MAIN
+ * scope                                          RT_SCOPE_NOWHERE
+ * tos                                            0
+ * protocol                                       RTPROT_STATIC
+ * prio                                           0
+ * family                                         AF_UNSPEC
+ * type                                           RTN_UNICAST
+ * iif                                            NULL
+ * @endcode
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink/data.h>
+#include <netlink/hashtable.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/link.h>
+#include <netlink/route/nexthop.h>
+
+/** @cond SKIP */
+#define ROUTE_ATTR_FAMILY    0x000001
+#define ROUTE_ATTR_TOS       0x000002
+#define ROUTE_ATTR_TABLE     0x000004
+#define ROUTE_ATTR_PROTOCOL  0x000008
+#define ROUTE_ATTR_SCOPE     0x000010
+#define ROUTE_ATTR_TYPE      0x000020
+#define ROUTE_ATTR_FLAGS     0x000040
+#define ROUTE_ATTR_DST       0x000080
+#define ROUTE_ATTR_SRC       0x000100
+#define ROUTE_ATTR_IIF       0x000200
+#define ROUTE_ATTR_OIF       0x000400
+#define ROUTE_ATTR_GATEWAY   0x000800
+#define ROUTE_ATTR_PRIO      0x001000
+#define ROUTE_ATTR_PREF_SRC  0x002000
+#define ROUTE_ATTR_METRICS   0x004000
+#define ROUTE_ATTR_MULTIPATH 0x008000
+#define ROUTE_ATTR_REALMS    0x010000
+#define ROUTE_ATTR_CACHEINFO 0x020000
+/** @endcond */
+
+static void route_constructor(struct nl_object *c)
+{
+       struct rtnl_route *r = (struct rtnl_route *) c;
+
+       r->rt_family = AF_UNSPEC;
+       r->rt_scope = RT_SCOPE_NOWHERE;
+       r->rt_table = RT_TABLE_MAIN;
+       r->rt_protocol = RTPROT_STATIC;
+       r->rt_type = RTN_UNICAST;
+       r->rt_prio = 0;
+
+       nl_init_list_head(&r->rt_nexthops);
+}
+
+static void route_free_data(struct nl_object *c)
+{
+       struct rtnl_route *r = (struct rtnl_route *) c;
+       struct rtnl_nexthop *nh, *tmp;
+
+       if (r == NULL)
+               return;
+
+       nl_addr_put(r->rt_dst);
+       nl_addr_put(r->rt_src);
+       nl_addr_put(r->rt_pref_src);
+
+       nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
+               rtnl_route_remove_nexthop(r, nh);
+               rtnl_route_nh_free(nh);
+       }
+}
+
+static int route_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct rtnl_route *dst = (struct rtnl_route *) _dst;
+       struct rtnl_route *src = (struct rtnl_route *) _src;
+       struct rtnl_nexthop *nh, *new;
+
+       if (src->rt_dst)
+               if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
+                       return -NLE_NOMEM;
+
+       if (src->rt_src)
+               if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
+                       return -NLE_NOMEM;
+
+       if (src->rt_pref_src)
+               if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
+                       return -NLE_NOMEM;
+
+       /* Will be inc'ed again while adding the nexthops of the source */
+       dst->rt_nr_nh = 0;
+
+       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)
+                       return -NLE_NOMEM;
+
+               rtnl_route_add_nexthop(dst, new);
+       }
+
+       return 0;
+}
+
+static void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct rtnl_route *r = (struct rtnl_route *) a;
+       int cache = 0, flags;
+       char buf[64];
+
+       if (r->rt_flags & RTM_F_CLONED)
+               cache = 1;
+
+       nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf)));
+
+       if (cache)
+               nl_dump(p, "cache ");
+
+       if (!(r->ce_mask & ROUTE_ATTR_DST) ||
+           nl_addr_get_len(r->rt_dst) == 0)
+               nl_dump(p, "default ");
+       else
+               nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
+
+       if (r->ce_mask & ROUTE_ATTR_TABLE && !cache)
+               nl_dump(p, "table %s ",
+                       rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
+
+       if (r->ce_mask & ROUTE_ATTR_TYPE)
+               nl_dump(p, "type %s ",
+                       nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
+
+       if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0)
+               nl_dump(p, "tos %#x ", r->rt_tos);
+
+       if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+               struct rtnl_nexthop *nh;
+
+               nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+                       p->dp_ivar = NH_DUMP_FROM_ONELINE;
+                       rtnl_route_nh_dump(nh, p);
+               }
+       }
+
+       flags = r->rt_flags & ~(RTM_F_CLONED);
+       if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) {
+
+               nl_dump(p, "<");
+
+#define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
+               flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+               PRINT_FLAG(DEAD);
+               PRINT_FLAG(ONLINK);
+               PRINT_FLAG(PERVASIVE);
+#undef PRINT_FLAG
+
+#define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
+               flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+               PRINT_FLAG(NOTIFY);
+               PRINT_FLAG(EQUALIZE);
+               PRINT_FLAG(PREFIX);
+#undef PRINT_FLAG
+
+#define PRINT_FLAG(f) if (flags & RTCF_##f) { \
+               flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
+               PRINT_FLAG(NOTIFY);
+               PRINT_FLAG(REDIRECTED);
+               PRINT_FLAG(DOREDIRECT);
+               PRINT_FLAG(DIRECTSRC);
+               PRINT_FLAG(DNAT);
+               PRINT_FLAG(BROADCAST);
+               PRINT_FLAG(MULTICAST);
+               PRINT_FLAG(LOCAL);
+#undef PRINT_FLAG
+
+               nl_dump(p, ">");
+       }
+
+       nl_dump(p, "\n");
+}
+
+static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+       struct rtnl_route *r = (struct rtnl_route *) a;
+       struct nl_cache *link_cache;
+       char buf[256];
+       int i;
+
+       link_cache = nl_cache_mngt_require_safe("route/link");
+
+       route_dump_line(a, p);
+       nl_dump_line(p, "    ");
+
+       if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
+               nl_dump(p, "preferred-src %s ",
+                       nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
+
+       if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE)
+               nl_dump(p, "scope %s ",
+                       rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
+
+       if (r->ce_mask & ROUTE_ATTR_PRIO)
+               nl_dump(p, "priority %#x ", r->rt_prio);
+
+       if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
+               nl_dump(p, "protocol %s ",
+                       rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
+
+       if (r->ce_mask & ROUTE_ATTR_IIF) {
+               if (link_cache) {
+                       nl_dump(p, "iif %s ",
+                               rtnl_link_i2name(link_cache, r->rt_iif,
+                                                buf, sizeof(buf)));
+               } else
+                       nl_dump(p, "iif %d ", r->rt_iif);
+       }
+
+       if (r->ce_mask & ROUTE_ATTR_SRC)
+               nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
+
+       nl_dump(p, "\n");
+
+       if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+               struct rtnl_nexthop *nh;
+
+               nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+                       nl_dump_line(p, "    ");
+                       p->dp_ivar = NH_DUMP_FROM_DETAILS;
+                       rtnl_route_nh_dump(nh, p);
+                       nl_dump(p, "\n");
+               }
+       }
+
+       if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
+               nl_dump_line(p, "    cacheinfo error %d (%s)\n",
+                       r->rt_cacheinfo.rtci_error,
+                       strerror_r(-r->rt_cacheinfo.rtci_error, buf, sizeof(buf)));
+       }
+
+       if (r->ce_mask & ROUTE_ATTR_METRICS) {
+               nl_dump_line(p, "    metrics [");
+               for (i = 0; i < RTAX_MAX; i++)
+                       if (r->rt_metrics_mask & (1 << i))
+                               nl_dump(p, "%s %u ",
+                                       rtnl_route_metric2str(i+1,
+                                                             buf, sizeof(buf)),
+                                       r->rt_metrics[i]);
+               nl_dump(p, "]\n");
+       }
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_route *route = (struct rtnl_route *) obj;
+
+       route_dump_details(obj, p);
+
+       if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
+               struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
+
+               nl_dump_line(p, "    used %u refcnt %u last-use %us "
+                               "expires %us\n",
+                            ci->rtci_used, ci->rtci_clntref,
+                            ci->rtci_last_use / nl_get_user_hz(),
+                            ci->rtci_expires / nl_get_user_hz());
+       }
+}
+
+static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
+                         uint32_t table_sz)
+{
+       struct rtnl_route *route = (struct rtnl_route *) obj;
+       unsigned int rkey_sz;
+       struct nl_addr *addr = NULL;
+       struct route_hash_key {
+               uint8_t         rt_family;
+               uint8_t         rt_tos;
+               uint32_t        rt_table;
+               uint32_t        rt_prio;
+               char            rt_addr[0];
+       } __attribute__((packed)) *rkey;
+#ifdef NL_DEBUG
+       char buf[INET6_ADDRSTRLEN+5];
+#endif
+
+       if (route->rt_dst)
+               addr = route->rt_dst;
+
+       rkey_sz = sizeof(*rkey);
+       if (addr)
+               rkey_sz += nl_addr_get_len(addr);
+       rkey = calloc(1, rkey_sz);
+       if (!rkey) {
+               NL_DBG(2, "Warning: calloc failed for %d bytes...\n", rkey_sz);
+               *hashkey = 0;
+               return;
+       }
+       rkey->rt_family = route->rt_family;
+       rkey->rt_tos = route->rt_tos;
+       rkey->rt_table = route->rt_table;
+       rkey->rt_prio = route->rt_prio;
+       if (addr)
+               memcpy(rkey->rt_addr, nl_addr_get_binary_addr(addr),
+                       nl_addr_get_len(addr));
+
+       *hashkey = nl_hash(rkey, rkey_sz, 0) % table_sz;
+
+       NL_DBG(5, "route %p key (fam %d tos %d table %d addr %s) keysz %d "
+               "hash 0x%x\n", route, rkey->rt_family, rkey->rt_tos,
+               rkey->rt_table, nl_addr2str(addr, buf, sizeof(buf)),
+               rkey_sz, *hashkey);
+
+       free(rkey);
+
+       return;
+}
+
+static int route_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       struct rtnl_route *a = (struct rtnl_route *) _a;
+       struct rtnl_route *b = (struct rtnl_route *) _b;
+       struct rtnl_nexthop *nh_a, *nh_b;
+       int i, diff = 0, found;
+
+#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= ROUTE_DIFF(FAMILY,      a->rt_family != b->rt_family);
+       diff |= ROUTE_DIFF(TOS,         a->rt_tos != b->rt_tos);
+       diff |= ROUTE_DIFF(TABLE,       a->rt_table != b->rt_table);
+       diff |= ROUTE_DIFF(PROTOCOL,    a->rt_protocol != b->rt_protocol);
+       diff |= ROUTE_DIFF(SCOPE,       a->rt_scope != b->rt_scope);
+       diff |= ROUTE_DIFF(TYPE,        a->rt_type != b->rt_type);
+       diff |= ROUTE_DIFF(PRIO,        a->rt_prio != b->rt_prio);
+       diff |= ROUTE_DIFF(DST,         nl_addr_cmp(a->rt_dst, b->rt_dst));
+       diff |= ROUTE_DIFF(SRC,         nl_addr_cmp(a->rt_src, b->rt_src));
+       diff |= ROUTE_DIFF(IIF,         a->rt_iif != b->rt_iif);
+       diff |= ROUTE_DIFF(PREF_SRC,    nl_addr_cmp(a->rt_pref_src,
+                                                   b->rt_pref_src));
+
+       if (flags & LOOSE_COMPARISON) {
+               nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
+                       found = 0;
+                       nl_list_for_each_entry(nh_a, &a->rt_nexthops,
+                                              rtnh_list) {
+                               if (!rtnl_route_nh_compare(nh_a, nh_b,
+                                                       nh_b->ce_mask, 1)) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+
+                       if (!found)
+                               goto nh_mismatch;
+               }
+
+               for (i = 0; i < RTAX_MAX - 1; i++) {
+                       if (a->rt_metrics_mask & (1 << i) &&
+                           (!(b->rt_metrics_mask & (1 << i)) ||
+                            a->rt_metrics[i] != b->rt_metrics[i]))
+                               diff |= ROUTE_DIFF(METRICS, 1);
+               }
+
+               diff |= ROUTE_DIFF(FLAGS,
+                         (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
+       } else {
+               if (a->rt_nr_nh != b->rt_nr_nh)
+                       goto nh_mismatch;
+
+               /* search for a dup in each nh of a */
+               nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) {
+                       found = 0;
+                       nl_list_for_each_entry(nh_b, &b->rt_nexthops,
+                                              rtnh_list) {
+                               if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (!found)
+                               goto nh_mismatch;
+               }
+
+               /* search for a dup in each nh of b, covers case where a has
+                * dupes itself */
+               nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
+                       found = 0;
+                       nl_list_for_each_entry(nh_a, &a->rt_nexthops,
+                                              rtnh_list) {
+                               if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0)) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (!found)
+                               goto nh_mismatch;
+               }
+
+               for (i = 0; i < RTAX_MAX - 1; i++) {
+                       if ((a->rt_metrics_mask & (1 << i)) ^
+                           (b->rt_metrics_mask & (1 << i)))
+                               diff |= ROUTE_DIFF(METRICS, 1);
+                       else
+                               diff |= ROUTE_DIFF(METRICS,
+                                       a->rt_metrics[i] != b->rt_metrics[i]);
+               }
+
+               diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
+       }
+
+out:
+       return diff;
+
+nh_mismatch:
+       diff |= ROUTE_DIFF(MULTIPATH, 1);
+       goto out;
+
+#undef ROUTE_DIFF
+}
+
+static int route_update(struct nl_object *old_obj, struct nl_object *new_obj)
+{
+       struct rtnl_route *new_route = (struct rtnl_route *) new_obj;
+       struct rtnl_route *old_route = (struct rtnl_route *) old_obj;
+       struct rtnl_nexthop *new_nh;
+       int action = new_obj->ce_msgtype;
+#ifdef NL_DEBUG
+       char buf[INET6_ADDRSTRLEN+5];
+#endif
+
+       /*
+        * ipv6 ECMP route notifications from the kernel come as
+        * separate notifications, one for every nexthop. This update
+        * function collapses such route msgs into a single
+        * route with multiple nexthops. The resulting object looks
+        * similar to a ipv4 ECMP route
+        */
+       if (new_route->rt_family != AF_INET6 ||
+           new_route->rt_table == RT_TABLE_LOCAL)
+               return -NLE_OPNOTSUPP;
+
+       /*
+        * For routes that are already multipath,
+        * or dont have a nexthop dont do anything
+        */
+       if (rtnl_route_get_nnexthops(new_route) != 1)
+               return -NLE_OPNOTSUPP;
+
+       /*
+        * Get the only nexthop entry from the new route. For
+        * IPv6 we always get a route with a 0th NH
+        * filled or nothing at all
+        */
+       new_nh = rtnl_route_nexthop_n(new_route, 0);
+       if (!new_nh || !rtnl_route_nh_get_gateway(new_nh))
+               return -NLE_OPNOTSUPP;
+
+       switch(action) {
+       case RTM_NEWROUTE : {
+               struct rtnl_nexthop *cloned_nh;
+
+               /*
+                * Add the nexthop to old route
+                */
+               cloned_nh = rtnl_route_nh_clone(new_nh);
+               if (!cloned_nh)
+                       return -NLE_NOMEM;
+               rtnl_route_add_nexthop(old_route, cloned_nh);
+
+               NL_DBG(2, "Route obj %p updated. Added "
+                       "nexthop %p via %s\n", old_route, cloned_nh,
+                       nl_addr2str(cloned_nh->rtnh_gateway, buf,
+                                       sizeof(buf)));
+       }
+               break;
+       case RTM_DELROUTE : {
+               struct rtnl_nexthop *old_nh;
+
+               /*
+                * Only take care of nexthop deletes and not
+                * route deletes. So, if there is only one nexthop
+                * quite likely we did not update it. So dont do
+                * anything and return
+                */
+               if (rtnl_route_get_nnexthops(old_route) <= 1)
+                       return -NLE_OPNOTSUPP;
+
+               /*
+                * Find the next hop in old route and delete it
+                */
+               nl_list_for_each_entry(old_nh, &old_route->rt_nexthops,
+                       rtnh_list) {
+                       if (!rtnl_route_nh_compare(old_nh, new_nh, ~0, 0)) {
+
+                               rtnl_route_remove_nexthop(old_route, old_nh);
+
+                               NL_DBG(2, "Route obj %p updated. Removed "
+                                       "nexthop %p via %s\n", old_route,
+                                       old_nh,
+                                       nl_addr2str(old_nh->rtnh_gateway, buf,
+                                       sizeof(buf)));
+
+                               rtnl_route_nh_free(old_nh);
+                               break;
+                       }
+               }
+       }
+               break;
+       default:
+               NL_DBG(2, "Unknown action associated "
+                       "to object %p during route update\n", new_obj);
+               return -NLE_OPNOTSUPP;
+       }
+
+       return NLE_SUCCESS;
+}
+
+static const struct trans_tbl route_attrs[] = {
+       __ADD(ROUTE_ATTR_FAMILY, family)
+       __ADD(ROUTE_ATTR_TOS, tos)
+       __ADD(ROUTE_ATTR_TABLE, table)
+       __ADD(ROUTE_ATTR_PROTOCOL, protocol)
+       __ADD(ROUTE_ATTR_SCOPE, scope)
+       __ADD(ROUTE_ATTR_TYPE, type)
+       __ADD(ROUTE_ATTR_FLAGS, flags)
+       __ADD(ROUTE_ATTR_DST, dst)
+       __ADD(ROUTE_ATTR_SRC, src)
+       __ADD(ROUTE_ATTR_IIF, iif)
+       __ADD(ROUTE_ATTR_OIF, oif)
+       __ADD(ROUTE_ATTR_GATEWAY, gateway)
+       __ADD(ROUTE_ATTR_PRIO, prio)
+       __ADD(ROUTE_ATTR_PREF_SRC, pref_src)
+       __ADD(ROUTE_ATTR_METRICS, metrics)
+       __ADD(ROUTE_ATTR_MULTIPATH, multipath)
+       __ADD(ROUTE_ATTR_REALMS, realms)
+       __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
+};
+
+static char *route_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, route_attrs,
+                          ARRAY_SIZE(route_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_route *rtnl_route_alloc(void)
+{
+       return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
+}
+
+void rtnl_route_get(struct rtnl_route *route)
+{
+       nl_object_get((struct nl_object *) route);
+}
+
+void rtnl_route_put(struct rtnl_route *route)
+{
+       nl_object_put((struct nl_object *) route);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+void rtnl_route_set_table(struct rtnl_route *route, uint32_t table)
+{
+       route->rt_table = table;
+       route->ce_mask |= ROUTE_ATTR_TABLE;
+}
+
+uint32_t rtnl_route_get_table(struct rtnl_route *route)
+{
+       return route->rt_table;
+}
+
+void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope)
+{
+       route->rt_scope = scope;
+       route->ce_mask |= ROUTE_ATTR_SCOPE;
+}
+
+uint8_t rtnl_route_get_scope(struct rtnl_route *route)
+{
+       return route->rt_scope;
+}
+
+void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos)
+{
+       route->rt_tos = tos;
+       route->ce_mask |= ROUTE_ATTR_TOS;
+}
+
+uint8_t rtnl_route_get_tos(struct rtnl_route *route)
+{
+       return route->rt_tos;
+}
+
+void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol)
+{
+       route->rt_protocol = protocol;
+       route->ce_mask |= ROUTE_ATTR_PROTOCOL;
+}
+
+uint8_t rtnl_route_get_protocol(struct rtnl_route *route)
+{
+       return route->rt_protocol;
+}
+
+void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio)
+{
+       route->rt_prio = prio;
+       route->ce_mask |= ROUTE_ATTR_PRIO;
+}
+
+uint32_t rtnl_route_get_priority(struct rtnl_route *route)
+{
+       return route->rt_prio;
+}
+
+int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
+{
+       if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
+               return -NLE_AF_NOSUPPORT;
+
+       route->rt_family = family;
+       route->ce_mask |= ROUTE_ATTR_FAMILY;
+
+       return 0;
+}
+
+uint8_t rtnl_route_get_family(struct rtnl_route *route)
+{
+       return route->rt_family;
+}
+
+int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
+{
+       if (route->ce_mask & ROUTE_ATTR_FAMILY) {
+               if (addr->a_family != route->rt_family)
+                       return -NLE_AF_MISMATCH;
+       } else
+               route->rt_family = addr->a_family;
+
+       if (route->rt_dst)
+               nl_addr_put(route->rt_dst);
+
+       nl_addr_get(addr);
+       route->rt_dst = addr;
+       
+       route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
+
+       return 0;
+}
+
+struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
+{
+       return route->rt_dst;
+}
+
+int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
+{
+       if (addr->a_family == AF_INET)
+               return -NLE_SRCRT_NOSUPPORT;
+
+       if (route->ce_mask & ROUTE_ATTR_FAMILY) {
+               if (addr->a_family != route->rt_family)
+                       return -NLE_AF_MISMATCH;
+       } else
+               route->rt_family = addr->a_family;
+
+       if (route->rt_src)
+               nl_addr_put(route->rt_src);
+
+       nl_addr_get(addr);
+       route->rt_src = addr;
+       route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
+
+       return 0;
+}
+
+struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
+{
+       return route->rt_src;
+}
+
+int rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
+{
+       if (type > RTN_MAX)
+               return -NLE_RANGE;
+
+       route->rt_type = type;
+       route->ce_mask |= ROUTE_ATTR_TYPE;
+
+       return 0;
+}
+
+uint8_t rtnl_route_get_type(struct rtnl_route *route)
+{
+       return route->rt_type;
+}
+
+void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags)
+{
+       route->rt_flag_mask |= flags;
+       route->rt_flags |= flags;
+       route->ce_mask |= ROUTE_ATTR_FLAGS;
+}
+
+void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags)
+{
+       route->rt_flag_mask |= flags;
+       route->rt_flags &= ~flags;
+       route->ce_mask |= ROUTE_ATTR_FLAGS;
+}
+
+uint32_t rtnl_route_get_flags(struct rtnl_route *route)
+{
+       return route->rt_flags;
+}
+
+int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
+{
+       if (metric > RTAX_MAX || metric < 1)
+               return -NLE_RANGE;
+
+       route->rt_metrics[metric - 1] = value;
+
+       if (!(route->rt_metrics_mask & (1 << (metric - 1)))) {
+               route->rt_nmetrics++;
+               route->rt_metrics_mask |= (1 << (metric - 1));
+       }
+
+       route->ce_mask |= ROUTE_ATTR_METRICS;
+
+       return 0;
+}
+
+int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
+{
+       if (metric > RTAX_MAX || metric < 1)
+               return -NLE_RANGE;
+
+       if (route->rt_metrics_mask & (1 << (metric - 1))) {
+               route->rt_nmetrics--;
+               route->rt_metrics_mask &= ~(1 << (metric - 1));
+       }
+
+       return 0;
+}
+
+int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
+{
+       if (metric > RTAX_MAX || metric < 1)
+               return -NLE_RANGE;
+
+       if (!(route->rt_metrics_mask & (1 << (metric - 1))))
+               return -NLE_OBJ_NOTFOUND;
+
+       if (value)
+               *value = route->rt_metrics[metric - 1];
+
+       return 0;
+}
+
+int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
+{
+       if (route->ce_mask & ROUTE_ATTR_FAMILY) {
+               if (addr->a_family != route->rt_family)
+                       return -NLE_AF_MISMATCH;
+       } else
+               route->rt_family = addr->a_family;
+
+       if (route->rt_pref_src)
+               nl_addr_put(route->rt_pref_src);
+
+       nl_addr_get(addr);
+       route->rt_pref_src = addr;
+       route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
+
+       return 0;
+}
+
+struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
+{
+       return route->rt_pref_src;
+}
+
+void rtnl_route_set_iif(struct rtnl_route *route, int ifindex)
+{
+       route->rt_iif = ifindex;
+       route->ce_mask |= ROUTE_ATTR_IIF;
+}
+
+int rtnl_route_get_iif(struct rtnl_route *route)
+{
+       return route->rt_iif;
+}
+
+void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
+{
+       nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
+       route->rt_nr_nh++;
+       route->ce_mask |= ROUTE_ATTR_MULTIPATH;
+}
+
+void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
+{
+       if (route->ce_mask & ROUTE_ATTR_MULTIPATH) {
+               route->rt_nr_nh--;
+               nl_list_del(&nh->rtnh_list);
+       }
+}
+
+struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
+{
+       if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
+               return &route->rt_nexthops;
+
+       return NULL;
+}
+
+int rtnl_route_get_nnexthops(struct rtnl_route *route)
+{
+       if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
+               return route->rt_nr_nh;
+
+       return 0;
+}
+
+void rtnl_route_foreach_nexthop(struct rtnl_route *r,
+                                void (*cb)(struct rtnl_nexthop *, void *),
+                                void *arg)
+{
+       struct rtnl_nexthop *nh;
+    
+       if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
+               nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+                        cb(nh, arg);
+               }
+       }
+}
+
+struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
+{
+       struct rtnl_nexthop *nh;
+       uint32_t i;
+    
+       if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
+               i = 0;
+               nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
+                        if (i == n) return nh;
+                       i++;
+               }
+       }
+        return NULL;
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Guess scope of a route object.
+ * @arg route          Route object.
+ *
+ * Guesses the scope of a route object, based on the following rules:
+ * @code
+ *   1) Local route -> local scope
+ *   2) At least one nexthop not directly connected -> universe scope
+ *   3) All others -> link scope
+ * @endcode
+ *
+ * @return Scope value.
+ */
+int rtnl_route_guess_scope(struct rtnl_route *route)
+{
+       if (route->rt_type == RTN_LOCAL)
+               return RT_SCOPE_HOST;
+
+       if (!nl_list_empty(&route->rt_nexthops)) {
+               struct rtnl_nexthop *nh;
+
+               /*
+                * Use scope uiniverse if there is at least one nexthop which
+                * is not directly connected
+                */
+               nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
+                       if (nh->rtnh_gateway)
+                               return RT_SCOPE_UNIVERSE;
+               }
+       }
+
+       return RT_SCOPE_LINK;
+}
+
+/** @} */
+
+static struct nla_policy route_policy[RTA_MAX+1] = {
+       [RTA_IIF]       = { .type = NLA_U32 },
+       [RTA_OIF]       = { .type = NLA_U32 },
+       [RTA_PRIORITY]  = { .type = NLA_U32 },
+       [RTA_FLOW]      = { .type = NLA_U32 },
+       [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
+       [RTA_METRICS]   = { .type = NLA_NESTED },
+       [RTA_MULTIPATH] = { .type = NLA_NESTED },
+};
+
+static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
+{
+       struct rtnl_nexthop *nh = NULL;
+       struct rtnexthop *rtnh = nla_data(attr);
+       size_t tlen = nla_len(attr);
+       int err;
+
+       while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
+               nh = rtnl_route_nh_alloc();
+               if (!nh)
+                       return -NLE_NOMEM;
+
+               rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
+               rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
+               rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
+
+               if (rtnh->rtnh_len > sizeof(*rtnh)) {
+                       struct nlattr *ntb[RTA_MAX + 1];
+
+                       err = nla_parse(ntb, RTA_MAX, (struct nlattr *)
+                                       RTNH_DATA(rtnh),
+                                       rtnh->rtnh_len - sizeof(*rtnh),
+                                       route_policy);
+                       if (err < 0)
+                               goto errout;
+
+                       if (ntb[RTA_GATEWAY]) {
+                               struct nl_addr *addr;
+
+                               addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
+                                                         route->rt_family);
+                               if (!addr) {
+                                       err = -NLE_NOMEM;
+                                       goto errout;
+                               }
+
+                               rtnl_route_nh_set_gateway(nh, addr);
+                               nl_addr_put(addr);
+                       }
+
+                       if (ntb[RTA_FLOW]) {
+                               uint32_t realms;
+                               
+                               realms = nla_get_u32(ntb[RTA_FLOW]);
+                               rtnl_route_nh_set_realms(nh, realms);
+                       }
+               }
+
+               rtnl_route_add_nexthop(route, nh);
+               tlen -= RTNH_ALIGN(rtnh->rtnh_len);
+               rtnh = RTNH_NEXT(rtnh);
+       }
+
+       err = 0;
+errout:
+       if (err && nh)
+               rtnl_route_nh_free(nh);
+
+       return err;
+}
+
+int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
+{
+       struct rtmsg *rtm;
+       struct rtnl_route *route;
+       struct nlattr *tb[RTA_MAX + 1];
+       struct nl_addr *src = NULL, *dst = NULL, *addr;
+       struct rtnl_nexthop *old_nh = NULL;
+       int err, family;
+
+       route = rtnl_route_alloc();
+       if (!route) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       route->ce_msgtype = nlh->nlmsg_type;
+
+       err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
+       if (err < 0)
+               goto errout;
+
+       rtm = nlmsg_data(nlh);
+       route->rt_family = family = rtm->rtm_family;
+       route->rt_tos = rtm->rtm_tos;
+       route->rt_table = rtm->rtm_table;
+       route->rt_type = rtm->rtm_type;
+       route->rt_scope = rtm->rtm_scope;
+       route->rt_protocol = rtm->rtm_protocol;
+       route->rt_flags = rtm->rtm_flags;
+       route->rt_prio = 0;
+
+       route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
+                         ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
+                         ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
+                         ROUTE_ATTR_FLAGS | ROUTE_ATTR_PRIO;
+
+       if (tb[RTA_DST]) {
+               if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
+                       goto errout_nomem;
+       } else {
+               if (!(dst = nl_addr_alloc(0)))
+                       goto errout_nomem;
+               nl_addr_set_family(dst, rtm->rtm_family);
+       }
+
+       nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
+       err = rtnl_route_set_dst(route, dst);
+       if (err < 0)
+               goto errout;
+
+       nl_addr_put(dst);
+
+       if (tb[RTA_SRC]) {
+               if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
+                       goto errout_nomem;
+       } else if (rtm->rtm_src_len)
+               if (!(src = nl_addr_alloc(0)))
+                       goto errout_nomem;
+
+       if (src) {
+               nl_addr_set_prefixlen(src, rtm->rtm_src_len);
+               rtnl_route_set_src(route, src);
+               nl_addr_put(src);
+       }
+
+       if (tb[RTA_TABLE])
+               rtnl_route_set_table(route, nla_get_u32(tb[RTA_TABLE]));
+
+       if (tb[RTA_IIF])
+               rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF]));
+
+       if (tb[RTA_PRIORITY])
+               rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
+
+       if (tb[RTA_PREFSRC]) {
+               if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
+                       goto errout_nomem;
+               rtnl_route_set_pref_src(route, addr);
+               nl_addr_put(addr);
+       }
+
+       if (tb[RTA_METRICS]) {
+               struct nlattr *mtb[RTAX_MAX + 1];
+               int i;
+
+               err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
+               if (err < 0)
+                       goto errout;
+
+               for (i = 1; i <= RTAX_MAX; i++) {
+                       if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
+                               uint32_t m = nla_get_u32(mtb[i]);
+                               if (rtnl_route_set_metric(route, i, m) < 0)
+                                       goto errout;
+                       }
+               }
+       }
+
+       if (tb[RTA_MULTIPATH])
+               if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
+                       goto errout;
+
+       if (tb[RTA_CACHEINFO]) {
+               nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
+                          sizeof(route->rt_cacheinfo));
+               route->ce_mask |= ROUTE_ATTR_CACHEINFO;
+       }
+
+       if (tb[RTA_OIF]) {
+               if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+                       goto errout;
+
+               rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
+       }
+
+       if (tb[RTA_GATEWAY]) {
+               if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+                       goto errout;
+
+               if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
+                       goto errout_nomem;
+
+               rtnl_route_nh_set_gateway(old_nh, addr);
+               nl_addr_put(addr);
+       }
+
+       if (tb[RTA_FLOW]) {
+               if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+                       goto errout;
+
+               rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
+       }
+
+       if (old_nh) {
+               rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff);
+               if (route->rt_nr_nh == 0) {
+                       /* If no nexthops have been provided via RTA_MULTIPATH
+                        * we add it as regular nexthop to maintain backwards
+                        * compatibility */
+                       rtnl_route_add_nexthop(route, old_nh);
+               } else {
+                       /* Kernel supports new style nexthop configuration,
+                        * verify that it is a duplicate and discard nexthop. */
+                       struct rtnl_nexthop *first;
+
+                       first = nl_list_first_entry(&route->rt_nexthops,
+                                                   struct rtnl_nexthop,
+                                                   rtnh_list);
+                       if (!first)
+                               BUG();
+
+                       if (rtnl_route_nh_compare(old_nh, first,
+                                                 old_nh->ce_mask, 0)) {
+                               err = -NLE_INVAL;
+                               goto errout;
+                       }
+
+                       rtnl_route_nh_free(old_nh);
+               }
+       }
+
+       *result = route;
+       return 0;
+
+errout:
+       rtnl_route_put(route);
+       return err;
+
+errout_nomem:
+       err = -NLE_NOMEM;
+       goto errout;
+}
+
+int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
+{
+       int i;
+       struct nlattr *metrics;
+       struct rtmsg rtmsg = {
+               .rtm_family = route->rt_family,
+               .rtm_tos = route->rt_tos,
+               .rtm_table = route->rt_table,
+               .rtm_protocol = route->rt_protocol,
+               .rtm_scope = route->rt_scope,
+               .rtm_type = route->rt_type,
+               .rtm_flags = route->rt_flags,
+       };
+
+       if (route->rt_dst == NULL)
+               return -NLE_MISSING_ATTR;
+
+       rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
+       if (route->rt_src)
+               rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
+
+       if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE)
+               rtmsg.rtm_scope = rtnl_route_guess_scope(route);
+
+       if (rtnl_route_get_nnexthops(route) == 1) {
+               struct rtnl_nexthop *nh;
+               nh = rtnl_route_nexthop_n(route, 0);
+               rtmsg.rtm_flags |= nh->rtnh_flags;
+       }
+
+       if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       /* Additional table attribute replacing the 8bit in the header, was
+        * required to allow more than 256 tables. */
+       NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
+
+       if (nl_addr_get_len(route->rt_dst))
+               NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
+       NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
+
+       if (route->ce_mask & ROUTE_ATTR_SRC)
+               NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
+
+       if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
+               NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src);
+
+       if (route->ce_mask & ROUTE_ATTR_IIF)
+               NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
+
+       if (route->rt_nmetrics > 0) {
+               uint32_t val;
+
+               metrics = nla_nest_start(msg, RTA_METRICS);
+               if (metrics == NULL)
+                       goto nla_put_failure;
+
+               for (i = 1; i <= RTAX_MAX; i++) {
+                       if (!rtnl_route_get_metric(route, i, &val))
+                               NLA_PUT_U32(msg, i, val);
+               }
+
+               nla_nest_end(msg, metrics);
+       }
+
+       if (rtnl_route_get_nnexthops(route) == 1) {
+               struct rtnl_nexthop *nh;
+
+               nh = rtnl_route_nexthop_n(route, 0);
+               if (nh->rtnh_gateway)
+                       NLA_PUT_ADDR(msg, RTA_GATEWAY, nh->rtnh_gateway);
+               if (nh->rtnh_ifindex)
+                       NLA_PUT_U32(msg, RTA_OIF, nh->rtnh_ifindex);
+               if (nh->rtnh_realms)
+                       NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
+       } else if (rtnl_route_get_nnexthops(route) > 1) {
+               struct nlattr *multipath;
+               struct rtnl_nexthop *nh;
+
+               if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
+                       goto nla_put_failure;
+
+               nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
+                       struct rtnexthop *rtnh;
+
+                       rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
+                       if (!rtnh)
+                               goto nla_put_failure;
+
+                       rtnh->rtnh_flags = nh->rtnh_flags;
+                       rtnh->rtnh_hops = nh->rtnh_weight;
+                       rtnh->rtnh_ifindex = nh->rtnh_ifindex;
+
+                       if (nh->rtnh_gateway)
+                               NLA_PUT_ADDR(msg, RTA_GATEWAY,
+                                            nh->rtnh_gateway);
+
+                       if (nh->rtnh_realms)
+                               NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
+
+                       rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
+                                               (void *) rtnh;
+               }
+
+               nla_nest_end(msg, multipath);
+       }
+
+       return 0;
+
+nla_put_failure:
+       return -NLE_MSGSIZE;
+}
+
+/** @cond SKIP */
+struct nl_object_ops route_obj_ops = {
+       .oo_name                = "route/route",
+       .oo_size                = sizeof(struct rtnl_route),
+       .oo_constructor         = route_constructor,
+       .oo_free_data           = route_free_data,
+       .oo_clone               = route_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = route_dump_line,
+           [NL_DUMP_DETAILS]   = route_dump_details,
+           [NL_DUMP_STATS]     = route_dump_stats,
+       },
+       .oo_compare             = route_compare,
+       .oo_keygen              = route_keygen,
+       .oo_update              = route_update,
+       .oo_attrs2str           = route_attrs2str,
+       .oo_id_attrs            = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
+                                  ROUTE_ATTR_TABLE | ROUTE_ATTR_DST |
+                                  ROUTE_ATTR_PRIO),
+};
+/** @endcond */
+
+/** @} */
diff --git a/lib/route/route_utils.c b/lib/route/route_utils.c
new file mode 100644 (file)
index 0000000..a5b3966
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * lib/route/route_utils.c     Routing Utilities
+ *
+ *     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) 2003-2006 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup route
+ * @defgroup route_utils Utilities
+ * @brief Routing Utility Functions
+ *
+ *
+ * @par 1) Translating Routing Table Names
+ * @code
+ * // libnl is only aware of the de facto standard routing table names.
+ * // Additional name <-> identifier associations have to be read in via
+ * // a configuration file, f.e. /etc/iproute2/rt_tables
+ * err = rtnl_route_read_table_names("/etc/iproute2/rt_tables");
+ *
+ * // Translating a table name to its idenfier
+ * int table = rtnl_route_str2table("main");
+ *
+ * // ... and the other way around.
+ * char buf[32];
+ * printf("Name: %s\n",
+ *        rtnl_route_table2str(table, buf, sizeof(buf)));
+ * @endcode
+ *
+ *
+ *
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+       
+/**
+ * @name Routing Table Identifier Translations
+ * @{
+ */
+
+static NL_LIST_HEAD(table_names);
+
+static int add_routing_table_name(long id, const char *name)
+{
+       return __trans_list_add(id, name, &table_names);
+}
+
+static void __init init_routing_table_names(void)
+{
+       add_routing_table_name(RT_TABLE_UNSPEC, "unspec");
+       add_routing_table_name(RT_TABLE_COMPAT, "compat");
+       add_routing_table_name(RT_TABLE_DEFAULT, "default");
+       add_routing_table_name(RT_TABLE_MAIN, "main");
+       add_routing_table_name(RT_TABLE_LOCAL, "local");
+};
+
+static void __exit release_routing_table_names(void)
+{
+       __trans_list_clear(&table_names);
+}
+
+int rtnl_route_read_table_names(const char *path)
+{
+       __trans_list_clear(&table_names);
+
+       return __nl_read_num_str_file(path, &add_routing_table_name);
+}
+
+char *rtnl_route_table2str(int table, char *buf, size_t size)
+{
+       return __list_type2str(table, buf, size, &table_names);
+}
+
+int rtnl_route_str2table(const char *name)
+{
+       return __list_str2type(name, &table_names);
+}
+
+
+/** @} */
+
+/**
+ * @name Routing Protocol Translations
+ * @{
+ */
+
+static NL_LIST_HEAD(proto_names);
+
+static int add_proto_name(long id, const char *name)
+{
+       return __trans_list_add(id, name, &proto_names);
+}
+
+static void __init init_proto_names(void)
+{
+       add_proto_name(RTPROT_UNSPEC, "unspec");
+       add_proto_name(RTPROT_REDIRECT, "redirect");
+       add_proto_name(RTPROT_KERNEL, "kernel");
+       add_proto_name(RTPROT_BOOT, "boot");
+       add_proto_name(RTPROT_STATIC, "static");
+};
+
+static void __exit release_proto_names(void)
+{
+       __trans_list_clear(&proto_names);
+}
+
+int rtnl_route_read_protocol_names(const char *path)
+{
+       __trans_list_clear(&proto_names);
+
+       return __nl_read_num_str_file(path, &add_proto_name);
+}
+
+char *rtnl_route_proto2str(int proto, char *buf, size_t size)
+{
+       return __list_type2str(proto, buf, size, &proto_names);
+}
+
+int rtnl_route_str2proto(const char *name)
+{
+       return __list_str2type(name, &proto_names);
+}
+
+/** @} */
+
+/**
+ * @name Routing Metrices Translations
+ * @{
+ */
+
+static const struct trans_tbl route_metrices[] = {
+       __ADD(RTAX_UNSPEC, unspec)
+       __ADD(RTAX_LOCK, lock)
+       __ADD(RTAX_MTU, mtu)
+       __ADD(RTAX_WINDOW, window)
+       __ADD(RTAX_RTT, rtt)
+       __ADD(RTAX_RTTVAR, rttvar)
+       __ADD(RTAX_SSTHRESH, ssthresh)
+       __ADD(RTAX_CWND, cwnd)
+       __ADD(RTAX_ADVMSS, advmss)
+       __ADD(RTAX_REORDERING, reordering)
+       __ADD(RTAX_HOPLIMIT, hoplimit)
+       __ADD(RTAX_INITCWND, initcwnd)
+       __ADD(RTAX_FEATURES, features)
+};
+
+char *rtnl_route_metric2str(int metric, char *buf, size_t size)
+{
+       return __type2str(metric, buf, size, route_metrices,
+                         ARRAY_SIZE(route_metrices));
+}
+
+int rtnl_route_str2metric(const char *name)
+{
+       return __str2type(name, route_metrices, ARRAY_SIZE(route_metrices));
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/route/rtnl.c b/lib/route/rtnl.c
new file mode 100644 (file)
index 0000000..82397e9
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * lib/route/rtnl.c            Routing Netlink
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @defgroup rtnl Routing Library (libnl-route)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+
+/**
+ * @name Sending
+ * @{
+ */
+
+/**
+ * Send routing netlink request message
+ * @arg sk             Netlink socket.
+ * @arg type           Netlink message type.
+ * @arg family         Address family.
+ * @arg flags          Additional netlink message flags.
+ *
+ * Fills out a routing netlink request message and sends it out
+ * using nl_send_simple().
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags)
+{
+       struct rtgenmsg gmsg = {
+               .rtgen_family = family,
+       };
+
+       return nl_send_simple(sk, type, flags, &gmsg, sizeof(gmsg));
+}
+
+/** @} */
+
+/**
+ * @name Routing Type Translations
+ * @{
+ */
+
+static const struct trans_tbl rtntypes[] = {
+       __ADD(RTN_UNSPEC,unspec)
+       __ADD(RTN_UNICAST,unicast)
+       __ADD(RTN_LOCAL,local)
+       __ADD(RTN_BROADCAST,broadcast)
+       __ADD(RTN_ANYCAST,anycast)
+       __ADD(RTN_MULTICAST,multicast)
+       __ADD(RTN_BLACKHOLE,blackhole)
+       __ADD(RTN_UNREACHABLE,unreachable)
+       __ADD(RTN_PROHIBIT,prohibit)
+       __ADD(RTN_THROW,throw)
+       __ADD(RTN_NAT,nat)
+       __ADD(RTN_XRESOLVE,xresolve)
+};
+
+char *nl_rtntype2str(int type, char *buf, size_t size)
+{
+       return __type2str(type, buf, size, rtntypes, ARRAY_SIZE(rtntypes));
+}
+
+int nl_str2rtntype(const char *name)
+{
+       return __str2type(name, rtntypes, ARRAY_SIZE(rtntypes));
+}
+
+/** @} */
+
+/**
+ * @name Scope Translations
+ * @{
+ */
+
+static const struct trans_tbl scopes[] = {
+       __ADD(255,nowhere)
+       __ADD(254,host)
+       __ADD(253,link)
+       __ADD(200,site)
+       __ADD(0,global)
+};
+
+char *rtnl_scope2str(int scope, char *buf, size_t size)
+{
+       return __type2str(scope, buf, size, scopes, ARRAY_SIZE(scopes));
+}
+
+int rtnl_str2scope(const char *name)
+{
+       return __str2type(name, scopes, ARRAY_SIZE(scopes));
+}
+
+/** @} */
+
+/**
+ * @name Realms Translations
+ * @{
+ */
+
+char * rtnl_realms2str(uint32_t realms, char *buf, size_t len)
+{
+       int from = RTNL_REALM_FROM(realms);
+       int to = RTNL_REALM_TO(realms);
+
+       snprintf(buf, len, "%d/%d", from, to);
+
+       return buf;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/route/rule.c b/lib/route/rule.c
new file mode 100644 (file)
index 0000000..b2161a2
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * lib/route/rule.c          Routing Rules
+ *
+ *     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) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup rule Routing Rules
+ * @brief
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/rule.h>
+#include <inttypes.h>
+
+/** @cond SKIP */
+#define RULE_ATTR_FAMILY       0x0001
+#define RULE_ATTR_TABLE                0x0002
+#define RULE_ATTR_ACTION       0x0004
+#define RULE_ATTR_FLAGS                0x0008
+#define RULE_ATTR_IIFNAME      0x0010
+#define RULE_ATTR_OIFNAME      0x0020
+#define RULE_ATTR_PRIO         0x0040
+#define RULE_ATTR_MARK         0x0080
+#define RULE_ATTR_MASK         0x0100
+#define RULE_ATTR_GOTO         0x0200
+#define RULE_ATTR_SRC          0x0400
+#define RULE_ATTR_DST          0x0800
+#define RULE_ATTR_DSFIELD      0x1000
+#define RULE_ATTR_FLOW         0x2000
+
+static struct nl_cache_ops rtnl_rule_ops;
+static struct nl_object_ops rule_obj_ops;
+/** @endcond */
+
+static void rule_free_data(struct nl_object *c)
+{
+       struct rtnl_rule *rule = nl_object_priv(c);
+
+       if (!rule)
+               return;
+
+       nl_addr_put(rule->r_src);
+       nl_addr_put(rule->r_dst);
+}
+
+static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+       struct rtnl_rule *dst = nl_object_priv(_dst);
+       struct rtnl_rule *src = nl_object_priv(_src);
+
+       if (src->r_src)
+               if (!(dst->r_src = nl_addr_clone(src->r_src)))
+                       return -NLE_NOMEM;
+
+       if (src->r_dst)
+               if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
+                       return -NLE_NOMEM;
+
+       return 0;
+}
+
+static struct nla_policy rule_policy[FRA_MAX+1] = {
+       [FRA_TABLE]     = { .type = NLA_U32 },
+       [FRA_IIFNAME]   = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
+       [FRA_OIFNAME]   = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
+       [FRA_PRIORITY]  = { .type = NLA_U32 },
+       [FRA_FWMARK]    = { .type = NLA_U32 },
+       [FRA_FWMASK]    = { .type = NLA_U32 },
+       [FRA_GOTO]      = { .type = NLA_U32 },
+       [FRA_FLOW]      = { .type = NLA_U32 },
+};
+
+static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+                          struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+       struct rtnl_rule *rule;
+       struct fib_rule_hdr *frh;
+       struct nlattr *tb[FRA_MAX+1];
+       int err = 1, family;
+
+       rule = rtnl_rule_alloc();
+       if (!rule) {
+               err = -NLE_NOMEM;
+               goto errout;
+       }
+
+       rule->ce_msgtype = n->nlmsg_type;
+       frh = nlmsg_data(n);
+
+       err = nlmsg_parse(n, sizeof(*frh), tb, FRA_MAX, rule_policy);
+       if (err < 0)
+               goto errout;
+
+       rule->r_family = family = frh->family;
+       rule->r_table = frh->table;
+       rule->r_action = frh->action;
+       rule->r_flags = frh->flags;
+
+       rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION |
+                        RULE_ATTR_FLAGS);
+
+       /* ipv4 only */
+       if (frh->tos) {
+               rule->r_dsfield = frh->tos;
+               rule->ce_mask |= RULE_ATTR_DSFIELD;
+       }
+
+       if (tb[FRA_TABLE]) {
+               rule->r_table = nla_get_u32(tb[FRA_TABLE]);
+               rule->ce_mask |= RULE_ATTR_TABLE;
+       }
+
+       if (tb[FRA_IIFNAME]) {
+               nla_strlcpy(rule->r_iifname, tb[FRA_IIFNAME], IFNAMSIZ);
+               rule->ce_mask |= RULE_ATTR_IIFNAME;
+       }
+
+       if (tb[FRA_OIFNAME]) {
+               nla_strlcpy(rule->r_oifname, tb[FRA_OIFNAME], IFNAMSIZ);
+               rule->ce_mask |= RULE_ATTR_OIFNAME;
+       }
+
+       if (tb[FRA_PRIORITY]) {
+               rule->r_prio = nla_get_u32(tb[FRA_PRIORITY]);
+               rule->ce_mask |= RULE_ATTR_PRIO;
+       }
+
+       if (tb[FRA_FWMARK]) {
+               rule->r_mark = nla_get_u32(tb[FRA_FWMARK]);
+               rule->ce_mask |= RULE_ATTR_MARK;
+       }
+
+       if (tb[FRA_FWMASK]) {
+               rule->r_mask = nla_get_u32(tb[FRA_FWMASK]);
+               rule->ce_mask |= RULE_ATTR_MASK;
+       }
+
+       if (tb[FRA_GOTO]) {
+               rule->r_goto = nla_get_u32(tb[FRA_GOTO]);
+               rule->ce_mask |= RULE_ATTR_GOTO;
+       }
+
+       if (tb[FRA_SRC]) {
+               if (!(rule->r_src = nl_addr_alloc_attr(tb[FRA_SRC], family)))
+                       goto errout_enomem;
+
+               nl_addr_set_prefixlen(rule->r_src, frh->src_len);
+               rule->ce_mask |= RULE_ATTR_SRC;
+       }
+
+       if (tb[FRA_DST]) {
+               if (!(rule->r_dst = nl_addr_alloc_attr(tb[FRA_DST], family)))
+                       goto errout_enomem;
+               nl_addr_set_prefixlen(rule->r_dst, frh->dst_len);
+               rule->ce_mask |= RULE_ATTR_DST;
+       }
+
+       /* ipv4 only */
+       if (tb[FRA_FLOW]) {
+               rule->r_flow = nla_get_u32(tb[FRA_FLOW]);
+               rule->ce_mask |= RULE_ATTR_FLOW;
+       }
+
+       err = pp->pp_cb((struct nl_object *) rule, pp);
+errout:
+       rtnl_rule_put(rule);
+       return err;
+
+errout_enomem:
+       err = -NLE_NOMEM;
+       goto errout;
+}
+
+static int rule_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+       return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP);
+}
+
+static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
+{
+       struct rtnl_rule *r = (struct rtnl_rule *) o;
+       char buf[128];
+
+       nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0);
+       nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf)));
+
+       if (r->ce_mask & RULE_ATTR_SRC)
+               nl_dump(p, "from %s ",
+                       nl_addr2str(r->r_src, buf, sizeof(buf)));
+
+       if (r->ce_mask & RULE_ATTR_DST)
+               nl_dump(p, "to %s ",
+                       nl_addr2str(r->r_dst, buf, sizeof(buf)));
+
+       if (r->ce_mask & RULE_ATTR_DSFIELD)
+               nl_dump(p, "tos %u ", r->r_dsfield);
+
+       if (r->ce_mask & (RULE_ATTR_MARK | RULE_ATTR_MASK))
+               nl_dump(p, "mark %#x/%#x", r->r_mark, r->r_mask);
+
+       if (r->ce_mask & RULE_ATTR_IIFNAME)
+               nl_dump(p, "iif %s ", r->r_iifname);
+
+       if (r->ce_mask & RULE_ATTR_OIFNAME)
+               nl_dump(p, "oif %s ", r->r_oifname);
+
+       if (r->ce_mask & RULE_ATTR_TABLE)
+               nl_dump(p, "lookup %s ",
+                       rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
+
+       if (r->ce_mask & RULE_ATTR_FLOW)
+               nl_dump(p, "flow %s ",
+                       rtnl_realms2str(r->r_flow, buf, sizeof(buf)));
+
+       if (r->ce_mask & RULE_ATTR_GOTO)
+               nl_dump(p, "goto %u ", r->r_goto);
+
+       if (r->ce_mask & RULE_ATTR_ACTION)
+               nl_dump(p, "action %s",
+                       nl_rtntype2str(r->r_action, buf, sizeof(buf)));
+
+       nl_dump(p, "\n");
+}
+
+static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+       rule_dump_line(obj, p);
+}
+
+static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+       rule_dump_details(obj, p);
+}
+
+#define RULE_ATTR_FLAGS                0x0008
+
+static int rule_compare(struct nl_object *_a, struct nl_object *_b,
+                       uint32_t attrs, int flags)
+{
+       struct rtnl_rule *a = (struct rtnl_rule *) _a;
+       struct rtnl_rule *b = (struct rtnl_rule *) _b;
+       int diff = 0;
+
+#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= RULE_DIFF(FAMILY,       a->r_family != b->r_family);
+       diff |= RULE_DIFF(TABLE,        a->r_table != b->r_table);
+       diff |= RULE_DIFF(ACTION,       a->r_action != b->r_action);
+       diff |= RULE_DIFF(IIFNAME,      strcmp(a->r_iifname, b->r_iifname));
+       diff |= RULE_DIFF(OIFNAME,      strcmp(a->r_oifname, b->r_oifname));
+       diff |= RULE_DIFF(PRIO,         a->r_prio != b->r_prio);
+       diff |= RULE_DIFF(MARK,         a->r_mark != b->r_mark);
+       diff |= RULE_DIFF(MASK,         a->r_mask != b->r_mask);
+       diff |= RULE_DIFF(GOTO,         a->r_goto != b->r_goto);
+       diff |= RULE_DIFF(SRC,          nl_addr_cmp(a->r_src, b->r_src));
+       diff |= RULE_DIFF(DST,          nl_addr_cmp(a->r_dst, b->r_dst));
+       diff |= RULE_DIFF(DSFIELD,      a->r_dsfield != b->r_dsfield);
+       diff |= RULE_DIFF(FLOW,         a->r_flow != b->r_flow);
+       
+#undef RULE_DIFF
+
+       return diff;
+}
+
+static const struct trans_tbl rule_attrs[] = {
+       __ADD(RULE_ATTR_FAMILY, family)
+       __ADD(RULE_ATTR_TABLE, table)
+       __ADD(RULE_ATTR_ACTION, action)
+       __ADD(RULE_ATTR_IIFNAME, iifname)
+       __ADD(RULE_ATTR_OIFNAME, oifname)
+       __ADD(RULE_ATTR_PRIO, prio)
+       __ADD(RULE_ATTR_MARK, mark)
+       __ADD(RULE_ATTR_MASK, mask)
+       __ADD(RULE_ATTR_GOTO, goto)
+       __ADD(RULE_ATTR_SRC, src)
+       __ADD(RULE_ATTR_DST, dst)
+       __ADD(RULE_ATTR_DSFIELD, dsfield)
+       __ADD(RULE_ATTR_FLOW, flow)
+};
+
+static char *rule_attrs2str(int attrs, char *buf, size_t len)
+{
+       return __flags2str(attrs, buf, len, rule_attrs,
+                          ARRAY_SIZE(rule_attrs));
+}
+
+/**
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_rule *rtnl_rule_alloc(void)
+{
+       return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
+}
+
+void rtnl_rule_put(struct rtnl_rule *rule)
+{
+       nl_object_put((struct nl_object *) rule);
+}
+
+/** @} */
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+/**
+ * Build a rule cache including all rules currently configured in the kernel.
+ * @arg sock           Netlink socket.
+ * @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.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
+                         struct nl_cache **result)
+{
+       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;
+}
+
+/** @} */
+
+/**
+ * @name Rule Addition
+ * @{
+ */
+
+static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
+                         struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct fib_rule_hdr frh = {
+               .family = tmpl->r_family,
+               .table = tmpl->r_table,
+               .action = tmpl->r_action,
+               .flags = tmpl->r_flags,
+               .tos = tmpl->r_dsfield,
+       };
+
+       if (!(tmpl->ce_mask & RULE_ATTR_FAMILY))
+               return -NLE_MISSING_ATTR;
+
+       msg = nlmsg_alloc_simple(cmd, flags);
+       if (!msg)
+               return -NLE_NOMEM;
+
+       if (tmpl->ce_mask & RULE_ATTR_SRC) 
+               frh.src_len = nl_addr_get_prefixlen(tmpl->r_src);
+
+       if (tmpl->ce_mask & RULE_ATTR_DST)
+               frh.dst_len = nl_addr_get_prefixlen(tmpl->r_dst);
+
+       if (nlmsg_append(msg, &frh, sizeof(frh), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       /* Additional table attribute replacing the 8bit in the header, was
+        * required to allow more than 256 tables. */
+       NLA_PUT_U32(msg, FRA_TABLE, tmpl->r_table);
+
+       if (tmpl->ce_mask & RULE_ATTR_SRC)
+               NLA_PUT_ADDR(msg, FRA_SRC, tmpl->r_src);
+
+       if (tmpl->ce_mask & RULE_ATTR_DST) 
+               NLA_PUT_ADDR(msg, FRA_DST, tmpl->r_dst);
+
+       if (tmpl->ce_mask & RULE_ATTR_IIFNAME)
+               NLA_PUT_STRING(msg, FRA_IIFNAME, tmpl->r_iifname);
+
+       if (tmpl->ce_mask & RULE_ATTR_OIFNAME)
+               NLA_PUT_STRING(msg, FRA_OIFNAME, tmpl->r_oifname);
+
+       if (tmpl->ce_mask & RULE_ATTR_PRIO)
+               NLA_PUT_U32(msg, FRA_PRIORITY, tmpl->r_prio);
+
+       if (tmpl->ce_mask & RULE_ATTR_MARK)
+               NLA_PUT_U32(msg, FRA_FWMARK, tmpl->r_mark);
+
+       if (tmpl->ce_mask & RULE_ATTR_MASK)
+               NLA_PUT_U32(msg, FRA_FWMASK, tmpl->r_mask);
+
+       if (tmpl->ce_mask & RULE_ATTR_GOTO)
+               NLA_PUT_U32(msg, FRA_GOTO, tmpl->r_goto);
+
+       if (tmpl->ce_mask & RULE_ATTR_FLOW)
+               NLA_PUT_U32(msg, FRA_FLOW, tmpl->r_flow);
+
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -NLE_MSGSIZE;
+}
+
+/**
+ * Build netlink request message to add a new rule
+ * @arg tmpl           template with data of new rule
+ * @arg flags          additional netlink message flags
+ * @arg result         Result pointer
+ *
+ * Builds a new netlink message requesting a addition of a new
+ * rule. 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. \a tmpl must contain the attributes of the new
+ * address set via \c rtnl_rule_set_* functions.
+ * 
+ * @return 0 on success or a negative error code.
+ */
+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,
+                             result);
+}
+
+/**
+ * Add a new rule
+ * @arg sk             Netlink socket.
+ * @arg tmpl           template with requested changes
+ * @arg flags          additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_rule_build_add_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Rule Deletion
+ * @{
+ */
+
+/**
+ * Build a netlink request message to delete a rule
+ * @arg rule           rule to delete
+ * @arg flags          additional netlink message flags
+ * @arg result         Result pointer
+ *
+ * Builds a new netlink message requesting a deletion of a rule.
+ * 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. \a rule must point to an existing
+ * address.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
+                                  struct nl_msg **result)
+{
+       return build_rule_msg(rule, RTM_DELRULE, flags, result);
+}
+
+/**
+ * Delete a rule
+ * @arg sk             Netlink socket.
+ * @arg rule           rule to delete
+ * @arg flags          additional netlink message flags
+ *
+ * Builds a netlink message by calling rtnl_rule_build_delete_request(),
+ * sends the request to the kernel and waits for the next ACK to be
+ * received and thus blocks until the request has been fullfilled.
+ *
+ * @return 0 on sucess or a negative error if an error occured.
+ */
+int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
+{
+       struct nl_msg *msg;
+       int err;
+       
+       if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
+               return err;
+
+       err = nl_send_auto_complete(sk, msg);
+       nlmsg_free(msg);
+       if (err < 0)
+               return err;
+
+       return wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
+{
+       rule->r_family = family;
+       rule->ce_mask |= RULE_ATTR_FAMILY;
+}
+
+int rtnl_rule_get_family(struct rtnl_rule *rule)
+{
+       if (rule->ce_mask & RULE_ATTR_FAMILY)
+               return rule->r_family;
+       else
+               return AF_UNSPEC;
+}
+
+void rtnl_rule_set_prio(struct rtnl_rule *rule, uint32_t prio)
+{
+       rule->r_prio = prio;
+       rule->ce_mask |= RULE_ATTR_PRIO;
+}
+
+uint32_t rtnl_rule_get_prio(struct rtnl_rule *rule)
+{
+       return rule->r_prio;
+}
+
+void rtnl_rule_set_mark(struct rtnl_rule *rule, uint32_t mark)
+{
+       rule->r_mark = mark;
+       rule->ce_mask |= RULE_ATTR_MARK;
+}
+
+uint32_t rtnl_rule_get_mark(struct rtnl_rule *rule)
+{
+       return rule->r_mark;
+}
+
+void rtnl_rule_set_mask(struct rtnl_rule *rule, uint32_t mask)
+{
+       rule->r_mask = mask;
+       rule->ce_mask |= RULE_ATTR_MASK;
+}
+
+uint32_t rtnl_rule_get_mask(struct rtnl_rule *rule)
+{
+       return rule->r_mask;
+}
+
+void rtnl_rule_set_table(struct rtnl_rule *rule, uint32_t table)
+{
+       rule->r_table = table;
+       rule->ce_mask |= RULE_ATTR_TABLE;
+}
+
+uint32_t rtnl_rule_get_table(struct rtnl_rule *rule)
+{
+       return rule->r_table;
+}
+
+void rtnl_rule_set_dsfield(struct rtnl_rule *rule, uint8_t dsfield)
+{
+       rule->r_dsfield = dsfield;
+       rule->ce_mask |= RULE_ATTR_DSFIELD;
+}
+
+uint8_t rtnl_rule_get_dsfield(struct rtnl_rule *rule)
+{
+       return rule->r_dsfield;
+}
+
+static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
+                               struct nl_addr *new, int flag)
+{
+       if (rule->ce_mask & RULE_ATTR_FAMILY) {
+               if (new->a_family != rule->r_family)
+                       return -NLE_AF_MISMATCH;
+       } else
+               rule->r_family = new->a_family;
+
+       if (*pos)
+               nl_addr_put(*pos);
+
+       nl_addr_get(new);
+       *pos = new;
+
+       rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
+
+       return 0;
+}
+
+int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
+{
+       return __assign_addr(rule, &rule->r_src, src, RULE_ATTR_SRC);
+}
+
+struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
+{
+       return rule->r_src;
+}
+
+int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
+{
+       return __assign_addr(rule, &rule->r_dst, dst, RULE_ATTR_DST);
+}
+
+struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
+{
+       return rule->r_dst;
+}
+
+int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
+{
+       if (strlen(dev) > IFNAMSIZ-1)
+               return -NLE_RANGE;
+
+       strcpy(rule->r_iifname, dev);
+       rule->ce_mask |= RULE_ATTR_IIFNAME;
+       return 0;
+}
+
+char *rtnl_rule_get_iif(struct rtnl_rule *rule)
+{
+       if (rule->ce_mask & RULE_ATTR_IIFNAME)
+               return rule->r_iifname;
+       else
+               return NULL;
+}
+
+int rtnl_rule_set_oif(struct rtnl_rule *rule, const char *dev)
+{
+       if (strlen(dev) > IFNAMSIZ-1)
+               return -NLE_RANGE;
+
+       strcpy(rule->r_oifname, dev);
+       rule->ce_mask |= RULE_ATTR_OIFNAME;
+       return 0;
+}
+
+char *rtnl_rule_get_oif(struct rtnl_rule *rule)
+{
+       if (rule->ce_mask & RULE_ATTR_OIFNAME)
+               return rule->r_oifname;
+       else
+               return NULL;
+}
+
+void rtnl_rule_set_action(struct rtnl_rule *rule, uint8_t action)
+{
+       rule->r_action = action;
+       rule->ce_mask |= RULE_ATTR_ACTION;
+}
+
+uint8_t rtnl_rule_get_action(struct rtnl_rule *rule)
+{
+       return rule->r_action;
+}
+
+void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
+{
+       rule->r_flow = realms;
+       rule->ce_mask |= RULE_ATTR_FLOW;
+}
+
+uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
+{
+       return rule->r_flow;
+}
+
+void rtnl_rule_set_goto(struct rtnl_rule *rule, uint32_t ref)
+{
+       rule->r_goto = ref;
+       rule->ce_mask |= RULE_ATTR_GOTO;
+}
+
+uint32_t rtnl_rule_get_goto(struct rtnl_rule *rule)
+{
+       return rule->r_goto;
+}
+
+/** @} */
+
+static struct nl_object_ops rule_obj_ops = {
+       .oo_name                = "route/rule",
+       .oo_size                = sizeof(struct rtnl_rule),
+       .oo_free_data           = rule_free_data,
+       .oo_clone               = rule_clone,
+       .oo_dump = {
+           [NL_DUMP_LINE]      = rule_dump_line,
+           [NL_DUMP_DETAILS]   = rule_dump_details,
+           [NL_DUMP_STATS]     = rule_dump_stats,
+       },
+       .oo_compare             = rule_compare,
+       .oo_attrs2str           = rule_attrs2str,
+       .oo_id_attrs            = ~0,
+};
+
+static struct nl_cache_ops rtnl_rule_ops = {
+       .co_name                = "route/rule",
+       .co_hdrsize             = sizeof(struct fib_rule_hdr),
+       .co_msgtypes            = {
+                                       { RTM_NEWRULE, NL_ACT_NEW, "new" },
+                                       { RTM_DELRULE, NL_ACT_DEL, "del" },
+                                       { RTM_GETRULE, NL_ACT_GET, "get" },
+                                       END_OF_MSGTYPES_LIST,
+                                 },
+       .co_protocol            = NETLINK_ROUTE,
+       .co_request_update      = rule_request_update,
+       .co_msg_parser          = rule_msg_parser,
+       .co_obj_ops             = &rule_obj_ops,
+};
+
+static void __init rule_init(void)
+{
+       nl_cache_mngt_register(&rtnl_rule_ops);
+}
+
+static void __exit rule_exit(void)
+{
+       nl_cache_mngt_unregister(&rtnl_rule_ops);
+}
+
+/** @} */
diff --git a/lib/route/tc.c b/lib/route/tc.c
new file mode 100644 (file)
index 0000000..29954fd
--- /dev/null
@@ -0,0 +1,1072 @@
+/*
+ * lib/route/tc.c              Traffic Control
+ *
+ *     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) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup tc Traffic Control
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/tc.h>
+#include <netlink-private/route/tc-api.h>
+
+/** @cond SKIP */
+
+static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX];
+static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX];
+
+static struct nla_policy tc_policy[TCA_MAX+1] = {
+       [TCA_KIND]      = { .type = NLA_STRING,
+                           .maxlen = TCKINDSIZ },
+       [TCA_STATS]     = { .minlen = sizeof(struct tc_stats) },
+       [TCA_STATS2]    = { .type = NLA_NESTED },
+};
+
+int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g,
+             struct nla_policy *policy)
+{
+       
+       if (g->ce_mask & TCA_ATTR_OPTS)
+               return nla_parse(tb, maxattr,
+                                (struct nlattr *) g->tc_opts->d_data,
+                                g->tc_opts->d_size, policy);
+       else {
+               /* Ugly but tb[] must be in a defined state even if no
+                * attributes can be found. */
+               memset(tb, 0, sizeof(struct nlattr *) * (maxattr + 1));
+               return 0;
+       }
+}
+
+static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = {
+       [TCA_STATS_BASIC]    = { .minlen = sizeof(struct gnet_stats_basic) },
+       [TCA_STATS_RATE_EST] = { .minlen = sizeof(struct gnet_stats_rate_est) },
+       [TCA_STATS_QUEUE]    = { .minlen = sizeof(struct gnet_stats_queue) },
+};
+
+int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc)
+{
+       struct nl_cache *link_cache;
+       struct rtnl_tc_ops *ops;
+       struct nlattr *tb[TCA_MAX + 1];
+       char kind[TCKINDSIZ];
+       struct tcmsg *tm;
+       int err;
+
+       tc->ce_msgtype = n->nlmsg_type;
+
+       err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy);
+       if (err < 0)
+               return err;
+
+       if (tb[TCA_KIND] == NULL)
+               return -NLE_MISSING_ATTR;
+
+       nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind));
+       rtnl_tc_set_kind(tc, kind);
+
+       tm = nlmsg_data(n);
+       tc->tc_family  = tm->tcm_family;
+       tc->tc_ifindex = tm->tcm_ifindex;
+       tc->tc_handle  = tm->tcm_handle;
+       tc->tc_parent  = tm->tcm_parent;
+       tc->tc_info    = tm->tcm_info;
+
+       tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE|
+                       TCA_ATTR_PARENT | TCA_ATTR_INFO);
+
+       if (tb[TCA_OPTIONS]) {
+               tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
+               if (!tc->tc_opts)
+                       return -NLE_NOMEM;
+               tc->ce_mask |= TCA_ATTR_OPTS;
+       }
+
+       if (tb[TCA_STATS2]) {
+               struct nlattr *tbs[TCA_STATS_MAX + 1];
+
+               err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2],
+                                      tc_stats2_policy);
+               if (err < 0)
+                       return err;
+
+               if (tbs[TCA_STATS_BASIC]) {
+                       struct gnet_stats_basic *bs;
+                       
+                       bs = nla_data(tbs[TCA_STATS_BASIC]);
+                       tc->tc_stats[RTNL_TC_BYTES]     = bs->bytes;
+                       tc->tc_stats[RTNL_TC_PACKETS]   = bs->packets;
+               }
+
+               if (tbs[TCA_STATS_RATE_EST]) {
+                       struct gnet_stats_rate_est *re;
+
+                       re = nla_data(tbs[TCA_STATS_RATE_EST]);
+                       tc->tc_stats[RTNL_TC_RATE_BPS]  = re->bps;
+                       tc->tc_stats[RTNL_TC_RATE_PPS]  = re->pps;
+               }
+               
+               if (tbs[TCA_STATS_QUEUE]) {
+                       struct gnet_stats_queue *q;
+
+                       q = nla_data(tbs[TCA_STATS_QUEUE]);
+                       tc->tc_stats[RTNL_TC_QLEN]      = q->qlen;
+                       tc->tc_stats[RTNL_TC_BACKLOG]   = q->backlog;
+                       tc->tc_stats[RTNL_TC_DROPS]     = q->drops;
+                       tc->tc_stats[RTNL_TC_REQUEUES]  = q->requeues;
+                       tc->tc_stats[RTNL_TC_OVERLIMITS]        = q->overlimits;
+               }
+
+               tc->ce_mask |= TCA_ATTR_STATS;
+               
+               if (tbs[TCA_STATS_APP]) {
+                       tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
+                       if (tc->tc_xstats == NULL)
+                               return -NLE_NOMEM;
+               } else
+                       goto compat_xstats;
+       } else {
+               if (tb[TCA_STATS]) {
+                       struct tc_stats *st = nla_data(tb[TCA_STATS]);
+
+                       tc->tc_stats[RTNL_TC_BYTES]     = st->bytes;
+                       tc->tc_stats[RTNL_TC_PACKETS]   = st->packets;
+                       tc->tc_stats[RTNL_TC_RATE_BPS]  = st->bps;
+                       tc->tc_stats[RTNL_TC_RATE_PPS]  = st->pps;
+                       tc->tc_stats[RTNL_TC_QLEN]      = st->qlen;
+                       tc->tc_stats[RTNL_TC_BACKLOG]   = st->backlog;
+                       tc->tc_stats[RTNL_TC_DROPS]     = st->drops;
+                       tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits;
+
+                       tc->ce_mask |= TCA_ATTR_STATS;
+               }
+
+compat_xstats:
+               if (tb[TCA_XSTATS]) {
+                       tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
+                       if (tc->tc_xstats == NULL)
+                               return -NLE_NOMEM;
+                       tc->ce_mask |= TCA_ATTR_XSTATS;
+               }
+       }
+
+       ops = rtnl_tc_get_ops(tc);
+       if (ops && ops->to_msg_parser) {
+               void *data = rtnl_tc_data(tc);
+
+               if (!data)
+                       return -NLE_NOMEM;
+
+               err = ops->to_msg_parser(tc, data);
+               if (err < 0)
+                       return err;
+       }
+
+       if ((link_cache = __nl_cache_mngt_require("route/link"))) {
+               struct rtnl_link *link;
+
+               if ((link = rtnl_link_get(link_cache, tc->tc_ifindex))) {
+                       rtnl_tc_set_link(tc, link);
+
+                       /* rtnl_tc_set_link incs refcnt */
+                       rtnl_link_put(link);
+               }
+       }
+
+       return 0;
+}
+
+int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags,
+                     struct nl_msg **result)
+{
+       struct nl_msg *msg;
+       struct rtnl_tc_ops *ops;
+       struct tcmsg tchdr = {
+               .tcm_family = AF_UNSPEC,
+               .tcm_ifindex = tc->tc_ifindex,
+               .tcm_handle = tc->tc_handle,
+               .tcm_parent = tc->tc_parent,
+       };
+       int err = -NLE_MSGSIZE;
+
+       msg = nlmsg_alloc_simple(type, flags);
+       if (!msg)
+               return -NLE_NOMEM;
+
+       if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
+               goto nla_put_failure;
+
+       if (tc->ce_mask & TCA_ATTR_KIND)
+           NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind);
+
+       ops = rtnl_tc_get_ops(tc);
+       if (ops && ops->to_msg_fill) {
+               struct nlattr *opts;
+               void *data = rtnl_tc_data(tc);
+
+               if (!(opts = nla_nest_start(msg, TCA_OPTIONS)))
+                       goto nla_put_failure;
+
+               if ((err = ops->to_msg_fill(tc, data, msg)) < 0)
+                       goto nla_put_failure;
+
+               nla_nest_end(msg, opts);
+       }
+
+       *result = msg;
+       return 0;
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return err;
+}
+
+void tca_set_kind(struct rtnl_tc *t, const char *kind)
+{
+       strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1);
+       t->ce_mask |= TCA_ATTR_KIND;
+}
+
+
+/** @endcond */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+/**
+ * Set interface index of traffic control object
+ * @arg tc             traffic control object
+ * @arg ifindex                interface index.
+ *
+ * Sets the interface index of a traffic control object. The interface
+ * index defines the network device which this tc object is attached to.
+ * This function will overwrite any network device assigned with previous
+ * calls to rtnl_tc_set_ifindex() or rtnl_tc_set_link().
+ */
+void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex)
+{
+       /* Obsolete possible old link reference */
+       rtnl_link_put(tc->tc_link);
+       tc->tc_link = NULL;
+       tc->ce_mask &= ~TCA_ATTR_LINK;
+
+       tc->tc_ifindex = ifindex;
+       tc->ce_mask |= TCA_ATTR_IFINDEX;
+}
+
+/**
+ * Return interface index of traffic control object
+ * @arg tc             traffic control object
+ */
+int rtnl_tc_get_ifindex(struct rtnl_tc *tc)
+{
+       return tc->tc_ifindex;
+}
+
+/**
+ * Set link of traffic control object
+ * @arg tc             traffic control object
+ * @arg link           link object
+ *
+ * Sets the link of a traffic control object. This function serves
+ * the same purpose as rtnl_tc_set_ifindex() but due to the continued
+ * allowed access to the link object it gives it the possibility to
+ * retrieve sane default values for the the MTU and the linktype.
+ * Always prefer this function over rtnl_tc_set_ifindex() if you can
+ * spare to have an additional link object around.
+ */
+void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
+{
+       rtnl_link_put(tc->tc_link);
+
+       if (!link)
+               return;
+
+       nl_object_get(OBJ_CAST(link));
+       tc->tc_link = link;
+       tc->tc_ifindex = link->l_index;
+       tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX;
+}
+
+/**
+ * Get link of traffic control object
+ * @arg tc             traffic control object
+ *
+ * Returns the link of a traffic control object. The link is only
+ * returned if it has been set before via rtnl_tc_set_link() or
+ * if a link cache was available while parsing the tc object. This
+ * function may still return NULL even if an ifindex is assigned to
+ * the tc object. It will _not_ look up the link by itself.
+ *
+ * @note The returned link will have its reference counter incremented.
+ *       It is in the responsibility of the caller to return the
+ *       reference.
+ *
+ * @return link object or NULL if not set.
+ */
+struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *tc)
+{
+       if (tc->tc_link) {
+               nl_object_get(OBJ_CAST(tc->tc_link));
+               return tc->tc_link;
+       }
+
+       return NULL;
+}
+
+/**
+ * Set the Maximum Transmission Unit (MTU) of traffic control object
+ * @arg tc             traffic control object
+ * @arg mtu            largest packet size expected
+ *
+ * Sets the MTU of a traffic control object. Not all traffic control
+ * objects will make use of this but it helps while calculating rate
+ * tables. This value is typically derived directly from the link
+ * the tc object is attached to if the link has been assigned via
+ * rtnl_tc_set_link(). It is usually not necessary to set the MTU
+ * manually, this function is provided to allow overwriting the derived
+ * value.
+ */
+void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu)
+{
+       tc->tc_mtu = mtu;
+       tc->ce_mask |= TCA_ATTR_MTU;
+}
+
+/**
+ * Return the MTU of traffic control object
+ * @arg tc             traffic control object
+ *
+ * Returns the MTU of a traffic control object which has been set via:
+ * -# User specified value set via rtnl_tc_set_mtu()
+ * -# Dervied from link set via rtnl_tc_set_link()
+ * -# Fall back to default: ethernet = 1500
+ */
+uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc)
+{
+       if (tc->ce_mask & TCA_ATTR_MTU)
+               return tc->tc_mtu;
+       else if (tc->ce_mask & TCA_ATTR_LINK)
+               return tc->tc_link->l_mtu;
+       else
+               return 1500; /* default to ethernet */
+}
+
+/**
+ * Set the Minimum Packet Unit (MPU) of a traffic control object
+ * @arg tc             traffic control object
+ * @arg mpu            minimum packet size expected
+ *
+ * Sets the MPU of a traffic contorl object. It specifies the minimum
+ * packet size to ever hit this traffic control object. Not all traffic
+ * control objects will make use of this but it helps while calculating
+ * rate tables.
+ */
+void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
+{
+       tc->tc_mpu = mpu;
+       tc->ce_mask |= TCA_ATTR_MPU;
+}
+
+/**
+ * Return the Minimum Packet Unit (MPU) of a traffic control object
+ * @arg tc             traffic control object
+ *
+ * @return The MPU previously set via rtnl_tc_set_mpu() or 0.
+ */
+uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc)
+{
+       return tc->tc_mpu;
+}
+
+/**
+ * Set per packet overhead of a traffic control object
+ * @arg tc             traffic control object
+ * @arg overhead       overhead per packet in bytes
+ *
+ * Sets the per packet overhead in bytes occuring on the link not seen
+ * by the kernel. This value can be used to correct size calculations
+ * if the packet size on the wire does not match the packet sizes seen
+ * in the network stack. Not all traffic control objects will make use
+ * this but it helps while calculating accurate packet sizes in the
+ * kernel.
+ */
+void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead)
+{
+       tc->tc_overhead = overhead;
+       tc->ce_mask |= TCA_ATTR_OVERHEAD;
+}
+
+/**
+ * Return per packet overhead of a traffic control object
+ * @arg tc             traffic control object
+ *
+ * @return The overhead previously set by rtnl_tc_set_overhead() or 0.
+ */
+uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc)
+{
+       return tc->tc_overhead;
+}
+
+/**
+ * Set the linktype of a traffic control object
+ * @arg tc             traffic control object
+ * @arg type           type of link (e.g. ARPHRD_ATM, ARPHRD_ETHER)
+ *
+ * Overwrites the type of link this traffic control object is attached to.
+ * This value is typically derived from the link this tc object is attached
+ * if the link has been assigned via rtnl_tc_set_link(). It is usually not
+ * necessary to set the linktype manually. This function is provided to
+ * allow overwriting the linktype.
+ */
+void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type)
+{
+       tc->tc_linktype = type;
+       tc->ce_mask |= TCA_ATTR_LINKTYPE;
+}
+
+/**
+ * Return the linktype of a traffic control object
+ * @arg tc             traffic control object
+ *
+ * Returns the linktype of the link the traffic control object is attached to:
+ * -# User specified value via rtnl_tc_set_linktype()
+ * -# Value derived from link set via rtnl_tc_set_link()
+ * -# Default fall-back: ARPHRD_ETHER
+ */
+uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc)
+{
+       if (tc->ce_mask & TCA_ATTR_LINKTYPE)
+               return tc->tc_linktype;
+       else if (tc->ce_mask & TCA_ATTR_LINK)
+               return tc->tc_link->l_arptype;
+       else
+               return ARPHRD_ETHER; /* default to ethernet */
+}
+
+/**
+ * Set identifier of traffic control object
+ * @arg tc             traffic control object
+ * @arg id             unique identifier
+ */
+void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
+{
+       tc->tc_handle = id;
+       tc->ce_mask |= TCA_ATTR_HANDLE;
+}
+
+/**
+ * Return identifier of a traffic control object
+ * @arg tc             traffic control object
+ */
+uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc)
+{
+       return tc->tc_handle;
+}
+
+/**
+ * Set the parent identifier of a traffic control object
+ * @arg tc             traffic control object
+ * @arg parent         identifier of parent traffif control object
+ *
+ */
+void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent)
+{
+       tc->tc_parent = parent;
+       tc->ce_mask |= TCA_ATTR_PARENT;
+}
+
+/**
+ * Return parent identifier of a traffic control object
+ * @arg tc             traffic control object
+ */
+uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc)
+{
+       return tc->tc_parent;
+}
+
+/**
+ * Define the type of traffic control object
+ * @arg tc             traffic control object
+ * @arg kind           name of the tc object type
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
+{
+       if (tc->ce_mask & TCA_ATTR_KIND)
+               return -NLE_EXIST;
+
+       strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind) - 1);
+       tc->ce_mask |= TCA_ATTR_KIND;
+
+       /* Force allocation of data */
+       rtnl_tc_data(tc);
+
+       return 0;
+}
+
+/**
+ * Return kind of traffic control object
+ * @arg tc             traffic control object
+ *
+ * @return Kind of traffic control object or NULL if not set.
+ */
+char *rtnl_tc_get_kind(struct rtnl_tc *tc)
+{
+       if (tc->ce_mask & TCA_ATTR_KIND)
+               return tc->tc_kind;
+       else
+               return NULL;
+}
+
+/**
+ * Return value of a statistical counter of a traffic control object
+ * @arg tc             traffic control object
+ * @arg id             identifier of statistical counter
+ *
+ * @return Value of requested statistic counter or 0.
+ */
+uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id)
+{
+       if (id < 0 || id > RTNL_TC_STATS_MAX)
+               return 0;
+
+       return tc->tc_stats[id];
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Calculate time required to transmit buffer at a specific rate
+ * @arg bufsize                Size of buffer to be transmited in bytes.
+ * @arg rate           Transmit rate in bytes per second.
+ *
+ * Calculates the number of micro seconds required to transmit a
+ * specific buffer at a specific transmit rate.
+ *
+ * @f[
+ *   txtime=\frac{bufsize}{rate}10^6
+ * @f]
+ * 
+ * @return Required transmit time in micro seconds.
+ */
+int rtnl_tc_calc_txtime(int bufsize, int rate)
+{
+       double tx_time_secs;
+       
+       tx_time_secs = (double) bufsize / (double) rate;
+
+       return tx_time_secs * 1000000.;
+}
+
+/**
+ * Calculate buffer size able to transmit in a specific time and rate.
+ * @arg txtime         Available transmit time in micro seconds.
+ * @arg rate           Transmit rate in bytes per second.
+ *
+ * Calculates the size of the buffer that can be transmitted in a
+ * specific time period at a specific transmit rate.
+ *
+ * @f[
+ *   bufsize=\frac{{txtime} \times {rate}}{10^6}
+ * @f]
+ *
+ * @return Size of buffer in bytes.
+ */
+int rtnl_tc_calc_bufsize(int txtime, int rate)
+{
+       double bufsize;
+
+       bufsize = (double) txtime * (double) rate;
+
+       return bufsize / 1000000.;
+}
+
+/**
+ * Calculate the binary logarithm for a specific cell size
+ * @arg cell_size      Size of cell, must be a power of two.
+ * @return Binary logirhtm of cell size or a negative error code.
+ */
+int rtnl_tc_calc_cell_log(int cell_size)
+{
+       int i;
+
+       for (i = 0; i < 32; i++)
+               if ((1 << i) == cell_size)
+                       return i;
+
+       return -NLE_INVAL;
+}
+
+
+/** @} */
+
+/**
+ * @name Rate Tables
+ * @{
+ */
+
+/*
+ * COPYRIGHT NOTE:
+ * align_to_atm() and adjust_size() derived/coped from iproute2 source.
+ */
+
+/*
+ * The align to ATM cells is used for determining the (ATM) SAR
+ * alignment overhead at the ATM layer. (SAR = Segmentation And
+ * Reassembly).  This is for example needed when scheduling packet on
+ * an ADSL connection.  Note that the extra ATM-AAL overhead is _not_
+ * included in this calculation. This overhead is added in the kernel
+ * before doing the rate table lookup, as this gives better precision
+ * (as the table will always be aligned for 48 bytes).
+ *  --Hawk, d.7/11-2004. <hawk@diku.dk>
+ */
+static unsigned int align_to_atm(unsigned int size)
+{
+       int linksize, cells;
+       cells = size / ATM_CELL_PAYLOAD;
+       if ((size % ATM_CELL_PAYLOAD) > 0)
+               cells++;
+
+       linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */
+       return linksize;
+}
+
+static unsigned int adjust_size(unsigned int size, unsigned int mpu,
+                               uint32_t linktype)
+{
+       if (size < mpu)
+               size = mpu;
+
+       switch (linktype) {
+       case ARPHRD_ATM:
+               return align_to_atm(size);
+
+       case ARPHRD_ETHER:
+       default:
+               return size;
+       }
+}
+
+/**
+ * Compute a transmission time lookup table
+ * @arg tc             traffic control object
+ * @arg spec           Rate specification
+ * @arg dst            Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[].
+ *
+ * Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the
+ * transmission times for various packet sizes, e.g. the transmission
+ * time for a packet of size \c pktsize could be looked up:
+ * @code
+ * txtime = table[pktsize >> log2(mtu)];
+ * @endcode
+ */
+int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec,
+                            uint32_t *dst)
+{
+       uint32_t mtu = rtnl_tc_get_mtu(tc);
+       uint32_t linktype = rtnl_tc_get_linktype(tc);
+       uint8_t cell_log = spec->rs_cell_log;
+       unsigned int size, i;
+
+       spec->rs_mpu = rtnl_tc_get_mpu(tc);
+       spec->rs_overhead = rtnl_tc_get_overhead(tc);
+
+       if (mtu == 0)
+               mtu = 2047;
+
+       if (cell_log == UINT8_MAX) {
+               /*
+                * cell_log not specified, calculate it. It has to specify the
+                * minimum number of rshifts required to break the MTU to below
+                * RTNL_TC_RTABLE_SIZE.
+                */
+               cell_log = 0;
+               while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE)
+                       cell_log++;
+       }
+
+       for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
+               size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
+               dst[i] = nl_us2ticks(rtnl_tc_calc_txtime(size, spec->rs_rate));
+       }
+
+       spec->rs_cell_align = -1;
+       spec->rs_cell_log = cell_log;
+
+       return 0;
+}
+
+/** @} */
+
+/**
+ * @name TC implementation of cache functions
+ */
+
+void rtnl_tc_free_data(struct nl_object *obj)
+{
+       struct rtnl_tc *tc = TC_CAST(obj);
+       struct rtnl_tc_ops *ops;
+       
+       rtnl_link_put(tc->tc_link);
+       nl_data_free(tc->tc_opts);
+       nl_data_free(tc->tc_xstats);
+
+       if (tc->tc_subdata) {
+               ops = rtnl_tc_get_ops(tc);
+               if (ops && ops->to_free_data)
+                       ops->to_free_data(tc, nl_data_get(tc->tc_subdata));
+
+               nl_data_free(tc->tc_subdata);
+       }
+}
+
+int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj)
+{
+       struct rtnl_tc *dst = TC_CAST(dstobj);
+       struct rtnl_tc *src = TC_CAST(srcobj);
+       struct rtnl_tc_ops *ops;
+
+       if (src->tc_link) {
+               nl_object_get(OBJ_CAST(src->tc_link));
+               dst->tc_link = src->tc_link;
+       }
+
+       if (src->tc_opts) {
+               dst->tc_opts = nl_data_clone(src->tc_opts);
+               if (!dst->tc_opts)
+                       return -NLE_NOMEM;
+       }
+       
+       if (src->tc_xstats) {
+               dst->tc_xstats = nl_data_clone(src->tc_xstats);
+               if (!dst->tc_xstats)
+                       return -NLE_NOMEM;
+       }
+
+       if (src->tc_subdata) {
+               if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) {
+                       return -NLE_NOMEM;
+               }
+       }
+
+       ops = rtnl_tc_get_ops(src);
+       if (ops && ops->to_clone) {
+               void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src);
+
+               if (!a)
+                       return 0;
+               else if (!b)
+                       return -NLE_NOMEM;
+
+               return ops->to_clone(a, b);
+       }
+
+       return 0;
+}
+
+static int tc_dump(struct rtnl_tc *tc, enum nl_dump_type type,
+                  struct nl_dump_params *p)
+{
+       struct rtnl_tc_type_ops *type_ops;
+       struct rtnl_tc_ops *ops;
+       void *data = rtnl_tc_data(tc);
+
+       type_ops = tc_type_ops[tc->tc_type];
+       if (type_ops && type_ops->tt_dump[type])
+               type_ops->tt_dump[type](tc, p);
+
+       ops = rtnl_tc_get_ops(tc);
+       if (ops && ops->to_dump[type]) {
+               ops->to_dump[type](tc, data, p);
+               return 1;
+       }
+
+       return 0;
+}
+
+void rtnl_tc_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_tc_type_ops *type_ops;
+       struct rtnl_tc *tc = TC_CAST(obj);
+       struct nl_cache *link_cache;
+       char buf[32];
+
+       nl_new_line(p);
+
+       type_ops = tc_type_ops[tc->tc_type];
+       if (type_ops && type_ops->tt_dump_prefix)
+               nl_dump(p, "%s ", type_ops->tt_dump_prefix);
+
+       nl_dump(p, "%s ", tc->tc_kind);
+
+       if ((link_cache = nl_cache_mngt_require_safe("route/link"))) {
+               nl_dump(p, "dev %s ",
+                       rtnl_link_i2name(link_cache, tc->tc_ifindex,
+                                        buf, sizeof(buf)));
+       } else
+               nl_dump(p, "dev %u ", tc->tc_ifindex);
+       
+       nl_dump(p, "id %s ",
+               rtnl_tc_handle2str(tc->tc_handle, buf, sizeof(buf)));
+       
+       nl_dump(p, "parent %s",
+               rtnl_tc_handle2str(tc->tc_parent, buf, sizeof(buf)));
+
+       tc_dump(tc, NL_DUMP_LINE, p);
+       nl_dump(p, "\n");
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+}
+
+void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_tc *tc = TC_CAST(obj);
+
+       rtnl_tc_dump_line(OBJ_CAST(tc), p);
+
+       nl_dump_line(p, "  ");
+
+       if (tc->ce_mask & TCA_ATTR_MTU)
+               nl_dump(p, " mtu %u", tc->tc_mtu);
+
+       if (tc->ce_mask & TCA_ATTR_MPU)
+               nl_dump(p, " mpu %u", tc->tc_mpu);
+
+       if (tc->ce_mask & TCA_ATTR_OVERHEAD)
+               nl_dump(p, " overhead %u", tc->tc_overhead);
+
+       if (!tc_dump(tc, NL_DUMP_DETAILS, p))
+               nl_dump(p, "no options");
+       nl_dump(p, "\n");
+}
+
+void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
+{
+       struct rtnl_tc *tc = TC_CAST(obj);
+       char *unit, fmt[64];
+       float res;
+
+       rtnl_tc_dump_details(OBJ_CAST(tc), p);
+
+       strcpy(fmt, "        %7.2f %s %10u %10u %10u %10u %10u\n");
+
+       nl_dump_line(p, 
+               "    Stats:    bytes    packets      drops overlimits" \
+               "       qlen    backlog\n");
+
+       res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit);
+       if (*unit == 'B')
+               fmt[11] = '9';
+
+       nl_dump_line(p, fmt, res, unit,
+               tc->tc_stats[RTNL_TC_PACKETS],
+               tc->tc_stats[RTNL_TC_DROPS],
+               tc->tc_stats[RTNL_TC_OVERLIMITS],
+               tc->tc_stats[RTNL_TC_QLEN],
+               tc->tc_stats[RTNL_TC_BACKLOG]);
+
+       res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit);
+
+       strcpy(fmt, "        %7.2f %s/s%9u pps");
+
+       if (*unit == 'B')
+               fmt[11] = '9';
+
+       nl_dump_line(p, fmt, res, unit, tc->tc_stats[RTNL_TC_RATE_PPS]);
+
+       tc_dump(tc, NL_DUMP_LINE, p);
+       nl_dump(p, "\n");
+}
+
+int rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj,
+                   uint32_t attrs, int flags)
+{
+       struct rtnl_tc *a = TC_CAST(aobj);
+       struct rtnl_tc *b = TC_CAST(bobj);
+       int diff = 0;
+
+#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
+
+       diff |= TC_DIFF(HANDLE,         a->tc_handle != b->tc_handle);
+       diff |= TC_DIFF(PARENT,         a->tc_parent != b->tc_parent);
+       diff |= TC_DIFF(IFINDEX,        a->tc_ifindex != b->tc_ifindex);
+       diff |= TC_DIFF(KIND,           strcmp(a->tc_kind, b->tc_kind));
+
+#undef TC_DIFF
+
+       return diff;
+}
+
+/** @} */
+
+/**
+ * @name Modules API
+ */
+
+struct rtnl_tc_ops *rtnl_tc_lookup_ops(enum rtnl_tc_type type, const char *kind)
+{
+       struct rtnl_tc_ops *ops;
+
+       nl_list_for_each_entry(ops, &tc_ops_list[type], to_list)
+               if (!strcmp(kind, ops->to_kind))
+                       return ops;
+
+       return NULL;
+}
+
+struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc)
+{
+       if (!tc->tc_ops)
+               tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind);
+
+       return tc->tc_ops;
+}
+
+/**
+ * Register a traffic control module
+ * @arg ops            traffic control module operations
+ */
+int rtnl_tc_register(struct rtnl_tc_ops *ops)
+{
+       static int init = 0;
+
+       /*
+        * Initialiation hack, make sure list is initialized when
+        * the first tc module registers. Putting this in a
+        * separate __init would required correct ordering of init
+        * functions
+        */
+       if (!init) {
+               int i;
+
+               for (i = 0; i < __RTNL_TC_TYPE_MAX; i++)
+                       nl_init_list_head(&tc_ops_list[i]);
+
+               init = 1;
+       }
+
+       if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX)
+               BUG();
+
+       if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind))
+               return -NLE_EXIST;
+
+       nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]);
+
+       return 0;
+}
+
+/**
+ * Unregister a traffic control module
+ * @arg ops            traffic control module operations
+ */
+void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
+{
+       nl_list_del(&ops->to_list);
+}
+
+/**
+ * Return pointer to private data of traffic control object
+ * @arg tc             traffic control object
+ *
+ * Allocates the private traffic control object data section
+ * as necessary and returns it.
+ *
+ * @return Pointer to private tc data or NULL if allocation failed.
+ */
+void *rtnl_tc_data(struct rtnl_tc *tc)
+{
+       if (!tc->tc_subdata) {
+               size_t size;
+
+               if (!tc->tc_ops) {
+                       if (!tc->tc_kind)
+                               BUG();
+
+                       if (!rtnl_tc_get_ops(tc))
+                               return NULL;
+               }
+
+               if (!(size = tc->tc_ops->to_size))
+                       BUG();
+
+               if (!(tc->tc_subdata = nl_data_alloc(NULL, size)))
+                       return NULL;
+       }
+
+       return nl_data_get(tc->tc_subdata);
+}
+
+/**
+ * Check traffic control object type and return private data section 
+ * @arg tc             traffic control object
+ * @arg ops            expected traffic control object operations
+ *
+ * Checks whether the traffic control object matches the type
+ * specified with the traffic control object operations. If the
+ * type matches, the private tc object data is returned. If type
+ * mismatches, APPBUG() will print a application bug warning.
+ *
+ * @see rtnl_tc_data()
+ *
+ * @return Pointer to private tc data or NULL if type mismatches.
+ */
+void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops)
+{
+       if (tc->tc_ops != ops) {
+               char buf[64];
+
+               snprintf(buf, sizeof(buf),
+                        "tc object %p used in %s context but is of type %s",
+                        tc, ops->to_kind, tc->tc_ops->to_kind);
+               APPBUG(buf);
+
+               return NULL;
+       }
+
+       return rtnl_tc_data(tc);
+}
+
+void rtnl_tc_type_register(struct rtnl_tc_type_ops *ops)
+{
+       if (ops->tt_type > RTNL_TC_TYPE_MAX)
+               BUG();
+
+       tc_type_ops[ops->tt_type] = ops;
+}
+
+void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *ops)
+{
+       if (ops->tt_type > RTNL_TC_TYPE_MAX)
+               BUG();
+
+       tc_type_ops[ops->tt_type] = NULL;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/socket.c b/lib/socket.c
new file mode 100644 (file)
index 0000000..1ca7783
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+ * lib/socket.c                Netlink Socket
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core_types
+ * @defgroup socket Socket
+ *
+ * Representation of a netlink socket
+ *
+ * Related sections in the development guide:
+ * - @core_doc{core_sockets, Netlink Sockets}
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/socket.h>
+ * ~~~~
+ */
+
+#include "defs.h"
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/handlers.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+
+static int default_cb = NL_CB_DEFAULT;
+
+static void __init init_default_cb(void)
+{
+       char *nlcb;
+
+       if ((nlcb = getenv("NLCB"))) {
+               if (!strcasecmp(nlcb, "default"))
+                       default_cb = NL_CB_DEFAULT;
+               else if (!strcasecmp(nlcb, "verbose"))
+                       default_cb = NL_CB_VERBOSE;
+               else if (!strcasecmp(nlcb, "debug"))
+                       default_cb = NL_CB_DEBUG;
+               else {
+                       fprintf(stderr, "Unknown value for NLCB, valid values: "
+                               "{default | verbose | debug}\n");
+               }
+       }
+}
+
+static uint32_t used_ports_map[32];
+static NL_RW_LOCK(port_map_lock);
+
+static uint32_t generate_local_port(void)
+{
+       int i, n;
+       uint32_t pid = getpid() & 0x3FFFFF;
+
+       nl_write_lock(&port_map_lock);
+
+       for (i = 0; i < 32; i++) {
+               if (used_ports_map[i] == 0xFFFFFFFF)
+                       continue;
+
+               for (n = 0; n < 32; n++) {
+                       if (1UL & (used_ports_map[i] >> n))
+                               continue;
+
+                       used_ports_map[i] |= (1UL << n);
+                       n += (i * 32);
+
+                       /* PID_MAX_LIMIT is currently at 2^22, leaving 10 bit
+                        * to, i.e. 1024 unique ports per application. */
+
+                       nl_write_unlock(&port_map_lock);
+
+                       return pid + (n << 22);
+               }
+       }
+
+       nl_write_unlock(&port_map_lock);
+
+       /* Out of sockets in our own PID namespace, what to do? FIXME */
+       return UINT_MAX;
+}
+
+static void release_local_port(uint32_t port)
+{
+       int nr;
+
+       if (port == UINT_MAX)
+               return;
+       
+       nr = port >> 22;
+
+       nl_write_lock(&port_map_lock);
+       used_ports_map[nr / 32] &= ~(1 << (nr % 32));
+       nl_write_unlock(&port_map_lock);
+}
+
+/**
+ * @name Allocation
+ * @{
+ */
+
+static struct nl_sock *__alloc_socket(struct nl_cb *cb)
+{
+       struct nl_sock *sk;
+
+       sk = calloc(1, sizeof(*sk));
+       if (!sk)
+               return NULL;
+
+       sk->s_fd = -1;
+       sk->s_cb = nl_cb_get(cb);
+       sk->s_local.nl_family = AF_NETLINK;
+       sk->s_peer.nl_family = AF_NETLINK;
+       sk->s_seq_expect = sk->s_seq_next = time(0);
+       sk->s_local.nl_pid = generate_local_port();
+       if (sk->s_local.nl_pid == UINT_MAX) {
+               nl_socket_free(sk);
+               return NULL;
+       }
+
+       return sk;
+}
+
+/**
+ * Allocate new netlink socket
+ *
+ * @return Newly allocated netlink socket or NULL.
+ */
+struct nl_sock *nl_socket_alloc(void)
+{
+       struct nl_cb *cb;
+        struct nl_sock *sk;
+
+       cb = nl_cb_alloc(default_cb);
+       if (!cb)
+               return NULL;
+
+        /* will increment cb reference count on success */
+       sk = __alloc_socket(cb);
+
+        nl_cb_put(cb);
+
+        return sk;
+}
+
+/**
+ * Allocate new socket with custom callbacks
+ * @arg cb             Callback handler
+ *
+ * The reference to the callback handler is taken into account
+ * automatically, it is released again upon calling nl_socket_free().
+ *
+ *@return Newly allocted socket handle or NULL.
+ */
+struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
+{
+       if (cb == NULL)
+               BUG();
+
+       return __alloc_socket(cb);
+}
+
+/**
+ * Free a netlink socket.
+ * @arg sk             Netlink socket.
+ */
+void nl_socket_free(struct nl_sock *sk)
+{
+       if (!sk)
+               return;
+
+       if (sk->s_fd >= 0)
+               close(sk->s_fd);
+
+       if (!(sk->s_flags & NL_OWN_PORT))
+               release_local_port(sk->s_local.nl_pid);
+
+       nl_cb_put(sk->s_cb);
+       free(sk);
+}
+
+/** @} */
+
+/**
+ * @name Sequence Numbers
+ * @{
+ */
+
+static int noop_seq_check(struct nl_msg *msg, void *arg)
+{
+       return NL_OK;
+}
+
+
+/**
+ * Disable sequence number checking.
+ * @arg sk             Netlink socket.
+ *
+ * Disables checking of sequence numbers on the netlink socket This is
+ * required to allow messages to be processed which were not requested by
+ * a preceding request message, e.g. netlink events.
+ *
+ * @note This function modifies the NL_CB_SEQ_CHECK configuration in
+ * the callback handle associated with the socket.
+ */
+void nl_socket_disable_seq_check(struct nl_sock *sk)
+{
+       nl_cb_set(sk->s_cb, NL_CB_SEQ_CHECK,
+                 NL_CB_CUSTOM, noop_seq_check, NULL);
+}
+
+/**
+ * Use next sequence number
+ * @arg sk             Netlink socket.
+ *
+ * Uses the next available sequence number and increases the counter
+ * by one for subsequent calls.
+ *
+ * @return Unique serial sequence number
+ */
+unsigned int nl_socket_use_seq(struct nl_sock *sk)
+{
+       return sk->s_seq_next++;
+}
+
+/**
+ * Disable automatic request for ACK
+ * @arg sk             Netlink socket.
+ *
+ * The default behaviour of a socket is to request an ACK for
+ * each message sent to allow for the caller to synchronize to
+ * the completion of the netlink operation. This function
+ * disables this behaviour and will result in requests being
+ * sent which will not have the NLM_F_ACK flag set automatically.
+ * However, it is still possible for the caller to set the
+ * NLM_F_ACK flag explicitely.
+ */
+void nl_socket_disable_auto_ack(struct nl_sock *sk)
+{
+       sk->s_flags |= NL_NO_AUTO_ACK;
+}
+
+/**
+ * Enable automatic request for ACK (default)
+ * @arg sk             Netlink socket.
+ * @see nl_socket_disable_auto_ack
+ */
+void nl_socket_enable_auto_ack(struct nl_sock *sk)
+{
+       sk->s_flags &= ~NL_NO_AUTO_ACK;
+}
+
+/** @} */
+
+/**
+ * @name Source Idenficiation
+ * @{
+ */
+
+uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
+{
+       return sk->s_local.nl_pid;
+}
+
+/**
+ * Set local port of socket
+ * @arg sk             Netlink socket.
+ * @arg port           Local port identifier
+ *
+ * Assigns a local port identifier to the socket. If port is 0
+ * a unique port identifier will be generated automatically.
+ */
+void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port)
+{
+       if (port == 0) {
+               port = generate_local_port(); 
+               /*
+                * Release local port after generation of a new one to be
+                * able to change local port using nl_socket_set_local_port(, 0)
+                */
+               if (!(sk->s_flags & NL_OWN_PORT))
+                       release_local_port(sk->s_local.nl_pid);
+               else
+                       sk->s_flags &= ~NL_OWN_PORT;
+       } else  {
+               if (!(sk->s_flags & NL_OWN_PORT))
+                       release_local_port(sk->s_local.nl_pid);
+               sk->s_flags |= NL_OWN_PORT;
+       }
+
+       sk->s_local.nl_pid = port;
+}
+
+/** @} */
+
+/**
+ * @name Group Subscriptions
+ * @{
+ */
+
+/**
+ * Join groups
+ * @arg sk             Netlink socket
+ * @arg group          Group identifier
+ *
+ * Joins the specified groups using the modern socket option which
+ * is available since kernel version 2.6.14. It allows joining an
+ * almost arbitary number of groups without limitation.  The list
+ * of groups has to be terminated by 0 (%NFNLGRP_NONE).
+ *
+ * Make sure to use the correct group definitions as the older
+ * bitmask definitions for nl_join_groups() are likely to still
+ * be present for backward compatibility reasons.
+ *
+ * @return 0 on sucess or a negative error code.
+ */
+int nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
+{
+       int err;
+       va_list ap;
+
+       if (sk->s_fd == -1)
+               return -NLE_BAD_SOCK;
+
+       va_start(ap, group);
+
+       while (group != 0) {
+               if (group < 0) {
+                       va_end(ap);
+                       return -NLE_INVAL;
+               }
+
+               err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+                                                &group, sizeof(group));
+               if (err < 0) {
+                       va_end(ap);
+                       return -nl_syserr2nlerr(errno);
+               }
+
+               group = va_arg(ap, int);
+       }
+
+       va_end(ap);
+
+       return 0;
+}
+
+int nl_socket_add_membership(struct nl_sock *sk, int group)
+{
+       return nl_socket_add_memberships(sk, group, 0);
+}
+
+/**
+ * Leave groups
+ * @arg sk             Netlink socket
+ * @arg group          Group identifier
+ *
+ * Leaves the specified groups using the modern socket option
+ * which is available since kernel version 2.6.14. The list of groups
+ * has to terminated by 0 (%NFNLGRP_NONE).
+ *
+ * @see nl_socket_add_membership
+ * @return 0 on success or a negative error code.
+ */
+int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...)
+{
+       int err;
+       va_list ap;
+
+       if (sk->s_fd == -1)
+               return -NLE_BAD_SOCK;
+
+       va_start(ap, group);
+
+       while (group != 0) {
+               if (group < 0) {
+                       va_end(ap);
+                       return -NLE_INVAL;
+               }
+
+               err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+                                                &group, sizeof(group));
+               if (err < 0) {
+                       va_end(ap);
+                       return -nl_syserr2nlerr(errno);
+               }
+
+               group = va_arg(ap, int);
+       }
+
+       va_end(ap);
+
+       return 0;
+}
+
+int nl_socket_drop_membership(struct nl_sock *sk, int group)
+{
+       return nl_socket_drop_memberships(sk, group, 0);
+}
+
+
+/**
+ * Join multicast groups (deprecated)
+ * @arg sk             Netlink socket.
+ * @arg groups         Bitmask of groups to join.
+ *
+ * This function defines the old way of joining multicast group which
+ * has to be done prior to calling nl_connect(). It works on any kernel
+ * version but is very limited as only 32 groups can be joined.
+ */
+void nl_join_groups(struct nl_sock *sk, int groups)
+{
+       sk->s_local.nl_groups |= groups;
+}
+
+
+/** @} */
+
+/**
+ * @name Peer Identfication
+ * @{
+ */
+
+uint32_t nl_socket_get_peer_port(const struct nl_sock *sk)
+{
+       return sk->s_peer.nl_pid;
+}
+
+void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port)
+{
+       sk->s_peer.nl_pid = port;
+}
+
+uint32_t nl_socket_get_peer_groups(const struct nl_sock *sk)
+{
+       return sk->s_peer.nl_groups;
+}
+
+void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups)
+{
+       sk->s_peer.nl_groups = groups;
+}
+
+
+
+/** @} */
+
+/**
+ * @name File Descriptor
+ * @{
+ */
+
+/**
+ * Return the file descriptor of the backing socket
+ * @arg sk             Netlink socket
+ *
+ * Only valid after calling nl_connect() to create and bind the respective
+ * socket.
+ *
+ * @return File descriptor or -1 if not available.
+ */
+int nl_socket_get_fd(const struct nl_sock *sk)
+{
+       return sk->s_fd;
+}
+
+/**
+ * Set file descriptor of socket to non-blocking state
+ * @arg sk             Netlink socket.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_socket_set_nonblocking(const struct nl_sock *sk)
+{
+       if (sk->s_fd == -1)
+               return -NLE_BAD_SOCK;
+
+       if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
+               return -nl_syserr2nlerr(errno);
+
+       return 0;
+}
+
+/**
+ * Enable use of MSG_PEEK when reading from socket
+ * @arg sk             Netlink socket.
+ */
+void nl_socket_enable_msg_peek(struct nl_sock *sk)
+{
+       sk->s_flags |= NL_MSG_PEEK;
+}
+
+/**
+ * Disable use of MSG_PEEK when reading from socket
+ * @arg sk             Netlink socket.
+ */
+void nl_socket_disable_msg_peek(struct nl_sock *sk)
+{
+       sk->s_flags &= ~NL_MSG_PEEK;
+}
+
+/** @} */
+
+/**
+ * @name Callback Handler
+ * @{
+ */
+
+struct nl_cb *nl_socket_get_cb(const struct nl_sock *sk)
+{
+       return nl_cb_get(sk->s_cb);
+}
+
+void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
+{
+        if (cb == NULL)
+                BUG();
+
+       nl_cb_put(sk->s_cb);
+       sk->s_cb = nl_cb_get(cb);
+}
+
+/**
+ * Modify the callback handler associated with the socket
+ * @arg sk             Netlink socket.
+ * @arg type           which type callback to set
+ * @arg kind           kind of callback
+ * @arg func           callback function
+ * @arg arg            argument to be passed to callback function
+ *
+ * @see nl_cb_set
+ */
+int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type,
+                       enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
+                       void *arg)
+{
+       return nl_cb_set(sk->s_cb, type, kind, func, arg);
+}
+
+/**
+ * Modify the error callback handler associated with the socket
+ * @arg sk             Netlink socket.
+ * @arg kind           kind of callback
+ * @arg func           callback function
+ * @arg arg            argument to be passed to callback function
+ *
+ * @see nl_cb_err
+ */
+int nl_socket_modify_err_cb(struct nl_sock *sk, enum nl_cb_kind kind,
+                           nl_recvmsg_err_cb_t func, void *arg)
+{
+       return nl_cb_err(sk->s_cb, kind, func, arg);
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+/**
+ * Set socket buffer size of netlink socket.
+ * @arg sk             Netlink socket.
+ * @arg rxbuf          New receive socket buffer size in bytes.
+ * @arg txbuf          New transmit socket buffer size in bytes.
+ *
+ * Sets the socket buffer size of a netlink socket to the specified
+ * values \c rxbuf and \c txbuf. Providing a value of \c 0 assumes a
+ * good default value.
+ *
+ * @note It is not required to call this function prior to nl_connect().
+ * @return 0 on sucess or a negative error code.
+ */
+int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
+{
+       int err;
+
+       if (rxbuf <= 0)
+               rxbuf = 32768;
+
+       if (txbuf <= 0)
+               txbuf = 32768;
+
+       if (sk->s_fd == -1)
+               return -NLE_BAD_SOCK;
+       
+       err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
+                        &txbuf, sizeof(txbuf));
+       if (err < 0)
+               return -nl_syserr2nlerr(errno);
+
+       err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
+                        &rxbuf, sizeof(rxbuf));
+       if (err < 0)
+               return -nl_syserr2nlerr(errno);
+
+       sk->s_flags |= NL_SOCK_BUFSIZE_SET;
+
+       return 0;
+}
+
+/**
+ * Set default message buffer size of netlink socket.
+ * @arg sk             Netlink socket.
+ * @arg bufsize                Default message buffer size in bytes.
+ *
+ * Sets the default message buffer size to the specified length in bytes.
+ * The default message buffer size limits the maximum message size the
+ * socket will be able to receive. It is generally recommneded to specify
+ * a buffer size no less than the size of a memory page.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_socket_set_msg_buf_size(struct nl_sock *sk, size_t bufsize)
+{
+       sk->s_bufsize = bufsize;
+
+       return 0;
+}
+
+/**
+ * Get default message buffer size of netlink socket.
+ * @arg sk             Netlink socket.
+ *
+ * @return Size of default message buffer.
+ */
+size_t nl_socket_get_msg_buf_size(struct nl_sock *sk)
+{
+       return sk->s_bufsize;
+}
+
+/**
+ * Enable/disable credential passing on netlink socket.
+ * @arg sk             Netlink socket.
+ * @arg state          New state (0 - disabled, 1 - enabled)
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_socket_set_passcred(struct nl_sock *sk, int state)
+{
+       int err;
+
+       if (sk->s_fd == -1)
+               return -NLE_BAD_SOCK;
+
+       err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
+                        &state, sizeof(state));
+       if (err < 0)
+               return -nl_syserr2nlerr(errno);
+
+       if (state)
+               sk->s_flags |= NL_SOCK_PASSCRED;
+       else
+               sk->s_flags &= ~NL_SOCK_PASSCRED;
+
+       return 0;
+}
+
+/**
+ * Enable/disable receival of additional packet information
+ * @arg sk             Netlink socket.
+ * @arg state          New state (0 - disabled, 1 - enabled)
+ *
+ * @return 0 on success or a negative error code
+ */
+int nl_socket_recv_pktinfo(struct nl_sock *sk, int state)
+{
+       int err;
+
+       if (sk->s_fd == -1)
+               return -NLE_BAD_SOCK;
+
+       err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
+                        &state, sizeof(state));
+       if (err < 0)
+               return -nl_syserr2nlerr(errno);
+
+       return 0;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/utils.c b/lib/utils.c
new file mode 100644 (file)
index 0000000..4457b1f
--- /dev/null
@@ -0,0 +1,1106 @@
+/*
+ * lib/utils.c         Utility Functions
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup utils Utilities
+ *
+ * Collection of helper functions
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/utils.h>
+ * ~~~~
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <linux/socket.h>
+#include <stdlib.h> /* exit() */
+
+/**
+ * Global variable indicating the desired level of debugging output.
+ *
+ * Level | Messages Printed
+ * ----- | ---------------------------------------------------------
+ *     0 | Debugging output disabled
+ *     1 | Warnings, important events and notifications
+ *     2 | More or less important debugging messages
+ *     3 | Repetitive events causing a flood of debugging messages
+ *     4 | Even less important messages
+ *
+ * If available, the variable will be initialized to the value of the
+ * environment variable `NLDBG`. The default value is 0 (disabled).
+ *
+ * For more information, see section @core_doc{_debugging, Debugging}.
+ */
+int nl_debug = 0;
+
+/** @cond SKIP */
+#ifdef NL_DEBUG
+struct nl_dump_params nl_debug_dp = {
+       .dp_type = NL_DUMP_DETAILS,
+};
+
+static void __init nl_debug_init(void)
+{
+       char *nldbg, *end;
+       
+       if ((nldbg = getenv("NLDBG"))) {
+               long level = strtol(nldbg, &end, 0);
+               if (nldbg != end)
+                       nl_debug = level;
+       }
+
+       nl_debug_dp.dp_fd = stderr;
+}
+#endif
+
+int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
+{
+       FILE *fd;
+       char buf[128];
+
+       fd = fopen(path, "r");
+       if (fd == NULL)
+               return -nl_syserr2nlerr(errno);
+
+       while (fgets(buf, sizeof(buf), fd)) {
+               int goodlen, err;
+               long num;
+               char *end;
+
+               if (*buf == '#' || *buf == '\n' || *buf == '\r')
+                       continue;
+
+               num = strtol(buf, &end, 0);
+               if (end == buf) {
+                       fclose(fd);
+                       return -NLE_INVAL;
+               }
+
+               if (num == LONG_MIN || num == LONG_MAX) {
+                       fclose(fd);
+                       return -NLE_RANGE;
+               }
+
+               while (*end == ' ' || *end == '\t')
+                       end++;
+
+               goodlen = strcspn(end, "#\r\n\t ");
+               if (goodlen == 0) {
+                       fclose(fd);
+                       return -NLE_INVAL;
+               }
+
+               end[goodlen] = '\0';
+
+               err = cb(num, end);
+               if (err < 0) {
+                       fclose(fd);
+                       return err;
+               }
+       }
+
+       fclose(fd);
+
+       return 0;
+}
+/** @endcond */
+
+/**
+ * @name Pretty Printing of Numbers
+ * @{
+ */
+
+/**
+ * Cancel down a byte counter
+ * @arg        l               byte counter
+ * @arg        unit            destination unit pointer
+ *
+ * Cancels down a byte counter until it reaches a reasonable
+ * unit. The chosen unit is assigned to \a unit.
+ * This function assume 1024 bytes in one kilobyte
+ * 
+ * @return The cancelled down byte counter in the new unit.
+ */
+double nl_cancel_down_bytes(unsigned long long l, char **unit)
+{
+       if (l >= 1099511627776LL) {
+               *unit = "TiB";
+               return ((double) l) / 1099511627776LL;
+       } else if (l >= 1073741824) {
+               *unit = "GiB";
+               return ((double) l) / 1073741824;
+       } else if (l >= 1048576) {
+               *unit = "MiB";
+               return ((double) l) / 1048576;
+       } else if (l >= 1024) {
+               *unit = "KiB";
+               return ((double) l) / 1024;
+       } else {
+               *unit = "B";
+               return (double) l;
+       }
+}
+
+/**
+ * Cancel down a bit counter
+ * @arg        l               bit counter
+ * @arg unit           destination unit pointer
+ *
+ * Cancels down bit counter until it reaches a reasonable
+ * unit. The chosen unit is assigned to \a unit.
+ * This function assume 1000 bits in one kilobit
+ *
+ * @return The cancelled down bit counter in the new unit.
+ */
+double nl_cancel_down_bits(unsigned long long l, char **unit)
+{
+       if (l >= 1000000000000ULL) {
+               *unit = "Tbit";
+               return ((double) l) / 1000000000000ULL;
+       }
+
+       if (l >= 1000000000) {
+               *unit = "Gbit";
+               return ((double) l) / 1000000000;
+       }
+
+       if (l >= 1000000) {
+               *unit = "Mbit";
+               return ((double) l) / 1000000;
+       }
+
+       if (l >= 1000) {
+               *unit = "Kbit";
+               return ((double) l) / 1000;
+       }
+
+       *unit = "bit";
+       return (double) l;
+}
+
+int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len)
+{
+       char *unit;
+       double frac;
+
+       switch (type) {
+       case NL_BYTE_RATE:
+               frac = nl_cancel_down_bytes(rate, &unit);
+               break;
+       
+       case NL_BIT_RATE:
+               frac = nl_cancel_down_bits(rate, &unit);
+               break;
+       
+       default:
+               BUG();
+       }
+
+       return snprintf(buf, len, "%.2f%s/s", frac, unit);
+}
+
+/**
+ * Cancel down a micro second value
+ * @arg        l               micro seconds
+ * @arg unit           destination unit pointer
+ *
+ * Cancels down a microsecond counter until it reaches a
+ * reasonable unit. The chosen unit is assigned to \a unit.
+ *
+ * @return The cancelled down microsecond in the new unit
+ */
+double nl_cancel_down_us(uint32_t l, char **unit)
+{
+       if (l >= 1000000) {
+               *unit = "s";
+               return ((double) l) / 1000000;
+       } else if (l >= 1000) {
+               *unit = "ms";
+               return ((double) l) / 1000;
+       } else {
+               *unit = "us";
+               return (double) l;
+       }
+}
+
+/** @} */
+
+/**
+ * @name Generic Unit Translations
+ * @{
+ */
+
+/**
+ * Convert a character string to a size
+ * @arg str            size encoded as character string
+ *
+ * Converts the specified size as character to the corresponding
+ * number of bytes.
+ *
+ * Supported formats are:
+ *  - b,kb/k,m/mb,gb/g for bytes
+ *  - bit,kbit/mbit/gbit
+ *
+ * This function assume 1000 bits in one kilobit and
+ * 1024 bytes in one kilobyte
+ *
+ * @return The number of bytes or -1 if the string is unparseable
+ */
+long nl_size2int(const char *str)
+{
+       char *p;
+       long l = strtol(str, &p, 0);
+       if (p == str)
+               return -NLE_INVAL;
+
+       if (*p) {
+               if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
+                       l *= 1024;
+               else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
+                       l *= 1024*1024*1024;
+               else if (!strcasecmp(p, "gbit"))
+                       l *= 1000000000L/8;
+               else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
+                       l *= 1024*1024;
+               else if (!strcasecmp(p, "mbit"))
+                       l *= 1000000/8;
+               else if (!strcasecmp(p, "kbit"))
+                       l *= 1000/8;
+               else if (!strcasecmp(p, "bit"))
+                       l /= 8;
+               else if (strcasecmp(p, "b") != 0)
+                       return -NLE_INVAL;
+       }
+
+       return l;
+}
+
+static const struct {
+       double limit;
+       const char *unit;
+} size_units[] = {
+       { 1024. * 1024. * 1024. * 1024. * 1024., "EiB" },
+       { 1024. * 1024. * 1024. * 1024., "TiB" },
+       { 1024. * 1024. * 1024., "GiB" },
+       { 1024. * 1024., "MiB" },
+       { 1024., "KiB" },
+       { 0., "B" },
+};
+
+/**
+ * Convert a size toa character string
+ * @arg size           Size in number of bytes
+ * @arg buf            Buffer to write character string to
+ * @arg len            Size of buf
+ *
+ * This function converts a value in bytes to a human readable representation
+ * of it. The function uses IEC prefixes:
+ *
+ * @code
+ * 1024 bytes => 1 KiB
+ * 1048576 bytes => 1 MiB
+ * @endcode
+ *
+ * The highest prefix is used which ensures a result of >= 1.0, the result
+ * is provided as floating point number with a maximum precision of 2 digits:
+ * @code
+ * 965176 bytes => 942.55 KiB
+ * @endcode
+ *
+ * @return pointer to buf
+ */
+char *nl_size2str(const size_t size, char *buf, const size_t len)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(size_units); i++) {
+               if (size >= size_units[i].limit) {
+                       snprintf(buf, len, "%.2g%s",
+                               (double) size / size_units[i].limit,
+                               size_units[i].unit);
+                       return buf;
+               }
+       }
+
+       BUG();
+}
+
+/**
+ * Convert a character string to a probability
+ * @arg str            probability encoded as character string
+ *
+ * Converts the specified probability as character to the
+ * corresponding probability number.
+ *
+ * Supported formats are:
+ *  - 0.0-1.0
+ *  - 0%-100%
+ *
+ * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX
+ */
+long nl_prob2int(const char *str)
+{
+       char *p;
+       double d = strtod(str, &p);
+
+       if (p == str)
+               return -NLE_INVAL;
+
+       if (d > 1.0)
+               d /= 100.0f;
+
+       if (d > 1.0f || d < 0.0f)
+               return -NLE_RANGE;
+
+       if (*p && strcmp(p, "%") != 0)
+               return -NLE_INVAL;
+
+       return rint(d * NL_PROB_MAX);
+}
+
+/** @} */
+
+/**
+ * @name Time Translations
+ * @{
+ */
+
+#ifndef USER_HZ
+#define USER_HZ 100
+#endif
+
+static uint32_t user_hz = USER_HZ;
+static uint32_t psched_hz = USER_HZ;
+
+static double ticks_per_usec = 1.0f;
+
+/* Retrieves the configured HZ and ticks/us value in the kernel.
+ * The value is cached. Supported ways of getting it:
+ *
+ * 1) environment variable
+ * 2) /proc/net/psched and sysconf
+ *
+ * Supports the environment variables:
+ *   PROC_NET_PSCHED  - may point to psched file in /proc
+ *   PROC_ROOT        - may point to /proc fs */ 
+static void __init get_psched_settings(void)
+{
+       char name[FILENAME_MAX];
+       FILE *fd;
+       int got_hz = 0;
+
+       if (getenv("HZ")) {
+               long hz = strtol(getenv("HZ"), NULL, 0);
+
+               if (LONG_MIN != hz && LONG_MAX != hz) {
+                       user_hz = hz;
+                       got_hz = 1;
+               }
+       }
+
+       if (!got_hz)
+               user_hz = sysconf(_SC_CLK_TCK);
+
+       psched_hz = user_hz;
+
+       if (getenv("TICKS_PER_USEC")) {
+               double t = strtod(getenv("TICKS_PER_USEC"), NULL);
+               ticks_per_usec = t;
+       }
+       else {
+               if (getenv("PROC_NET_PSCHED"))
+                       snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
+               else if (getenv("PROC_ROOT"))
+                       snprintf(name, sizeof(name), "%s/net/psched",
+                                getenv("PROC_ROOT"));
+               else
+                       strncpy(name, "/proc/net/psched", sizeof(name) - 1);
+               
+               if ((fd = fopen(name, "r"))) {
+                       unsigned int ns_per_usec, ns_per_tick, nom, denom;
+
+                       if (fscanf(fd, "%08x %08x %08x %08x",
+                              &ns_per_usec, &ns_per_tick, &nom, &denom) != 4) {
+                            NL_DBG(1, "Fatal error: can not read psched settings from \"%s\". " \
+                                    "Try to set TICKS_PER_USEC, PROC_NET_PSCHED or PROC_ROOT " \
+                                    "environment variables\n", name);
+                            exit(1);
+                        }
+
+                       ticks_per_usec = (double) ns_per_usec / 
+                                        (double) ns_per_tick;
+
+                       if (nom == 1000000)
+                               psched_hz = denom;
+
+                       fclose(fd);
+               }
+       }
+}
+
+
+/**
+ * Return the value of HZ
+ */
+int nl_get_user_hz(void)
+{
+       return user_hz;
+}
+
+/**
+ * Return the value of packet scheduler HZ
+ */
+int nl_get_psched_hz(void)
+{
+       return psched_hz;
+}
+
+/**
+ * Convert micro seconds to ticks
+ * @arg us             micro seconds
+ * @return number of ticks
+ */
+uint32_t nl_us2ticks(uint32_t us)
+{
+       return us * ticks_per_usec;
+}
+
+
+/**
+ * Convert ticks to micro seconds
+ * @arg ticks          number of ticks
+ * @return microseconds
+ */
+uint32_t nl_ticks2us(uint32_t ticks)
+{
+       return ticks / ticks_per_usec;
+}
+
+int nl_str2msec(const char *str, uint64_t *result)
+{
+       uint64_t total = 0, l;
+       int plen;
+       char *p;
+
+       do {
+               l = strtoul(str, &p, 0);
+               if (p == str)
+                       return -NLE_INVAL;
+               else if (*p) {
+                       plen = strcspn(p, " \t");
+
+                       if (!plen)
+                               total += l;
+                       else if (!strncasecmp(p, "sec", plen))
+                               total += (l * 1000);
+                       else if (!strncasecmp(p, "min", plen))
+                               total += (l * 1000*60);
+                       else if (!strncasecmp(p, "hour", plen))
+                               total += (l * 1000*60*60);
+                       else if (!strncasecmp(p, "day", plen))
+                               total += (l * 1000*60*60*24);
+                       else
+                               return -NLE_INVAL;
+
+                       str = p + plen;
+               } else
+                       total += l;
+       } while (*str && *p);
+
+       *result = total;
+
+       return 0;
+}
+
+/**
+ * Convert milliseconds to a character string
+ * @arg msec           number of milliseconds
+ * @arg buf            destination buffer
+ * @arg len            buffer length
+ *
+ * Converts milliseconds to a character string split up in days, hours,
+ * minutes, seconds, and milliseconds and stores it in the specified
+ * destination buffer.
+ *
+ * @return The destination buffer.
+ */
+char * nl_msec2str(uint64_t msec, char *buf, size_t len)
+{
+       uint64_t split[5];
+       size_t i;
+       static const char *units[5] = {"d", "h", "m", "s", "msec"};
+       char * const buf_orig = buf;
+
+#define _SPLIT(idx, unit) if ((split[idx] = msec / unit)) msec %= unit
+       _SPLIT(0, 86400000);    /* days */
+       _SPLIT(1, 3600000);     /* hours */
+       _SPLIT(2, 60000);       /* minutes */
+       _SPLIT(3, 1000);        /* seconds */
+#undef  _SPLIT
+       split[4] = msec;
+
+       for (i = 0; i < ARRAY_SIZE(split) && len; i++) {
+               int l;
+               if (split[i] == 0)
+                       continue;
+               l = snprintf(buf, len, "%s%" PRIu64 "%s",
+                       (buf==buf_orig) ? "" : " ", split[i], units[i]);
+               buf += l;
+               len -= l;
+       }
+
+       return buf_orig;
+}
+
+/** @} */
+
+/**
+ * @name Netlink Family Translations
+ * @{
+ */
+
+static const struct trans_tbl nlfamilies[] = {
+       __ADD(NETLINK_ROUTE,route)
+       __ADD(NETLINK_USERSOCK,usersock)
+       __ADD(NETLINK_FIREWALL,firewall)
+       __ADD(NETLINK_INET_DIAG,inetdiag)
+       __ADD(NETLINK_NFLOG,nflog)
+       __ADD(NETLINK_XFRM,xfrm)
+       __ADD(NETLINK_SELINUX,selinux)
+       __ADD(NETLINK_ISCSI,iscsi)
+       __ADD(NETLINK_AUDIT,audit)
+       __ADD(NETLINK_FIB_LOOKUP,fib_lookup)
+       __ADD(NETLINK_CONNECTOR,connector)
+       __ADD(NETLINK_NETFILTER,netfilter)
+       __ADD(NETLINK_IP6_FW,ip6_fw)
+       __ADD(NETLINK_DNRTMSG,dnrtmsg)
+       __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent)
+       __ADD(NETLINK_GENERIC,generic)
+       __ADD(NETLINK_SCSITRANSPORT,scsitransport)
+       __ADD(NETLINK_ECRYPTFS,ecryptfs)
+};
+
+char * nl_nlfamily2str(int family, char *buf, size_t size)
+{
+       return __type2str(family, buf, size, nlfamilies,
+                         ARRAY_SIZE(nlfamilies));
+}
+
+int nl_str2nlfamily(const char *name)
+{
+       return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies));
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @name Link Layer Protocol Translations
+ * @{
+ */
+
+static const struct trans_tbl llprotos[] = {
+       {0, "generic"},
+       __ADD(ARPHRD_ETHER,ether)
+       __ADD(ARPHRD_EETHER,eether)
+       __ADD(ARPHRD_AX25,ax25)
+       __ADD(ARPHRD_PRONET,pronet)
+       __ADD(ARPHRD_CHAOS,chaos)
+       __ADD(ARPHRD_IEEE802,ieee802)
+       __ADD(ARPHRD_ARCNET,arcnet)
+       __ADD(ARPHRD_APPLETLK,atalk)
+       __ADD(ARPHRD_DLCI,dlci)
+       __ADD(ARPHRD_ATM,atm)
+       __ADD(ARPHRD_METRICOM,metricom)
+       __ADD(ARPHRD_IEEE1394,ieee1394)
+#ifdef ARPHRD_EUI64
+       __ADD(ARPHRD_EUI64,eui64)
+#endif
+       __ADD(ARPHRD_INFINIBAND,infiniband)
+       __ADD(ARPHRD_SLIP,slip)
+       __ADD(ARPHRD_CSLIP,cslip)
+       __ADD(ARPHRD_SLIP6,slip6)
+       __ADD(ARPHRD_CSLIP6,cslip6)
+       __ADD(ARPHRD_RSRVD,rsrvd)
+       __ADD(ARPHRD_ADAPT,adapt)
+       __ADD(ARPHRD_ROSE,rose)
+       __ADD(ARPHRD_X25,x25)
+#ifdef ARPHRD_HWX25
+       __ADD(ARPHRD_HWX25,hwx25)
+#endif
+       __ADD(ARPHRD_CAN,can)
+       __ADD(ARPHRD_PPP,ppp)
+       __ADD(ARPHRD_HDLC,hdlc)
+       __ADD(ARPHRD_LAPB,lapb)
+       __ADD(ARPHRD_DDCMP,ddcmp)
+       __ADD(ARPHRD_RAWHDLC,rawhdlc)
+       __ADD(ARPHRD_TUNNEL,ipip)
+       __ADD(ARPHRD_TUNNEL6,tunnel6)
+       __ADD(ARPHRD_FRAD,frad)
+       __ADD(ARPHRD_SKIP,skip)
+       __ADD(ARPHRD_LOOPBACK,loopback)
+       __ADD(ARPHRD_LOCALTLK,localtlk)
+       __ADD(ARPHRD_FDDI,fddi)
+       __ADD(ARPHRD_BIF,bif)
+       __ADD(ARPHRD_SIT,sit)
+       __ADD(ARPHRD_IPDDP,ip/ddp)
+       __ADD(ARPHRD_IPGRE,gre)
+       __ADD(ARPHRD_PIMREG,pimreg)
+       __ADD(ARPHRD_HIPPI,hippi)
+       __ADD(ARPHRD_ASH,ash)
+       __ADD(ARPHRD_ECONET,econet)
+       __ADD(ARPHRD_IRDA,irda)
+       __ADD(ARPHRD_FCPP,fcpp)
+       __ADD(ARPHRD_FCAL,fcal)
+       __ADD(ARPHRD_FCPL,fcpl)
+       __ADD(ARPHRD_FCFABRIC,fcfb_0)
+       __ADD(ARPHRD_FCFABRIC+1,fcfb_1)
+       __ADD(ARPHRD_FCFABRIC+2,fcfb_2)
+       __ADD(ARPHRD_FCFABRIC+3,fcfb_3)
+       __ADD(ARPHRD_FCFABRIC+4,fcfb_4)
+       __ADD(ARPHRD_FCFABRIC+5,fcfb_5)
+       __ADD(ARPHRD_FCFABRIC+6,fcfb_6)
+       __ADD(ARPHRD_FCFABRIC+7,fcfb_7)
+       __ADD(ARPHRD_FCFABRIC+8,fcfb_8)
+       __ADD(ARPHRD_FCFABRIC+9,fcfb_9)
+       __ADD(ARPHRD_FCFABRIC+10,fcfb_10)
+       __ADD(ARPHRD_FCFABRIC+11,fcfb_11)
+       __ADD(ARPHRD_FCFABRIC+12,fcfb_12)
+       __ADD(ARPHRD_IEEE802_TR,tr)
+       __ADD(ARPHRD_IEEE80211,ieee802.11)
+       __ADD(ARPHRD_PHONET,phonet)
+#ifdef ARPHRD_CAIF
+       __ADD(ARPHRD_CAIF, caif)
+#endif
+#ifdef ARPHRD_IEEE80211_PRISM
+       __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
+#endif
+#ifdef ARPHRD_VOID
+       __ADD(ARPHRD_VOID,void)
+#endif
+#ifdef ARPHRD_NONE
+       __ADD(ARPHRD_NONE,nohdr)
+#endif
+};
+
+char * nl_llproto2str(int llproto, char *buf, size_t len)
+{
+       return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos));
+}
+
+int nl_str2llproto(const char *name)
+{
+       return __str2type(name, llprotos, ARRAY_SIZE(llprotos));
+}
+
+/** @} */
+
+
+/**
+ * @name Ethernet Protocol Translations
+ * @{
+ */
+
+static const struct trans_tbl ether_protos[] = {
+       __ADD(ETH_P_LOOP,loop)
+       __ADD(ETH_P_PUP,pup)
+       __ADD(ETH_P_PUPAT,pupat)
+       __ADD(ETH_P_IP,ip)
+       __ADD(ETH_P_X25,x25)
+       __ADD(ETH_P_ARP,arp)
+       __ADD(ETH_P_BPQ,bpq)
+       __ADD(ETH_P_IEEEPUP,ieeepup)
+       __ADD(ETH_P_IEEEPUPAT,ieeepupat)
+       __ADD(ETH_P_DEC,dec)
+       __ADD(ETH_P_DNA_DL,dna_dl)
+       __ADD(ETH_P_DNA_RC,dna_rc)
+       __ADD(ETH_P_DNA_RT,dna_rt)
+       __ADD(ETH_P_LAT,lat)
+       __ADD(ETH_P_DIAG,diag)
+       __ADD(ETH_P_CUST,cust)
+       __ADD(ETH_P_SCA,sca)
+       __ADD(ETH_P_TEB,teb)
+       __ADD(ETH_P_RARP,rarp)
+       __ADD(ETH_P_ATALK,atalk)
+       __ADD(ETH_P_AARP,aarp)
+#ifdef ETH_P_8021Q
+       __ADD(ETH_P_8021Q,802.1q)
+#endif
+       __ADD(ETH_P_IPX,ipx)
+       __ADD(ETH_P_IPV6,ipv6)
+       __ADD(ETH_P_PAUSE,pause)
+       __ADD(ETH_P_SLOW,slow)
+#ifdef ETH_P_WCCP
+       __ADD(ETH_P_WCCP,wccp)
+#endif
+       __ADD(ETH_P_PPP_DISC,ppp_disc)
+       __ADD(ETH_P_PPP_SES,ppp_ses)
+       __ADD(ETH_P_MPLS_UC,mpls_uc)
+       __ADD(ETH_P_MPLS_MC,mpls_mc)
+       __ADD(ETH_P_ATMMPOA,atmmpoa)
+       __ADD(ETH_P_LINK_CTL,link_ctl)
+       __ADD(ETH_P_ATMFATE,atmfate)
+       __ADD(ETH_P_PAE,pae)
+       __ADD(ETH_P_AOE,aoe)
+       __ADD(ETH_P_TIPC,tipc)
+       __ADD(ETH_P_1588,ieee1588)
+       __ADD(ETH_P_FCOE,fcoe)
+       __ADD(ETH_P_FIP,fip)
+       __ADD(ETH_P_EDSA,edsa)
+       __ADD(ETH_P_EDP2,edp2)
+       __ADD(ETH_P_802_3,802.3)
+       __ADD(ETH_P_AX25,ax25)
+       __ADD(ETH_P_ALL,all)
+       __ADD(ETH_P_802_2,802.2)
+       __ADD(ETH_P_SNAP,snap)
+       __ADD(ETH_P_DDCMP,ddcmp)
+       __ADD(ETH_P_WAN_PPP,wan_ppp)
+       __ADD(ETH_P_PPP_MP,ppp_mp)
+       __ADD(ETH_P_LOCALTALK,localtalk)
+       __ADD(ETH_P_CAN,can)
+       __ADD(ETH_P_PPPTALK,ppptalk)
+       __ADD(ETH_P_TR_802_2,tr_802.2)
+       __ADD(ETH_P_MOBITEX,mobitex)
+       __ADD(ETH_P_CONTROL,control)
+       __ADD(ETH_P_IRDA,irda)
+       __ADD(ETH_P_ECONET,econet)
+       __ADD(ETH_P_HDLC,hdlc)
+       __ADD(ETH_P_ARCNET,arcnet)
+       __ADD(ETH_P_DSA,dsa)
+       __ADD(ETH_P_TRAILER,trailer)
+       __ADD(ETH_P_PHONET,phonet)
+       __ADD(ETH_P_IEEE802154,ieee802154)
+       __ADD(ETH_P_CAIF,caif)
+};
+
+char *nl_ether_proto2str(int eproto, char *buf, size_t len)
+{
+       return __type2str(eproto, buf, len, ether_protos,
+                           ARRAY_SIZE(ether_protos));
+}
+
+int nl_str2ether_proto(const char *name)
+{
+       return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos));
+}
+
+/** @} */
+
+/**
+ * @name IP Protocol Translations
+ * @{
+ */
+
+char *nl_ip_proto2str(int proto, char *buf, size_t len)
+{
+       struct protoent *p = getprotobynumber(proto);
+
+       if (p) {
+               snprintf(buf, len, "%s", p->p_name);
+               return buf;
+       }
+
+       snprintf(buf, len, "0x%x", proto);
+       return buf;
+}
+
+int nl_str2ip_proto(const char *name)
+{
+       struct protoent *p = getprotobyname(name);
+       unsigned long l;
+       char *end;
+
+       if (p)
+               return p->p_proto;
+
+       l = strtoul(name, &end, 0);
+       if (l == ULONG_MAX || *end != '\0')
+               return -NLE_OBJ_NOTFOUND;
+
+       return (int) l;
+}
+
+/** @} */
+
+/**
+ * @name Dumping Helpers
+ * @{
+ */
+
+/**
+ * Handle a new line while dumping
+ * @arg params         Dumping parameters
+ *
+ * This function must be called before dumping any onto a
+ * new line. It will ensure proper prefixing as specified
+ * by the dumping parameters.
+ *
+ * @note This function will NOT dump any newlines itself
+ */
+void nl_new_line(struct nl_dump_params *params)
+{
+       params->dp_line++;
+
+       if (params->dp_prefix) {
+               int i;
+               for (i = 0; i < params->dp_prefix; i++) {
+                       if (params->dp_fd)
+                               fprintf(params->dp_fd, " ");
+                       else if (params->dp_buf)
+                               strncat(params->dp_buf, " ",
+                                       params->dp_buflen -
+                                       strlen(params->dp_buf) - 1);
+               }
+       }
+
+       if (params->dp_nl_cb)
+               params->dp_nl_cb(params, params->dp_line);
+}
+
+static void dump_one(struct nl_dump_params *parms, const char *fmt,
+                    va_list args)
+{
+       if (parms->dp_fd)
+               vfprintf(parms->dp_fd, fmt, args);
+       else if (parms->dp_buf || parms->dp_cb) {
+               char *buf = NULL;
+               if (vasprintf(&buf, fmt, args) >= 0) {
+                       if (parms->dp_cb)
+                               parms->dp_cb(parms, buf);
+                       else
+                               strncat(parms->dp_buf, buf,
+                                       parms->dp_buflen -
+                                       strlen(parms->dp_buf) - 1);
+                       free(buf);
+               }
+       }
+}
+
+
+/**
+ * Dump a formatted character string
+ * @arg params         Dumping parameters
+ * @arg fmt            printf style formatting string
+ * @arg ...            Arguments to formatting string
+ *
+ * Dumps a printf style formatting string to the output device
+ * as specified by the dumping parameters.
+ */
+void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       dump_one(params, fmt, args);
+       va_end(args);
+}
+
+void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...)
+{
+       va_list args;
+
+       nl_new_line(parms);
+
+       va_start(args, fmt);
+       dump_one(parms, fmt, args);
+       va_end(args);
+}
+
+
+/** @} */
+
+/** @cond SKIP */
+
+int __trans_list_add(int i, const char *a, struct nl_list_head *head)
+{
+       struct trans_list *tl;
+
+       tl = calloc(1, sizeof(*tl));
+       if (!tl)
+               return -NLE_NOMEM;
+
+       tl->i = i;
+       tl->a = strdup(a);
+
+       nl_list_add_tail(&tl->list, head);
+
+       return 0;
+}
+
+void __trans_list_clear(struct nl_list_head *head)
+{
+       struct trans_list *tl, *next;
+
+       nl_list_for_each_entry_safe(tl, next, head, list) {
+               free(tl->a);
+               free(tl);
+       }
+
+       nl_init_list_head(head);
+}
+
+char *__type2str(int type, char *buf, size_t len,
+                const struct trans_tbl *tbl, size_t tbl_len)
+{
+       size_t i;
+       for (i = 0; i < tbl_len; i++) {
+               if (tbl[i].i == type) {
+                       snprintf(buf, len, "%s", tbl[i].a);
+                       return buf;
+               }
+       }
+
+       snprintf(buf, len, "0x%x", type);
+       return buf;
+}
+
+char *__list_type2str(int type, char *buf, size_t len,
+                     struct nl_list_head *head)
+{
+       struct trans_list *tl;
+
+       nl_list_for_each_entry(tl, head, list) {
+               if (tl->i == type) {
+                       snprintf(buf, len, "%s", tl->a);
+                       return buf;
+               }
+       }
+
+       snprintf(buf, len, "0x%x", type);
+       return buf;
+}
+
+char *__flags2str(int flags, char *buf, size_t len,
+                 const struct trans_tbl *tbl, size_t tbl_len)
+{
+       size_t i;
+       int tmp = flags;
+
+       memset(buf, 0, len);
+       
+       for (i = 0; i < tbl_len; i++) {
+               if (tbl[i].i & tmp) {
+                       tmp &= ~tbl[i].i;
+                       strncat(buf, tbl[i].a, len - strlen(buf) - 1);
+                       if ((tmp & flags))
+                               strncat(buf, ",", len - strlen(buf) - 1);
+               }
+       }
+
+       return buf;
+}
+
+int __str2type(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
+{
+       unsigned long l;
+       char *end;
+       size_t i;
+
+       if (*buf == '\0')
+               return -NLE_INVAL;
+
+       for (i = 0; i < tbl_len; i++)
+               if (!strcasecmp(tbl[i].a, buf))
+                       return tbl[i].i;
+
+       l = strtoul(buf, &end, 0);
+       if (l == ULONG_MAX || *end != '\0')
+               return -NLE_OBJ_NOTFOUND;
+
+       return (int) l;
+}
+
+int __list_str2type(const char *buf, struct nl_list_head *head)
+{
+       struct trans_list *tl;
+       unsigned long l;
+       char *end;
+
+       if (*buf == '\0')
+               return -NLE_INVAL;
+
+       nl_list_for_each_entry(tl, head, list) {
+               if (!strcasecmp(tl->a, buf))
+                       return tl->i;
+       }
+
+       l = strtoul(buf, &end, 0);
+       if (l == ULONG_MAX || *end != '\0')
+               return -NLE_OBJ_NOTFOUND;
+
+       return (int) l;
+}
+
+int __str2flags(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
+{
+       int flags = 0;
+       size_t i;
+       size_t len; /* ptrdiff_t ? */
+       char *p = (char *) buf, *t;
+
+       for (;;) {
+               if (*p == ' ')
+                       p++;
+       
+               t = strchr(p, ',');
+               len = t ? t - p : strlen(p);
+               for (i = 0; i < tbl_len; i++)
+                       if (len == strlen(tbl[i].a) &&
+                           !strncasecmp(tbl[i].a, p, len))
+                               flags |= tbl[i].i;
+
+               if (!t)
+                       return flags;
+
+               p = ++t;
+       }
+
+       return 0;
+}
+
+void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params)
+{
+       int type = params->dp_type;
+
+       if (type < 0 || type > NL_DUMP_MAX)
+               BUG();
+
+       params->dp_line = 0;
+
+       if (params->dp_dump_msgtype) {
+#if 0
+               /* XXX */
+               char buf[64];
+
+               dp_dump_line(params, 0, "%s ",
+                            nl_cache_mngt_type2name(obj->ce_ops,
+                                                    obj->ce_ops->co_protocol,
+                                                    obj->ce_msgtype,
+                                                    buf, sizeof(buf)));
+#endif
+               params->dp_pre_dump = 1;
+       }
+
+       if (obj->ce_ops->oo_dump[type])
+               obj->ce_ops->oo_dump[type](obj, params);
+}
+
+/** @endcond */
+
+/** @} */
diff --git a/lib/version.c b/lib/version.c
new file mode 100644 (file)
index 0000000..0dcafa0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * lib/version.c       Run-time version information
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup core
+ * @defgroup utils Utilities
+ *
+ * Run-time version information
+ *
+ * @{
+ */
+
+
+/**
+ * @name Run-time version information
+ * @{
+ */
+
+#include <netlink/version.h>
+
+const int      nl_ver_num = LIBNL_VER_NUM;
+const int      nl_ver_maj = LIBNL_VER_MAJ;
+const int      nl_ver_min = LIBNL_VER_MIN;
+const int      nl_ver_mic = LIBNL_VER_MIC;
+
+/** @} */
+
+/** @} */
diff --git a/libnl-3.0.pc.in b/libnl-3.0.pc.in
new file mode 100644 (file)
index 0000000..b87e3dc
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnl
+Description: Convenience library for netlink sockets
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lnl-@MAJ_VERSION@
+Cflags: -I${includedir}/libnl@MAJ_VERSION@
diff --git a/libnl-cli-3.0.pc.in b/libnl-cli-3.0.pc.in
new file mode 100644 (file)
index 0000000..d3638ba
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnl-cli
+Description: Command Line Interface library for netlink sockets
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lnl-cli-@MAJ_VERSION@
+Cflags: -I${includedir}
+Requires: libnl-3.0 libnl-genl-3.0 libnl-nf-3.0 libnl-route-3.0
diff --git a/libnl-genl-3.0.pc.in b/libnl-genl-3.0.pc.in
new file mode 100644 (file)
index 0000000..d6b69b8
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnl-genl
+Description: Generic Netlink Library
+Version: @PACKAGE_VERSION@
+Requires: libnl-3.0
+Libs: -L${libdir} -lnl-genl-@MAJ_VERSION@
+Cflags: -I${includedir}/libnl@MAJ_VERSION@
diff --git a/libnl-nf-3.0.pc.in b/libnl-nf-3.0.pc.in
new file mode 100644 (file)
index 0000000..d82e1a6
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnl-nf
+Description: Netfilter Netlink Library
+Version: @PACKAGE_VERSION@
+Requires: libnl-route-3.0
+Libs: -L${libdir} -lnl-nf-@MAJ_VERSION@
+Cflags: -I${includedir}/libnl@MAJ_VERSION@
diff --git a/libnl-route-3.0.pc.in b/libnl-route-3.0.pc.in
new file mode 100644 (file)
index 0000000..372a4f4
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnl-route
+Description: Netlink Routing Family Library
+Version: @PACKAGE_VERSION@
+Requires: libnl-3.0
+Libs: -L${libdir} -lnl-route-@MAJ_VERSION@
+Cflags: -I${includedir}/libnl@MAJ_VERSION@
diff --git a/m4/libtool.m4 b/m4/libtool.m4
new file mode 100644 (file)
index 0000000..56666f0
--- /dev/null
@@ -0,0 +1,7986 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+                  [m4_fatal([Libtool version $1 or higher is required],
+                            63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\    *)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+       [m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+       [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+       [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+          m4_quote(lt_decl_varnames),
+       m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+                       lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+                                          [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+       dnl If the libtool generation code has been placed in $CONFIG_LT,
+       dnl instead of duplicating it all over again into config.status,
+       dnl then we will have config.status run $CONFIG_LT later, so it
+       dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_REPLACE_SHELLFNS
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],                 [_LT_LANG(C)],
+  [C++],               [_LT_LANG(CXX)],
+  [Go],                        [_LT_LANG(GO)],
+  [Java],              [_LT_LANG(GCJ)],
+  [Fortran 77],                [_LT_LANG(F77)],
+  [Fortran],           [_LT_LANG(FC)],
+  [Windows Resource],  [_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+       [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+       [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+       [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+       # By default we will add the -single_module flag. You can override
+       # by either setting the environment variable LT_MULTI_MODULE
+       # non-empty at configure time, or by adding -multi_module to the
+       # link flags.
+       rm -rf libconftest.dylib*
+       echo "int foo(void){return 1;}" > conftest.c
+       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+       # If there is a non-empty error log, and "single_module"
+       # appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+         cat conftest.err >&AS_MESSAGE_LOG_FD
+       # Otherwise, if the output was created with a 0 exit code from
+       # the compiler, it worked.
+       elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+         lt_cv_apple_cc_single_mod=yes
+       else
+         cat conftest.err >&AS_MESSAGE_LOG_FD
+       fi
+       rm -rf libconftest.dylib*
+       rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+       [lt_cv_ld_exported_symbols_list=yes],
+       [lt_cv_ld_exported_symbols_list=no])
+       LDFLAGS="$save_LDFLAGS"
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+       cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+       10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+       10.[[012]]*)
+         _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+       10.*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+         /^0/ {
+             s/^0  *\([^ ]*\) *$/\1/
+             p
+         }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[  --with-sysroot[=DIR] Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([${with_sysroot}])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+       HPUX_IA64_MODE="32"
+       ;;
+      *ELF-64*)
+       HPUX_IA64_MODE="64"
+       ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+       *32-bit*)
+         LD="${LD-ld} -melf32bsmip"
+         ;;
+       *N32*)
+         LD="${LD-ld} -melf32bmipn32"
+         ;;
+       *64-bit*)
+         LD="${LD-ld} -melf64bmip"
+       ;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+       *32-bit*)
+         LD="${LD-ld} -32"
+         ;;
+       *N32*)
+         LD="${LD-ld} -n32"
+         ;;
+       *64-bit*)
+         LD="${LD-ld} -64"
+         ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+       case $host in
+         x86_64-*kfreebsd*-gnu)
+           LD="${LD-ld} -m elf_i386_fbsd"
+           ;;
+         x86_64-*linux*)
+           LD="${LD-ld} -m elf_i386"
+           ;;
+         ppc64-*linux*|powerpc64-*linux*)
+           LD="${LD-ld} -m elf32ppclinux"
+           ;;
+         s390x-*linux*)
+           LD="${LD-ld} -m elf_s390"
+           ;;
+         sparc64-*linux*)
+           LD="${LD-ld} -m elf32_sparc"
+           ;;
+       esac
+       ;;
+      *64-bit*)
+       case $host in
+         x86_64-*kfreebsd*-gnu)
+           LD="${LD-ld} -m elf_x86_64_fbsd"
+           ;;
+         x86_64-*linux*)
+           LD="${LD-ld} -m elf_x86_64"
+           ;;
+         ppc*-*linux*|powerpc*-*linux*)
+           LD="${LD-ld} -m elf64ppc"
+           ;;
+         s390*-*linux*|s390*-*tpf*)
+           LD="${LD-ld} -m elf64_s390"
+           ;;
+         sparc*-*linux*)
+           LD="${LD-ld} -m elf64_sparc"
+           ;;
+       esac
+       ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+       if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+         LD="${LD-ld} -64"
+       fi
+       ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test "$ac_status" -eq 0; then
+       # Ensure the archiver fails upon bogus file names.
+       rm -f conftest.$ac_objext libconftest.a
+       AC_TRY_EVAL([lt_ar_try])
+       if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#              [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[        ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+             test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL          RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL                DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL                0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW         DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW       RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW     DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW     0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+       }
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+         [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+           [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+       [AC_CHECK_FUNC([dlopen],
+             [lt_cv_dlopen="dlopen"],
+         [AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+           [AC_CHECK_LIB([svld], [dlopen],
+                 [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+             [AC_CHECK_LIB([dld], [dld_link],
+                   [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+             ])
+           ])
+         ])
+       ])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+         lt_cv_dlopen_self, [dnl
+         _LT_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+           lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+         lt_cv_dlopen_self_static, [dnl
+         _LT_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+           lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+        [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+        [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+        [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+       [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+       [], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+       lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+          echo ' yes '
+          echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+       :
+      else
+       can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+       if test "$lt_cv_prog_gnu_ld" = yes; then
+               version_type=linux # correct to gnu/linux during the next big refactor
+       else
+               version_type=irix
+       fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+        LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+        [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Add ABI-specific directories to the system library path.
+  sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[  ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+    *)                         need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+       shlibpath_overrides_runpath=no
+       ;;
+      *)
+       shlibpath_overrides_runpath=yes
+       ;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+       ;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+           :
+         else
+           cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+         fi ;;
+       esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+        [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+       [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+       # Check to see if the nm accepts a BSD-compat flag.
+       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+       #   nm: unknown option "B" ignored
+       # Tru64's nm complains that /dev/null is an invalid object file
+       case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+       */dev/null* | *'Invalid file or object type'*)
+         lt_cv_path_NM="$tmp_nm -B"
+         break
+         ;;
+       *)
+         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+         */dev/null*)
+           lt_cv_path_NM="$tmp_nm -p"
+           break
+           ;;
+         *)
+           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+           continue # so that we can try to find one that supports BSD flags
+           ;;
+         esac
+         ;;
+       esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+       [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[    ]]\($symcode$symcode*\)[[       ]][[    ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+       mv -f "$nlist"T "$nlist"
+      else
+       rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+       if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+         cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t@_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+         # Now generate the symbol file.
+         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+         cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t@_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+         $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+         cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+         # Now try linking the two files.
+         mv conftest.$ac_objext conftstm.$ac_objext
+         lt_globsym_save_LIBS=$LIBS
+         lt_globsym_save_CFLAGS=$CFLAGS
+         LIBS="conftstm.$ac_objext"
+         CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+         if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+           pipe_works=yes
+         fi
+         LIBS=$lt_globsym_save_LIBS
+         CFLAGS=$lt_globsym_save_CFLAGS
+       else
+         echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+       fi
+      else
+       echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+       # All AIX code is PIC.
+       if test "$host_cpu" = ia64; then
+         # AIX 5 now supports IA64 processor
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       else
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+       fi
+       ;;
+      chorus*)
+       case $cc_basename in
+       cxch68*)
+         # Green Hills C++ Compiler
+         # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+         ;;
+       esac
+       ;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+       # This hack is so that the source file can tell whether it is being
+       # built for inclusion in a dll (and should export symbols for example).
+       m4_if([$1], [GCJ], [],
+         [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+       ;;
+      dgux*)
+       case $cc_basename in
+         ec++*)
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         ghcx*)
+           # Green Hills C++ Compiler
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      freebsd* | dragonfly*)
+       # FreeBSD uses GNU C++
+       ;;
+      hpux9* | hpux10* | hpux11*)
+       case $cc_basename in
+         CC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+           if test "$host_cpu" != ia64; then
+             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+           fi
+           ;;
+         aCC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+           case $host_cpu in
+           hppa*64*|ia64*)
+             # +Z the default
+             ;;
+           *)
+             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+             ;;
+           esac
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      interix*)
+       # This is c89, which is MS Visual C++ (no shared libs)
+       # Anyone wants to do a port?
+       ;;
+      irix5* | irix6* | nonstopux*)
+       case $cc_basename in
+         CC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           # CC pic flag -KPIC is the default.
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+       case $cc_basename in
+         KCC*)
+           # KAI C++ Compiler
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           ;;
+         ecpc* )
+           # old Intel C++ for x86_64 which still supported -KPIC.
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         icpc* )
+           # Intel C++, used to be incompatible with GCC.
+           # ICC 10 doesn't accept -KPIC any more.
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         pgCC* | pgcpp*)
+           # Portland Group C++ compiler
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         cxx*)
+           # Compaq C++
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+           # IBM XL 8.0, 9.0 on PPC and BlueGene
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+           ;;
+         *)
+           case `$CC -V 2>&1 | sed 5q` in
+           *Sun\ C*)
+             # Sun C++ 5.9
+             _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+             _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+             _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+             ;;
+           esac
+           ;;
+       esac
+       ;;
+      lynxos*)
+       ;;
+      m88k*)
+       ;;
+      mvs*)
+       case $cc_basename in
+         cxx*)
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      netbsd*)
+       ;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+       case $cc_basename in
+         KCC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           ;;
+         RCC*)
+           # Rational C++ 2.4.1
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         cxx*)
+           # Digital/Compaq C++
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      psos*)
+       ;;
+      solaris*)
+       case $cc_basename in
+         CC* | sunCC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+           ;;
+         gcx*)
+           # Green Hills C++ Compiler
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      sunos4*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.x
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         lcc*)
+           # Lucid
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+       case $cc_basename in
+         CC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+       esac
+       ;;
+      tandem*)
+       case $cc_basename in
+         NCC*)
+           # NonStop-UX NCC 3.20
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      vxworks*)
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+       ;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+       ;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+       ;;
+      nagfor*)
+       # NAG Fortran compiler
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       ;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+       ;;
+      *)
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+         # Sun Fortran 8.3 passes all unrecognized flags to the linker
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+         ;;
+       *Sun\ F* | *Sun*Fortran*)
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+         ;;
+       *Sun\ C*)
+         # Sun C 5.9
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         ;;
+        *Intel*\ [[CF]]*Compiler*)
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+         ;;
+       *Portland\ Group*)
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         ;;
+       esac
+       ;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+       [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+       [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+       [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+         *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+       # support --undefined.  This deserves some investigation.  FIXME
+       _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+         cp $export_symbols $output_objdir/$soname.def;
+       else
+         echo EXPORTS > $output_objdir/$soname.def;
+         cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+       $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+       case $cc_basename in
+         diet\ *) tmp_diet=yes;;       # linux-dietlibc with static linking (!diet-dyn)
+       esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+        && test "$tmp_diet" = no
+      then
+       tmp_addflag=' $pic_flag'
+       tmp_sharedflag='-shared'
+       case $cc_basename,$host_cpu in
+        pgcc*)                         # Portland Group C compiler
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # Portland Group f77 and f90 compilers
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag -Mnomain' ;;
+       ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
+         tmp_addflag=' -i_dynamic' ;;
+       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
+         tmp_addflag=' -i_dynamic -nofor_main' ;;
+       ifc* | ifort*)                  # Intel Fortran compiler
+         tmp_addflag=' -nofor_main' ;;
+       lf95*)                          # Lahey Fortran 8.1
+         _LT_TAGVAR(whole_archive_flag_spec, $1)=
+         tmp_sharedflag='--shared' ;;
+       xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+         tmp_sharedflag='-qmkshrobj'
+         tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(compiler_needs_object, $1)=yes
+         ;;
+       esac
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ C*)                       # Sun C 5.9
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(compiler_needs_object, $1)=yes
+         tmp_sharedflag='-G' ;;
+       *Sun\ F*)                       # Sun Fortran 8.3
+         tmp_sharedflag='-G' ;;
+       esac
+       _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+           cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+           echo "local: *; };" >> $output_objdir/$libname.ver~
+           $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+       case $cc_basename in
+       xlf* | bgf* | bgxlf* | mpixlf*)
+         # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+         if test "x$supports_anon_versioning" = xyes; then
+           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+             cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+             echo "local: *; };" >> $output_objdir/$libname.ver~
+             $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+         fi
+         ;;
+       esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+       ;;
+       *)
+         # For security reasons, it is highly recommended that you always
+         # use absolute paths for naming shared libraries, and exclude the
+         # DT_RUNPATH tag from executables and libraries.  But doing so
+         # requires that you compile everything twice, which is a pain.
+         if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         else
+           _LT_TAGVAR(ld_shlibs, $1)=no
+         fi
+       ;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+       # Neither direct hardcoding nor static linking is supported with a
+       # broken collect2.
+       _LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+       # On IA64, the linker does run time linking by default, so we don't
+       # have to do anything special.
+       aix_use_runtimelinking=no
+       exp_sym_flag='-Bexport'
+       no_entry_flag=""
+      else
+       # If we're using GNU nm, then we don't want the "-C" option.
+       # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
+       if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+       else
+         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+       fi
+       aix_use_runtimelinking=no
+
+       # Test if we are trying to use run time linking or normal
+       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+       # need to do runtime linking.
+       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+         for ld_flag in $LDFLAGS; do
+         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+           aix_use_runtimelinking=yes
+           break
+         fi
+         done
+         ;;
+       esac
+
+       exp_sym_flag='-bexport'
+       no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+       case $host_os in aix4.[[012]]|aix4.[[012]].*)
+       # We only want to do this on AIX 4.2 and lower, the check
+       # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" &&
+          strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+         then
+         # We have reworked collect2
+         :
+         else
+         # We have old collect2
+         _LT_TAGVAR(hardcode_direct, $1)=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         _LT_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
+         ;;
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag="$shared_flag "'${wl}-G'
+       fi
+      else
+       # not using gcc
+       if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+       else
+         if test "$aix_use_runtimelinking" = yes; then
+           shared_flag='${wl}-G'
+         else
+           shared_flag='${wl}-bM:SRE'
+         fi
+       fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+       # Warning - without using the other runtime loading flags (-brtl),
+       # -berok will link without error, but may produce a broken library.
+       _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+       if test "$host_cpu" = ia64; then
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+         _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+         _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+       else
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+         # Warning - without using the other run time loading flags,
+         # -berok will link without error, but may produce a broken library.
+         _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+         _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+         fi
+         _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+         # This is similar to how AIX traditionally builds its shared libraries.
+         _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+       # Native MSVC
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+       _LT_TAGVAR(always_export_symbols, $1)=yes
+       _LT_TAGVAR(file_list_spec, $1)='@'
+       # Tell ltmain to make .lib files, not .a files.
+       libext=lib
+       # Tell ltmain to make .dll files, not .so files.
+       shrext_cmds=".dll"
+       # FIXME: Setting linknames here is a bad hack.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+       _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+           sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+         else
+           sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+         fi~
+         $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+         linknames='
+       # The linker will not automatically build a static lib if we build a DLL.
+       # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+       _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+       _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+       # Don't use ranlib
+       _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+       _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+         lt_tool_outputfile="@TOOL_OUTPUT@"~
+         case $lt_outputfile in
+           *.exe|*.EXE) ;;
+           *)
+             lt_outputfile="$lt_outputfile.exe"
+             lt_tool_outputfile="$lt_tool_outputfile.exe"
+             ;;
+         esac~
+         if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+           $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+           $RM "$lt_outputfile.manifest";
+         fi'
+       ;;
+      *)
+       # Assume MSVC wrapper
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+       # Tell ltmain to make .lib files, not .a files.
+       libext=lib
+       # Tell ltmain to make .dll files, not .so files.
+       shrext_cmds=".dll"
+       # FIXME: Setting linknames here is a bad hack.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+       # The linker will automatically build a .lib file if we build a DLL.
+       _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+       # FIXME: Should let the user specify the lib program.
+       _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+       ;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+       _LT_TAGVAR(hardcode_direct, $1)=yes
+       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+       # hardcode_minus_L: Not really in the search PATH,
+       # but as the default location of the library.
+       _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       case $host_cpu in
+       hppa*64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+      else
+       case $host_cpu in
+       hppa*64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+       m4_if($1, [], [
+         # Older versions of the 11.00 compiler do not understand -b yet
+         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+         _LT_LINKER_OPTION([if $CC understands -b],
+           _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+           [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+           [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+         [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+         ;;
+       esac
+      fi
+      if test "$with_gnu_ld" = no; then
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       case $host_cpu in
+       hppa*64*|ia64*)
+         _LT_TAGVAR(hardcode_direct, $1)=no
+         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+         ;;
+       *)
+         _LT_TAGVAR(hardcode_direct, $1)=yes
+         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         _LT_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       # Try to use the -exported_symbol ld option, if it does not
+       # work, assume that -exports_file does not work either and
+       # implicitly export all symbols.
+       # This should be the same for all languages, so no per-tag cache variable.
+       AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+         [lt_cv_irix_exported_symbol],
+         [save_LDFLAGS="$LDFLAGS"
+          LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+          AC_LINK_IFELSE(
+            [AC_LANG_SOURCE(
+               [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+                             [C++], [[int foo (void) { return 0; }]],
+                             [Fortran 77], [[
+      subroutine foo
+      end]],
+                             [Fortran], [[
+      subroutine foo
+      end]])])],
+             [lt_cv_irix_exported_symbol=yes],
+             [lt_cv_irix_exported_symbol=no])
+           LDFLAGS="$save_LDFLAGS"])
+       if test "$lt_cv_irix_exported_symbol" = yes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+       fi
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+       _LT_TAGVAR(hardcode_direct, $1)=yes
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+       if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+       else
+         case $host_os in
+          openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+            _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+            ;;
+          *)
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+            ;;
+         esac
+       fi
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)     # as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+       # Both c and cxx compiler support -rpath directly
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+       wlarc='${wl}'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+       case `$CC -V 2>&1` in
+       *"Compilers 5.0"*)
+         wlarc=''
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+         ;;
+       *)
+         wlarc='${wl}'
+         _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+         ;;
+       esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+       # The compiler driver will combine and reorder linker options,
+       # but understands `-z linker_flag'.  GCC discards it without `$wl',
+       # but is careful enough not to reorder.
+       # Supported since Solaris 2.6 (maybe 2.5.1?)
+       if test "$GCC" = yes; then
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+       else
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+       fi
+       ;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+       # Use $CC to link under sequent, because it throws in some extra .o
+       # files that make .init and .fini sections work.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+       sni)
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+       ;;
+       siemens)
+         ## LD is ld it makes a PLAMLIB
+         ## CC just makes a GrossModule.
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+         _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+       motorola)
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+       ;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       runpath_var=LD_RUN_PATH
+       hardcode_runpath_var=yes
+       _LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+       ;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+       [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+       [$RM conftest*
+       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+       if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+         soname=conftest
+         lib=conftest
+         libobjs=conftest.$ac_objext
+         deplibs=
+         wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+         pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+         compiler_flags=-v
+         linker_flags=-v
+         verstring=
+         output_objdir=.
+         libname=conftest
+         lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+         _LT_TAGVAR(allow_undefined_flag, $1)=
+         if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+         then
+           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+         else
+           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+         fi
+         _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+       else
+         cat conftest.err 1>&5
+       fi
+       $RM conftest*
+       ])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+         $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+           for ld_flag in $LDFLAGS; do
+             case $ld_flag in
+             *-brtl*)
+               aix_use_runtimelinking=yes
+               break
+               ;;
+             esac
+           done
+           ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" &&
+            strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+         then
+           # We have reworked collect2
+           :
+         else
+           # We have old collect2
+           _LT_TAGVAR(hardcode_direct, $1)=unsupported
+           # It fails to find uninstalled libraries when the uninstalled
+           # path is not listed in the libpath.  Setting hardcode_minus_L
+           # to unsupported forces relinking
+           _LT_TAGVAR(hardcode_minus_L, $1)=yes
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
+          esac
+          shared_flag='-shared'
+         if test "$aix_use_runtimelinking" = yes; then
+           shared_flag="$shared_flag "'${wl}-G'
+         fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+         # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+         # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+          else
+           if test "$aix_use_runtimelinking" = yes; then
+             shared_flag='${wl}-G'
+           else
+             shared_flag='${wl}-bM:SRE'
+           fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+       # export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+           _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+           _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+           # Determine the default libpath from the value encoded in an
+           # empty executable.
+           _LT_SYS_MODULE_PATH_AIX([$1])
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+           # Warning - without using the other run time loading flags,
+           # -berok will link without error, but may produce a broken library.
+           _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+           _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+           if test "$with_gnu_ld" = yes; then
+             # We only use this code for GNU lds that support --whole-archive.
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+           else
+             # Exported symbols can be pulled into shared objects from archives
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+           fi
+           _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+           # This is similar to how AIX traditionally builds its shared
+           # libraries.
+           _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+       if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+         # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+         # support --undefined.  This deserves some investigation.  FIXME
+         _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       else
+         _LT_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+         # FIXME: insert proper C++ library support
+         _LT_TAGVAR(ld_shlibs, $1)=no
+         ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+       case $GXX,$cc_basename in
+       ,cl* | no,cl*)
+         # Native MSVC
+         # hardcode_libdir_flag_spec is actually meaningless, as there is
+         # no search path for DLLs.
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+         _LT_TAGVAR(always_export_symbols, $1)=yes
+         _LT_TAGVAR(file_list_spec, $1)='@'
+         # Tell ltmain to make .lib files, not .a files.
+         libext=lib
+         # Tell ltmain to make .dll files, not .so files.
+         shrext_cmds=".dll"
+         # FIXME: Setting linknames here is a bad hack.
+         _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+         _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+             $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+           else
+             $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+           fi~
+           $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+           linknames='
+         # The linker will not automatically build a static lib if we build a DLL.
+         # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+         # Don't use ranlib
+         _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+         _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+           lt_tool_outputfile="@TOOL_OUTPUT@"~
+           case $lt_outputfile in
+             *.exe|*.EXE) ;;
+             *)
+               lt_outputfile="$lt_outputfile.exe"
+               lt_tool_outputfile="$lt_tool_outputfile.exe"
+               ;;
+           esac~
+           func_to_tool_file "$lt_outputfile"~
+           if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+             $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+             $RM "$lt_outputfile.manifest";
+           fi'
+         ;;
+       *)
+         # g++
+         # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+         # as there is no search path for DLLs.
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+         _LT_TAGVAR(always_export_symbols, $1)=no
+         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+         if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+           # If the export-symbols file already is a .def file (1st line
+           # is EXPORTS), use it as is; otherwise, prepend...
+           _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+             cp $export_symbols $output_objdir/$soname.def;
+           else
+             echo EXPORTS > $output_objdir/$soname.def;
+             cat $export_symbols >> $output_objdir/$soname.def;
+           fi~
+           $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+         else
+           _LT_TAGVAR(ld_shlibs, $1)=no
+         fi
+         ;;
+       esac
+       ;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+       ;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          ghcx*)
+           # Green Hills C++ Compiler
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+       # switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                            # but as the default
+                                            # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+         _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+             _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                                # but as the default
+                                                # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          aCC*)
+           case $host_cpu in
+             hppa*64*)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+               ;;
+             ia64*)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+               ;;
+             *)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+               ;;
+           esac
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+           ;;
+          *)
+           if test "$GXX" = yes; then
+             if test $with_gnu_ld = no; then
+               case $host_cpu in
+                 hppa*64*)
+                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+                   ;;
+                 ia64*)
+                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+                   ;;
+                 *)
+                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+                   ;;
+               esac
+             fi
+           else
+             # FIXME: insert proper C++ library support
+             _LT_TAGVAR(ld_shlibs, $1)=no
+           fi
+           ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+       _LT_TAGVAR(hardcode_direct, $1)=no
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+       # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+       # Instead, shared libraries are loaded at an image base (0x10000000 by
+       # default) and relocated if they conflict, which is a slow very memory
+       # consuming and fragmenting process.  To avoid this, we pick a random,
+       # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+       # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+       ;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+           # SGI C++
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+           # Archives containing C++ object files must be created using
+           # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+           # necessary to make sure instantiated templates are included
+           # in the archive.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+           ;;
+          *)
+           if test "$GXX" = yes; then
+             if test "$with_gnu_ld" = no; then
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+             else
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+             fi
+           fi
+           _LT_TAGVAR(link_all_deplibs, $1)=yes
+           ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+        case $cc_basename in
+          KCC*)
+           # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+           # KCC will only create a shared library if the output file
+           # ends with ".so" (or ".sl" for HP-UX), so rename the library
+           # to its proper name (with version) after linking.
+           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+           # Archives containing C++ object files must be created using
+           # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+           ;;
+         icpc* | ecpc* )
+           # Intel C++
+           with_gnu_ld=yes
+           # version 8.0 and above of icpc choke on multiply defined symbols
+           # if we add $predep_objects and $postdep_objects, however 7.1 and
+           # earlier do not add the objects themselves.
+           case `$CC -V 2>&1` in
+             *"Version 7."*)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+               ;;
+             *)  # Version 8.0 or newer
+               tmp_idyn=
+               case $host_cpu in
+                 ia64*) tmp_idyn=' -i_dynamic';;
+               esac
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+               ;;
+           esac
+           _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+           ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+           case `$CC -V` in
+           *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+             _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+             _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+               $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+               $RANLIB $oldlib'
+             _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+             _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+             ;;
+           *) # Version 6 and above use weak symbols
+             _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+             ;;
+           esac
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+         cxx*)
+           # Compaq C++
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+           runpath_var=LD_RUN_PATH
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+           ;;
+         xl* | mpixl* | bgxl*)
+           # IBM XL 8.0 on PPC, with GNU ld
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+           _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           if test "x$supports_anon_versioning" = xyes; then
+             _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+               cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+               echo "local: *; };" >> $output_objdir/$libname.ver~
+               $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+           fi
+           ;;
+         *)
+           case `$CC -V 2>&1 | sed 5q` in
+           *Sun\ C*)
+             # Sun C++ 5.9
+             _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+             _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+             _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+             # Not sure whether something based on
+             # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+             # would be better.
+             output_verbose_link_cmd='func_echo_all'
+
+             # Archives containing C++ object files must be created using
+             # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+             # necessary to make sure instantiated templates are included
+             # in the archive.
+             _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+             ;;
+           esac
+           ;;
+       esac
+       ;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       ;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+       ;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+         *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+       esac
+       ;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+         _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+         wlarc=
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+         _LT_TAGVAR(hardcode_direct, $1)=yes
+         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       fi
+       # Workaround some broken pre-1.5 toolchains
+       output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+       ;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+       ;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       ;;
+
+      openbsd*)
+       if test -f /usr/libexec/ld.so; then
+         _LT_TAGVAR(hardcode_direct, $1)=yes
+         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+         if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+           _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+         fi
+         output_verbose_link_cmd=func_echo_all
+       else
+         _LT_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+           # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+           # KCC will only create a shared library if the output file
+           # ends with ".so" (or ".sl" for HP-UX), so rename the library
+           # to its proper name (with version) after linking.
+           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+           # Archives containing C++ object files must be created using
+           # the KAI C++ compiler.
+           case $host in
+             osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+             *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+           esac
+           ;;
+          RCC*)
+           # Rational C++ 2.4.1
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          cxx*)
+           case $host in
+             osf3*)
+               _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+               ;;
+             *)
+               _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+                 echo "-hidden">> $lib.exp~
+                 $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+                 $RM $lib.exp'
+               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+               ;;
+           esac
+
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+           ;;
+         *)
+           if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+             _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+             case $host in
+               osf3*)
+                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+                 ;;
+               *)
+                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+                 ;;
+             esac
+
+             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+             _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+             # Commands to make compiler produce verbose output that lists
+             # what "hidden" libraries, object files and flags are used when
+             # linking a shared library.
+             output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+           else
+             # FIXME: insert proper C++ library support
+             _LT_TAGVAR(ld_shlibs, $1)=no
+           fi
+           ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+           # Sun C++ 4.x
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          lcc*)
+           # Lucid
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+           _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+           _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+             $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+           _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+           case $host_os in
+             solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+             *)
+               # The compiler driver will combine and reorder linker options,
+               # but understands `-z linker_flag'.
+               # Supported since Solaris 2.6 (maybe 2.5.1?)
+               _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+               ;;
+           esac
+           _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+           output_verbose_link_cmd='func_echo_all'
+
+           # Archives containing C++ object files must be created using
+           # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+           # necessary to make sure instantiated templates are included
+           # in the archive.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+           ;;
+          gcx*)
+           # Green Hills C++ Compiler
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+           # The C++ compiler must be used to create the archive.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+           ;;
+          *)
+           # GNU C++ compiler with Solaris linker
+           if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+             _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+             if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                 $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+               # Commands to make compiler produce verbose output that lists
+               # what "hidden" libraries, object files and flags are used when
+               # linking a shared library.
+               output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+             else
+               # g++ 2.7 appears to require `-G' NOT `-shared' on this
+               # platform.
+               _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                 $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+               # Commands to make compiler produce verbose output that lists
+               # what "hidden" libraries, object files and flags are used when
+               # linking a shared library.
+               output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+             fi
+
+             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+             case $host_os in
+               solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+               *)
+                 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+                 ;;
+             esac
+           fi
+           ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+       # Note: We can NOT use -z defs as we might desire, because we do not
+       # link with -lc, and that would cause any symbols used from libc to
+       # always be unresolved, which means just about no library would
+       # ever link correctly.  If we're not using GNU ld we use -z text
+       # though, which does catch some bad symbols but isn't as heavy-handed
+       # as -z defs.
+       _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+       _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+       _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+       _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+       _LT_TAGVAR(link_all_deplibs, $1)=yes
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+       runpath_var='LD_RUN_PATH'
+
+       case $cc_basename in
+          CC*)
+           _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+             '"$_LT_TAGVAR(old_archive_cmds, $1)"
+           _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+             '"$_LT_TAGVAR(reload_cmds, $1)"
+           ;;
+         *)
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           ;;
+       esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+           # NonStop-UX NCC 3.20
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case ${2} in
+  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case ${prev}${p} in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+        prev=$p
+        continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test "$pre_test_object_deps_done" = no; then
+        case ${prev} in
+        -L | -R)
+          # Internal compiler library paths should come after those
+          # provided the user.  The postdeps already come after the
+          # user supplied libs so there is no need to process them.
+          if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+            _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+          else
+            _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+          fi
+          ;;
+        # The "-l" case would never come before the object being
+        # linked, so don't bother handling this case.
+        esac
+       else
+        if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+          _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+        else
+          _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+        fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+        pre_test_object_deps_done=yes
+        continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+          _LT_TAGVAR(predep_objects, $1)="$p"
+        else
+          _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+        fi
+       else
+        if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+          _LT_TAGVAR(postdep_objects, $1)="$p"
+        else
+          _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+        fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC* | sunCC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+       if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+         test "$enable_shared" = yes && enable_static=no
+       fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+  CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+       if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+         test "$enable_shared" = yes && enable_static=no
+       fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([    ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary parameter first.
+    func_stripname_result=${3}
+    func_stripname_result=${func_stripname_result#"${1}"}
+    func_stripname_result=${func_stripname_result%"${2}"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+    func_split_long_opt_name=${1%%=*}
+    func_split_long_opt_arg=${1#*=}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+    func_split_short_opt_arg=${1#??}
+    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+    case ${1} in
+      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+      *)    func_lo2o_result=${1} ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
+
+  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
+
+  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+    func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
new file mode 100644 (file)
index 0000000..5d9acd8
--- /dev/null
@@ -0,0 +1,384 @@
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+           [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+                     [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+                  [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+       [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_shared=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+       [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+       [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_static=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+       [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_fast_install=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+        [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+       [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+       IFS="$lt_save_ifs"
+       if test "X$lt_pkg" = "X$lt_p"; then
+         pic_mode=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+                [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+                [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+                [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+                [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+                [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
new file mode 100644 (file)
index 0000000..9000a05
--- /dev/null
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+          m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+            [m4_foreach([_Lt_suffix],
+               ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+       [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+         [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+                [lt_append([$1], [$2], [$3])$4],
+                [$5])],
+         [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+       m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+       [$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+                     [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
new file mode 100644 (file)
index 0000000..07a8602
--- /dev/null
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers                      -*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
new file mode 100644 (file)
index 0000000..c573da9
--- /dev/null
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],  [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],             [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],        [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],         [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],    [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],           [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],             [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],    [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],           [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],       [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],               [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],        [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],    [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],    [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],         [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],            [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],  [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],             [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],            [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],    [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],   [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],          [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],            [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],           [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],  [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],    [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],          [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],          [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],                [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],     [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],          [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],   [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],           [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],           [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],           [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],  [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],      [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],    [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],    [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],    [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],     [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],         [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],       [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],        [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],                [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],        [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],   [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],              [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],               [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],              [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644 (file)
index 0000000..af1277b
--- /dev/null
@@ -0,0 +1,7 @@
+# -*- Makefile -*-
+
+dist_man8_MANS = \
+       nl-classid-lookup.8 \
+       nl-pktloc-lookup.8 \
+       nl-qdisc-add.8 nl-qdisc-delete.8 nl-qdisc-list.8 \
+       genl-ctrl-list.8
diff --git a/man/Makefile.in b/man/Makefile.in
new file mode 100644 (file)
index 0000000..69b1803
--- /dev/null
@@ -0,0 +1,502 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = man
+DIST_COMMON = $(dist_man8_MANS) $(srcdir)/Makefile.am \
+       $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+man8dir = $(mandir)/man8
+am__installdirs = "$(DESTDIR)$(man8dir)"
+NROFF = nroff
+MANS = $(dist_man8_MANS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+dist_man8_MANS = \
+       nl-classid-lookup.8 \
+       nl-pktloc-lookup.8 \
+       nl-qdisc-add.8 nl-qdisc-delete.8 nl-qdisc-list.8 \
+       genl-ctrl-list.8
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign man/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+install-man8: $(dist_man8_MANS)
+       @$(NORMAL_INSTALL)
+       @list1='$(dist_man8_MANS)'; \
+       list2=''; \
+       test -n "$(man8dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.8[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man8:
+       @$(NORMAL_UNINSTALL)
+       @list='$(dist_man8_MANS)'; test -n "$(man8dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+       @list='$(MANS)'; if test -n "$$list"; then \
+         list=`for p in $$list; do \
+           if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+           if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+         if test -n "$$list" && \
+           grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+           echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+           grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/         /' >&2; \
+           echo "       to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+           echo "       typically \`make maintainer-clean' will remove them" >&2; \
+           exit 1; \
+         else :; fi; \
+       else :; fi
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS)
+installdirs:
+       for dir in "$(DESTDIR)$(man8dir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man8
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man8
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+       distclean distclean-generic distclean-libtool distdir dvi \
+       dvi-am html html-am info info-am install install-am \
+       install-data install-data-am install-dvi install-dvi-am \
+       install-exec install-exec-am install-html install-html-am \
+       install-info install-info-am install-man install-man8 \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       uninstall uninstall-am uninstall-man uninstall-man8
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/man/genl-ctrl-list.8 b/man/genl-ctrl-list.8
new file mode 100644 (file)
index 0000000..6132475
--- /dev/null
@@ -0,0 +1,104 @@
+.TH genl\-ctrl-list 8 "20 April 2012" "libnl"
+.SH NAME
+genl\-ctrl\-list \- List available kernel-side Generic Netlink families
+.SH SYNOPSIS
+.B genl\-ctrl\-list [-d]
+
+.SH DESCRIPTION
+.PP
+Queries the Generic Netlink controller in kernel and prints a list of all
+registered Generic Netlink families including the version of the interface
+that has been registered.
+
+.SH OPTIONS
+.TP
+.BR \-\^h " or " \-\-help
+Print help text to console and exit.
+.TP
+.BR \-\^v " or " \-\-version
+Print versioning information to console and exit.
+.TP
+.BR \-\^d " or " \-\-details
+Include additional detailed information for each Generic Netlink
+family that is printed.
+
+The information includes:
+
+.RS
+.TP
+.B hdrsize N
+The size of the user specific header.
+
+.TP
+.B maxattr N
+The maximum Netlink attribute identifier expected by the interface.
+
+.TP
+.B op NAME (ID) <FLAGS>
+A list of available operations including their name, numeric identifier
+and the flags indicating the capabilities of the opertion.
+
+Available flags:
+.RS
+.TP
+.I admin-perm
+Requires administrative privileges
+
+.TP
+.I has-doit
+Command can handle request
+
+.TP
+.I has-dump
+Command can handle a dump request
+
+.TP
+.I has-policy
+Command enforces attribute validation policy
+.RE
+
+.TP
+.B grp NAME (ID)
+A list of registered multicast groups including name (if available)
+and identifier.
+.RE
+
+.RS
+.B Example:
+.RS
+0x0010 nlctrl version 2
+.RS 0
+    hdrsize 0 maxattr 7
+.RS 0
+      op GETFAMILY (0x03) <has-doit,has-dump,has-policy>
+.RS 0
+      grp notify (0x10)
+.RE
+
+
+.SH EXAMPLE
+.RS 0
+$ genl-ctrl-list 
+.RS 0
+0x0010 nlctrl version 2
+.RS 0
+0x0011 NLBL_MGMT version 3
+.RS 0
+0x0012 NLBL_CIPSOv4 version 3
+.RS 0
+0x0013 NLBL_UNLBL version 3
+.RS 0
+0x0014 acpi_event version 1
+.RS 0
+0x0015 thermal_event version 1
+.RS 0
+0x0016 VFS_DQUOT version 1
+.RS 0
+0x0017 TASKSTATS version 1
+.RS 0
+0x0018 NET_DM version 2
+
+.SH AUTHOR
+.PP
+Thomas Graf is the original author and current maintainer of libnl and
+libnl tools. Many people have contributed to it since.
diff --git a/man/nl-classid-lookup.8 b/man/nl-classid-lookup.8
new file mode 100644 (file)
index 0000000..3cf13de
--- /dev/null
@@ -0,0 +1,51 @@
+.TH nl\-classid\-lookup 8 "19 October 2010" "libnl"
+.SH NAME
+nl\-classid\-lookup - Lookup classid definitions
+.SH SYNOPSIS
+.B nl\-classid\-lookup
+.RB [ \-hv ]
+.RB [ \-r ]
+.RB [ \-\-raw ]
+.I name
+
+.SH DESCRIPTION
+.PP
+nl\-classid\-lookup searches the classid database for a matching entry. It is used
+to resolve qdisc/class names to classid values and vice versa.
+
+.SH OPTIONS
+.TP
+.BR \-\^h " or " \-\-help
+Print help text to console and exit.
+.TP
+.BR \-\^v " or " \-\-version
+Print versioning information to console and exit.
+.TP
+.BR \-\^r " or " \-\-reverse
+Do a reverse lookup. Lookup a classid and print its name.
+.TP
+.B \-\-raw
+Print the raw classid in hexadecimal format, do not pretty print it.
+
+.SH USAGE
+.PP
+Resolve the qdisc/class name "interactive":
+.PP
+.RS
+# nl\-classid\-lookup interactive
+.RE
+.PP
+Lookup the name of classid 1:2:
+.PP
+.RS
+# nl\-classid\-lookup -r 1:2
+.RE
+
+.SH FILES
+.PP
+/etc/libnl/classid
+
+.SH AUTHOR
+.PP
+Thomas Graf is the original author and current maintainer of libnl and
+libnl tools. Many people have contributed to it since.
diff --git a/man/nl-pktloc-lookup.8 b/man/nl-pktloc-lookup.8
new file mode 100644 (file)
index 0000000..7a1daa4
--- /dev/null
@@ -0,0 +1,48 @@
+.TH nl\-pktloc-lookup 8 "27 October 2010" "libnl"
+.SH NAME
+nl\-pktloc\-lookup - Lookup packet location definitions
+.SH SYNOPSIS
+.B nl\-pktloc\-lookup
+.I name
+.br
+.B nl\-pktloc\-lookup \-\-list
+
+.SH DESCRIPTION
+.PP
+nl\-pktloc\-lookup searches the packet location database for a matching
+entry. It is used to resolve packet location aliases to their definition,
+i.e. alignment, layer, offset, and mask.
+
+.SH OPTIONS
+.TP
+.BR \-\^h " or " \-\-help
+Print help text to console and exit.
+.TP
+.BR \-\^v " or " \-\-version
+Print versioning information to console and exit.
+.TP
+.BR \-\^l " or " \-\-list
+List all packet location definitions.
+.TP
+.BR \-\-u32=VALUE
+Prints the packet location definition in a special format that is
+understood by iproute2's u32 selector parser. It will output a
+u32 selector which will compare the provided value with the value
+specified by the packet location.
+
+Please note that due to the limitation of u32, it is not possible
+to use packet locations based on the link layer. nl-pktloc-lookup
+will print an error message in this case.
+
+Example:
+  selector=$(nl-pktloc-lookup --u32 22 tcp.sport)
+  tc filter add [...] u32 match $(selector) flowid 1:2
+
+.SH FILES
+.PP
+/etc/libnl/pktloc
+
+.SH AUTHOR
+.PP
+Thomas Graf is the original author and current maintainer of libnl and
+libnl tools. Many people have contributed to it since.
diff --git a/man/nl-qdisc-add.8 b/man/nl-qdisc-add.8
new file mode 100644 (file)
index 0000000..bc3fb17
--- /dev/null
@@ -0,0 +1,118 @@
+.TH nl\-qdisc 8 "21 October 2010" "libnl"
+.SH NAME
+nl\-qdisc\-{add|list|delete} - Manage queueing disciplines
+.SH SYNOPSIS
+.B nl\-qdisc\-add \-\-dev
+.I dev
+.B \-\-parent
+.I id
+.B [OPTIONS]
+.I qdisc-type
+.B [QDISC]
+.sp
+.B nl\-qdisc\-delete [ \-\-interactive ] [OPTIONS]
+.sp
+.B nl\-qdisc\-list [OPTIONS]
+
+.SH DESCRIPTION
+.PP
+The nl\-qdisc tools allow to manage and configure queueing disciplines
+(qdiscs) in the kernel.
+
+.SH OPTIONS
+.TP
+.BR \-\^h " or " \-\-help
+Print help text to console and exit.
+.TP
+.BR \-\^v " or " \-\-version
+Print versioning information to console and exit.
+.TP
+.BR \-\^q " or " \-\-quiet
+Do not print informal notifications about actions taken to the console.
+By default a short description of each qdisc added/update/deleted will
+be printed to the console. This option disables this behaviour.
+.TP
+.BR \-\^d " or " \-\-dev "=DEV"
+Network device the qdisc is attached to.
+.TP
+.BR \-\^p " or " \-\-parent "=ID"
+Identifier of the parent qdisc/class this qdisc is attached to. The
+identifier can be specified as classid, name or one of the special
+values "root" or "ingress".
+.TP
+.BR \-\^i " or " \-\-id "=ID"
+Identifier of qdisc. It can be specified as classid or name.
+
+.SS nl\-qdisc\-add Options
+.TP
+.B \-\-update
+Update qdisc if it already exists, otherwise attempting to add a qdisc which already
+exists will result in an error. This does not include changing the type of the qdisc,
+use \-\-replace if you wish to do so.
+.TP
+.B \-\-replace
+Replace or update qdisc if it already exists. Same behaviour as \-\-update but will
+completely replace the qdisc if it exists already.
+.TP
+.B \-\-update\-only
+Update an existing qdisc but do not create it if it does not exist.
+.TP
+.B \-\-replace\-only
+Update or replace an existing qdisc but do not create it if it does exist.
+
+.SS nl\-qdisc\-delete Options
+.TP
+.B \-\-interactive
+The interactive mode requires confirmation by the user for each qdisc deleted. It
+will print a prompt for each qdisc matching the provided filter and requires the
+user to answer 'y'es or 'n'o.
+.TP
+.B \-\-yes
+Make the default answer for interactive prompts be 'y'es. This option is also
+required to delete all qdiscs on all network devices.
+.TP
+.BR \-\^k " or " \-\-kind "=TYPE"
+Only delete qdiscs of this type.
+
+.SS nl\-qdisc\-list Options
+.TP
+.B \-\-details
+Show detailed information for each qdisc listed.
+.TP
+.B \-\-stats
+Show statistics information for each qdisc listed. This option will also turn
+on detailed information automatically.
+.TP
+.BR \-\^r " or " \-\-recursive
+List all TC objects recurisvely attached to all qdiscs matching the filter.
+.TP
+.BR \-\^k " or " \-\-kind "=TYPE"
+Only list qdiscs of this type.
+
+.SH USAGE
+.PP
+Add a HTB root qdisc with id "5:":
+.PP
+.RS
+nl\-qdisc\-add \-\-dev eth0 \-\-parent root \-\-id 5: htb
+.RE
+.PP
+List all qdiscs on eth0 and print statistical data:
+.PP
+.RS
+nl\-qdisc\-list \-\-stats \-\-dev eth0
+.RE
+.PP
+Delete the qdisc "5:":
+.RS
+nl\-qdisc\-delete \-\-id 5:
+.RE
+
+.SH "SEE ALSO"
+.PP
+.B nl\-classid\-lookup(8)
+
+.SH AUTHOR
+.PP
+Thomas Graf is the original author and current maintainer of libnl and
+libnl tools. Many people have contributed to it since.
diff --git a/man/nl-qdisc-delete.8 b/man/nl-qdisc-delete.8
new file mode 100644 (file)
index 0000000..864a4e0
--- /dev/null
@@ -0,0 +1 @@
+.so man8/nl-qdisc-add.8
diff --git a/man/nl-qdisc-list.8 b/man/nl-qdisc-list.8
new file mode 100644 (file)
index 0000000..864a4e0
--- /dev/null
@@ -0,0 +1 @@
+.so man8/nl-qdisc-add.8
diff --git a/python/Makefile.am b/python/Makefile.am
new file mode 100644 (file)
index 0000000..bd5ac11
--- /dev/null
@@ -0,0 +1,3 @@
+# -*- Makefile -*-
+
+SUBDIRS = netlink
diff --git a/python/Makefile.in b/python/Makefile.in
new file mode 100644 (file)
index 0000000..ba2d070
--- /dev/null
@@ -0,0 +1,607 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = python
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(srcdir)/setup.py.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES = setup.py
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+       $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+       distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = netlink
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign python/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign python/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+setup.py: $(top_builddir)/config.status $(srcdir)/setup.py.in
+       cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+       install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am check check-am clean clean-generic clean-libtool \
+       ctags ctags-recursive distclean distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs installdirs-am maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic \
+       mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+       uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/python/README b/python/README
new file mode 100644 (file)
index 0000000..4ccc337
--- /dev/null
@@ -0,0 +1,12 @@
+
+***************************************************************************
+
+NOTE: The python wrapper is experimental and may or may not work.
+
+***************************************************************************
+
+For the brave:
+
+  (requires an installed libnl)
+  - $ python ./setup.py build
+  - $ sudo python ./setup.py install
diff --git a/python/netlink/Makefile.am b/python/netlink/Makefile.am
new file mode 100644 (file)
index 0000000..0f1045b
--- /dev/null
@@ -0,0 +1,10 @@
+# -*- Makefile -*-
+
+SUBDIRS = route
+
+EXTRA_DIST = \
+       capi.i \
+       fixes.h \
+       __init__.py \
+       core.py \
+       util.py
diff --git a/python/netlink/Makefile.in b/python/netlink/Makefile.in
new file mode 100644 (file)
index 0000000..60f6672
--- /dev/null
@@ -0,0 +1,611 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = python/netlink
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+       $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+       distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = route
+EXTRA_DIST = \
+       capi.i \
+       fixes.h \
+       __init__.py \
+       core.py \
+       util.py
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign python/netlink/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign python/netlink/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+       install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am check check-am clean clean-generic clean-libtool \
+       ctags ctags-recursive distclean distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs installdirs-am maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic \
+       mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+       uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/python/netlink/__init__.py b/python/netlink/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/python/netlink/capi.i b/python/netlink/capi.i
new file mode 100644 (file)
index 0000000..73c4bf3
--- /dev/null
@@ -0,0 +1,454 @@
+%module capi
+%{
+#include <netlink/netlink.h>
+#include <netlink/types.h>
+#include <netlink/socket.h>
+#include <netlink/msg.h>
+#include <netlink/object.h>
+#include <netlink/cache.h>
+%}
+
+%include <stdint.i>
+%include <cstring.i>
+
+%inline %{
+        struct nl_dump_params *alloc_dump_params(void)
+        {
+                struct nl_dump_params *dp;
+                if (!(dp = calloc(1, sizeof(*dp))))
+                        return NULL;
+                dp->dp_fd = stdout;
+                return dp;
+        }
+
+        void free_dump_params(struct nl_dump_params *dp)
+        {
+                free(dp);
+        }
+%};
+
+/* <netlink/types.h> */
+
+enum nl_dump_type {
+       NL_DUMP_LINE,           /**< Dump object briefly on one line */
+       NL_DUMP_DETAILS,        /**< Dump all attributes but no statistics */
+       NL_DUMP_STATS,          /**< Dump all attributes including statistics */
+       __NL_DUMP_MAX,
+};
+
+struct nl_dump_params
+{
+       /**
+        * Specifies the type of dump that is requested.
+        */
+       enum nl_dump_type       dp_type;
+
+       /**
+        * Specifies the number of whitespaces to be put in front
+        * of every new line (indentation).
+        */
+       int                     dp_prefix;
+
+       /**
+        * Causes the cache index to be printed for each element.
+        */
+       int                     dp_print_index;
+
+       /**
+        * Causes each element to be prefixed with the message type.
+        */
+       int                     dp_dump_msgtype;
+
+       /**
+        * A callback invoked for output
+        *
+        * Passed arguments are:
+        *  - dumping parameters
+        *  - string to append to the output
+        */
+       void                    (*dp_cb)(struct nl_dump_params *, char *);
+
+       /**
+        * A callback invoked for every new line, can be used to
+        * customize the indentation.
+        *
+        * Passed arguments are:
+        *  - dumping parameters
+        *  - line number starting from 0
+        */
+       void                    (*dp_nl_cb)(struct nl_dump_params *, int);
+
+       /**
+        * User data pointer, can be used to pass data to callbacks.
+        */
+       void                    *dp_data;
+
+       /**
+        * File descriptor the dumping output should go to
+        */
+       FILE *                  dp_fd;
+
+       /**
+        * Alternatively the output may be redirected into a buffer
+        */
+       char *                  dp_buf;
+
+       /**
+        * Length of the buffer dp_buf
+        */
+       size_t                  dp_buflen;
+
+       /**
+        * PRIVATE
+        * Set if a dump was performed prior to the actual dump handler.
+        */
+       int                     dp_pre_dump;
+
+       /**
+        * PRIVATE
+        * Owned by the current caller
+        */
+       int                     dp_ivar;
+
+       unsigned int            dp_line;
+};
+
+/* <netlink/errno.h> */
+extern const char *nl_geterror(int);
+
+/* <netlink/utils.h> */
+
+extern double nl_cancel_down_bytes(unsigned long long, char **);
+extern double nl_cancel_down_bits(unsigned long long, char **);
+%cstring_output_maxsize(char *buf, size_t len)
+extern int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len);
+extern double nl_cancel_down_us(uint32_t, char **);
+
+extern long nl_size2int(const char *);
+%cstring_output_maxsize(char *buf, const size_t len)
+extern char *nl_size2str(const size_t, char *buf, const size_t len);
+extern long nl_prob2int(const char *);
+
+extern int nl_get_user_hz(void);
+extern uint32_t nl_us2ticks(uint32_t);
+extern uint32_t nl_ticks2us(uint32_t);
+extern int nl_str2msec(const char *, uint64_t *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_msec2str(uint64_t, char *buf, size_t len);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_llproto2str(int, char *buf, size_t len);
+extern int nl_str2llproto(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_ether_proto2str(int, char *buf, size_t len);
+extern int nl_str2ether_proto(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_ip_proto2str(int, char *buf, size_t len);
+extern int nl_str2ip_proto(const char *);
+
+extern void nl_new_line(struct nl_dump_params *);
+extern void nl_dump(struct nl_dump_params *, const char *, ...);
+extern void nl_dump_line(struct nl_dump_params *, const char *, ...);
+
+/* <netlink/netlink.h> */
+extern struct nl_dump_params *alloc_dump_params(void);
+extern void free_dump_params(struct nl_dump_params *);
+
+extern int nl_connect(struct nl_sock *, int);
+extern void nl_close(struct nl_sock *);
+
+/* <netlink/socket.h> */
+extern struct nl_sock *nl_socket_alloc(void);
+extern struct nl_sock *nl_socket_alloc_cb(struct nl_cb *);
+extern void nl_socket_free(struct nl_sock *);
+
+extern uint32_t nl_socket_get_local_port(const struct nl_sock *);
+extern void nl_socket_set_local_port(struct nl_sock *, uint32_t);
+
+extern uint32_t nl_socket_get_peer_port(const struct nl_sock *);
+extern void nl_socket_set_peer_port(struct nl_sock *, uint32_t);
+
+extern uint32_t nl_socket_get_peer_groups(const struct nl_sock *sk);
+extern void  nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups);
+
+extern int nl_socket_set_buffer_size(struct nl_sock *, int, int);
+
+/* <netlink/msg.h> */
+extern int                     nlmsg_size(int);
+extern int                     nlmsg_total_size(int);
+extern int                     nlmsg_padlen(int);
+
+extern void *                  nlmsg_data(const struct nlmsghdr *);
+extern int                     nlmsg_datalen(const struct nlmsghdr *);
+extern void *                  nlmsg_tail(const struct nlmsghdr *);
+
+/* attribute access */
+extern struct nlattr *   nlmsg_attrdata(const struct nlmsghdr *, int);
+extern int               nlmsg_attrlen(const struct nlmsghdr *, int);
+
+/* message parsing */
+extern int               nlmsg_valid_hdr(const struct nlmsghdr *, int);
+extern int               nlmsg_ok(const struct nlmsghdr *, int);
+extern struct nlmsghdr *  nlmsg_next(struct nlmsghdr *, int *);
+extern int               nlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
+                                     int, struct nla_policy *);
+extern struct nlattr *   nlmsg_find_attr(struct nlmsghdr *, int, int);
+extern int               nlmsg_validate(struct nlmsghdr *, int, int,
+                                        struct nla_policy *);
+
+extern struct nl_msg *   nlmsg_alloc(void);
+extern struct nl_msg *   nlmsg_alloc_size(size_t);
+extern struct nl_msg *   nlmsg_alloc_simple(int, int);
+extern void              nlmsg_set_default_size(size_t);
+extern struct nl_msg *   nlmsg_inherit(struct nlmsghdr *);
+extern struct nl_msg *   nlmsg_convert(struct nlmsghdr *);
+extern void *            nlmsg_reserve(struct nl_msg *, size_t, int);
+extern int               nlmsg_append(struct nl_msg *, void *, size_t, int);
+extern int               nlmsg_expand(struct nl_msg *, size_t);
+
+extern struct nlmsghdr *  nlmsg_put(struct nl_msg *, uint32_t, uint32_t,
+                                   int, int, int);
+extern struct nlmsghdr *  nlmsg_hdr(struct nl_msg *);
+extern void              nlmsg_get(struct nl_msg *);
+extern void              nlmsg_free(struct nl_msg *);
+
+/* attribute modification */
+extern void              nlmsg_set_proto(struct nl_msg *, int);
+extern int               nlmsg_get_proto(struct nl_msg *);
+extern size_t            nlmsg_get_max_size(struct nl_msg *);
+extern void              nlmsg_set_src(struct nl_msg *, struct sockaddr_nl *);
+extern struct sockaddr_nl *nlmsg_get_src(struct nl_msg *);
+extern void              nlmsg_set_dst(struct nl_msg *, struct sockaddr_nl *);
+extern struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *);
+extern void              nlmsg_set_creds(struct nl_msg *, struct ucred *);
+extern struct ucred *    nlmsg_get_creds(struct nl_msg *);
+
+extern char *            nl_nlmsgtype2str(int, char *, size_t);
+extern int               nl_str2nlmsgtype(const char *);
+
+extern char *            nl_nlmsg_flags2str(int, char *, size_t);
+
+extern int               nl_msg_parse(struct nl_msg *,
+                                      void (*cb)(struct nl_object *, void *),
+                                      void *);
+
+extern void            nl_msg_dump(struct nl_msg *, FILE *);
+
+%inline %{
+       struct nl_object *cast_obj(void *obj)
+        {
+                return (struct nl_object *) obj;
+        }
+
+        struct nl_object *object_alloc_name(const char *name)
+        {
+                struct nl_object *obj;
+
+                if (nl_object_alloc_name(name, &obj) < 0)
+                        return NULL;
+
+                return obj;
+        }
+%};
+
+extern struct nl_object *nl_object_alloc(struct nl_object_ops *);
+extern void nl_object_free(struct nl_object *);
+extern struct nl_object *nl_object_clone(struct nl_object *);
+extern void nl_object_get(struct nl_object *);
+extern void nl_object_put(struct nl_object *);
+extern int nl_object_shared(struct nl_object *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern void nl_object_dump_buf(struct nl_object *, char *buf, size_t len);
+
+extern void nl_object_dump(struct nl_object *, struct nl_dump_params *);
+
+extern int nl_object_identical(struct nl_object *, struct nl_object *);
+extern uint32_t nl_object_diff(struct nl_object *, struct nl_object *);
+extern int nl_object_match_filter(struct nl_object *, struct nl_object *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_object_attrs2str(struct nl_object *, uint32_t, char *buf, size_t len);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_object_attr_list(struct nl_object *, char *buf, size_t len);
+
+extern void nl_object_mark(struct nl_object *);
+extern void nl_object_unmark(struct nl_object *);
+extern int nl_object_is_marked(struct nl_object *);
+
+extern int nl_object_get_refcnt(struct nl_object *);
+
+/* <netlink/cache.h> */
+
+typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *);
+
+%inline %{
+        struct nl_cache *alloc_cache_name(const char *name)
+        {
+                struct nl_cache *c;
+                if (nl_cache_alloc_name(name, &c) < 0)
+                        return NULL;
+                return c;
+        }
+
+        struct nl_cache_mngr *alloc_cache_mngr(struct nl_sock *sock,
+                                               int protocol, int flags)
+        {
+                struct nl_cache_mngr *mngr;
+
+                if (nl_cache_mngr_alloc(sock, protocol, flags, &mngr) < 0)
+                        return NULL;
+
+                return mngr;
+        }
+
+        struct nl_cache *cache_mngr_add(struct nl_cache_mngr *mngr,
+                                        const char *name, change_func_t func,
+                                        void *arg)
+        {
+                struct nl_cache *cache;
+
+                if (nl_cache_mngr_add(mngr, name, func, arg, &cache) < 0)
+                        return NULL;
+
+                return cache;
+        }
+%}
+
+/* Access Functions */
+extern int                     nl_cache_nitems(struct nl_cache *);
+extern int                     nl_cache_nitems_filter(struct nl_cache *,
+                                                      struct nl_object *);
+extern struct nl_cache_ops *   nl_cache_get_ops(struct nl_cache *);
+extern struct nl_object *      nl_cache_get_first(struct nl_cache *);
+extern struct nl_object *      nl_cache_get_last(struct nl_cache *);
+extern struct nl_object *      nl_cache_get_next(struct nl_object *);
+extern struct nl_object *      nl_cache_get_prev(struct nl_object *);
+
+extern struct nl_cache *       nl_cache_alloc(struct nl_cache_ops *);
+extern struct nl_cache *       nl_cache_subset(struct nl_cache *,
+                                               struct nl_object *);
+extern void                    nl_cache_clear(struct nl_cache *);
+extern void                    nl_cache_free(struct nl_cache *);
+
+/* Cache modification */
+extern int                     nl_cache_add(struct nl_cache *,
+                                            struct nl_object *);
+extern int                     nl_cache_parse_and_add(struct nl_cache *,
+                                                      struct nl_msg *);
+extern void                    nl_cache_remove(struct nl_object *);
+extern int                     nl_cache_refill(struct nl_sock *,
+                                               struct nl_cache *);
+extern int                     nl_cache_pickup(struct nl_sock *,
+                                               struct nl_cache *);
+extern int                     nl_cache_resync(struct nl_sock *,
+                                               struct nl_cache *,
+                                               change_func_t,
+                                               void *);
+extern int                     nl_cache_include(struct nl_cache *,
+                                                struct nl_object *,
+                                                change_func_t,
+                                                void *);
+extern void                    nl_cache_set_arg1(struct nl_cache *, int);
+extern void                    nl_cache_set_arg2(struct nl_cache *, int);
+
+/* General */
+extern int                     nl_cache_is_empty(struct nl_cache *);
+extern struct nl_object *      nl_cache_search(struct nl_cache *,
+                                               struct nl_object *);
+extern void                    nl_cache_mark_all(struct nl_cache *);
+
+/* Dumping */
+extern void                    nl_cache_dump(struct nl_cache *,
+                                             struct nl_dump_params *);
+extern void                    nl_cache_dump_filter(struct nl_cache *,
+                                                    struct nl_dump_params *,
+                                                    struct nl_object *);
+
+/* Iterators */
+extern void                    nl_cache_foreach(struct nl_cache *,
+                                                void (*cb)(struct nl_object *,
+                                                           void *),
+                                                void *arg);
+extern void                    nl_cache_foreach_filter(struct nl_cache *,
+                                                       struct nl_object *,
+                                                       void (*cb)(struct
+                                                                  nl_object *,
+                                                                  void *),
+                                                       void *arg);
+
+/* --- cache management --- */
+
+/* Cache type management */
+extern struct nl_cache_ops *   nl_cache_ops_lookup(const char *);
+extern struct nl_cache_ops *   nl_cache_ops_associate(int, int);
+extern struct nl_msgtype *     nl_msgtype_lookup(struct nl_cache_ops *, int);
+extern void                    nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *);
+extern int                     nl_cache_mngt_register(struct nl_cache_ops *);
+extern int                     nl_cache_mngt_unregister(struct nl_cache_ops *);
+
+/* Global cache provisioning/requiring */
+extern void                    nl_cache_mngt_provide(struct nl_cache *);
+extern void                    nl_cache_mngt_unprovide(struct nl_cache *);
+extern struct nl_cache *       nl_cache_mngt_require(const char *);
+
+struct nl_cache_mngr;
+
+#define NL_AUTO_PROVIDE                1
+
+extern int                     nl_cache_mngr_get_fd(struct nl_cache_mngr *);
+extern int                     nl_cache_mngr_poll(struct nl_cache_mngr *,
+                                                  int);
+extern int                     nl_cache_mngr_data_ready(struct nl_cache_mngr *);
+extern void                    nl_cache_mngr_free(struct nl_cache_mngr *);
+
+/* <netlink/addr.h> */
+%inline %{
+        struct nl_addr *addr_parse(const char *addr, int guess)
+        {
+                struct nl_addr *result;
+
+                if (nl_addr_parse(addr, guess, &result) < 0)
+                        return NULL;
+
+                return result;
+        }
+%};
+
+extern struct nl_addr *nl_addr_alloc(size_t);
+extern struct nl_addr *nl_addr_alloc_attr(struct nlattr *, int);
+extern struct nl_addr *nl_addr_build(int, void *, size_t);
+extern struct nl_addr *nl_addr_clone(struct nl_addr *);
+
+extern struct nl_addr *nl_addr_get(struct nl_addr *);
+extern void nl_addr_put(struct nl_addr *);
+extern int nl_addr_shared(struct nl_addr *);
+
+extern int nl_addr_cmp(struct nl_addr *, struct nl_addr *);
+extern int nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
+extern int nl_addr_iszero(struct nl_addr *);
+extern int nl_addr_valid(char *, int);
+extern int nl_addr_guess_family(struct nl_addr *);
+extern int nl_addr_fill_sockaddr(struct nl_addr *, struct sockaddr *, socklen_t *);
+extern int nl_addr_info(struct nl_addr *, struct addrinfo **);
+extern int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen);
+
+extern void nl_addr_set_family(struct nl_addr *, int);
+extern int nl_addr_get_family(struct nl_addr *);
+extern int nl_addr_set_binary_addr(struct nl_addr *, void *, size_t);
+
+extern void *nl_addr_get_binary_addr(struct nl_addr *);
+extern unsigned int nl_addr_get_len(struct nl_addr *);
+extern void nl_addr_set_prefixlen(struct nl_addr *, int);
+extern unsigned int nl_addr_get_prefixlen(struct nl_addr *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_af2str(int, char *buf, size_t len);
+extern int nl_str2af(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *nl_addr2str(struct nl_addr *, char *buf, size_t len);
diff --git a/python/netlink/core.py b/python/netlink/core.py
new file mode 100644 (file)
index 0000000..3298e2c
--- /dev/null
@@ -0,0 +1,744 @@
+#
+# Netlink interface based on libnl
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""netlink library based on libnl
+
+This module provides an interface to netlink sockets
+
+The module contains the following public classes:
+ - Socket -- The netlink socket
+ - Object -- Abstract object (based on struct nl_obect in libnl) used as
+         base class for all object types which can be put into a Cache
+ - Cache -- A collection of objects which are derived from the base
+        class Object. Used for netlink protocols which maintain a list
+        or tree of objects.
+ - DumpParams --
+
+The following exceptions are defined:
+ - NetlinkError -- Base exception for all general purpose exceptions raised.
+ - KernelError -- Raised when the kernel returns an error as response to a
+          request.
+
+All other classes or functions in this module are considered implementation
+details.
+"""
+from __future__ import absolute_import
+
+
+
+from . import capi
+import sys
+import socket
+
+__all__ = [
+    'Message',
+    'Socket',
+    'DumpParams',
+    'Object',
+    'Cache',
+    'KernelError',
+    'NetlinkError',
+]
+
+__version__ = '0.1'
+
+# netlink protocols
+NETLINK_ROUTE = 0
+# NETLINK_UNUSED = 1
+NETLINK_USERSOCK = 2
+NETLINK_FIREWALL = 3
+NETLINK_INET_DIAG = 4
+NETLINK_NFLOG = 5
+NETLINK_XFRM = 6
+NETLINK_SELINUX = 7
+NETLINK_ISCSI = 8
+NETLINK_AUDIT = 9
+NETLINK_FIB_LOOKUP = 10
+NETLINK_CONNECTOR = 11
+NETLINK_NETFILTER = 12
+NETLINK_IP6_FW = 13
+NETLINK_DNRTMSG = 14
+NETLINK_KOBJECT_UEVENT = 15
+NETLINK_GENERIC = 16
+NETLINK_SCSITRANSPORT = 18
+NETLINK_ECRYPTFS = 19
+
+NL_DONTPAD = 0
+NL_AUTO_PORT = 0
+NL_AUTO_SEQ = 0
+
+NL_DUMP_LINE = 0
+NL_DUMP_DETAILS = 1
+NL_DUMP_STATS = 2
+
+NLM_F_REQUEST = 1
+NLM_F_MULTI = 2
+NLM_F_ACK = 4
+NLM_F_ECHO = 8
+
+NLM_F_ROOT = 0x100
+NLM_F_MATCH = 0x200
+NLM_F_ATOMIC = 0x400
+NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
+
+NLM_F_REPLACE = 0x100
+NLM_F_EXCL = 0x200
+NLM_F_CREATE = 0x400
+NLM_F_APPEND = 0x800
+
+class NetlinkError(Exception):
+    def __init__(self, error):
+        self._error = error
+        self._msg = capi.nl_geterror(error)
+
+    def __str__(self):
+        return self._msg
+
+class KernelError(NetlinkError):
+    def __str__(self):
+        return 'Kernel returned: {0}'.format(self._msg)
+
+class ImmutableError(NetlinkError):
+    def __init__(self, msg):
+        self._msg = msg
+
+    def __str__(self):
+        return 'Immutable attribute: {0}'.format(self._msg)
+
+class Message(object):
+    """Netlink message"""
+
+    def __init__(self, size=0):
+        if size == 0:
+            self._msg = capi.nlmsg_alloc()
+        else:
+            self._msg = capi.nlmsg_alloc_size(size)
+
+        if self._msg is None:
+            raise Exception('Message allocation returned NULL')
+
+    def __del__(self):
+        capi.nlmsg_free(self._msg)
+
+    def __len__(self):
+        return capi.nlmsg_len(nlmsg_hdr(self._msg))
+
+    @property
+    def protocol(self):
+        return capi.nlmsg_get_proto(self._msg)
+
+    @protocol.setter
+    def protocol(self, value):
+        capi.nlmsg_set_proto(self._msg, value)
+
+    @property
+    def maxSize(self):
+        return capi.nlmsg_get_max_size(self._msg)
+
+    @property
+    def hdr(self):
+        return capi.nlmsg_hdr(self._msg)
+
+    @property
+    def data(self):
+        return capi.nlmsg_data(self._msg)
+
+    @property
+    def attrs(self):
+        return capi.nlmsg_attrdata(self._msg)
+
+    def send(self, sock):
+        sock.send(self)
+
+class Socket(object):
+    """Netlink socket"""
+
+    def __init__(self, cb=None):
+        if cb is None:
+            self._sock = capi.nl_socket_alloc()
+        else:
+            self._sock = capi.nl_socket_alloc_cb(cb)
+
+        if self._sock is None:
+            raise Exception('NULL pointer returned while allocating socket')
+
+    def __del__(self):
+        capi.nl_socket_free(self._sock)
+
+    def __str__(self):
+        return 'nlsock<{0}>'.format(self.localPort)
+
+    @property
+    def local_port(self):
+        return capi.nl_socket_get_local_port(self._sock)
+
+    @local_port.setter
+    def local_port(self, value):
+        capi.nl_socket_set_local_port(self._sock, int(value))
+
+    @property
+    def peer_port(self):
+        return capi.nl_socket_get_peer_port(self._sock)
+
+    @peer_port.setter
+    def peer_port(self, value):
+        capi.nl_socket_set_peer_port(self._sock, int(value))
+
+    @property
+    def peer_groups(self):
+        return capi.nl_socket_get_peer_groups(self._sock)
+
+    @peer_groups.setter
+    def peer_groups(self, value):
+        capi.nl_socket_set_peer_groups(self._sock, value)
+
+    def set_bufsize(self, rx, tx):
+        capi.nl_socket_set_buffer_size(self._sock, rx, tx)
+
+    def connect(self, proto):
+        capi.nl_connect(self._sock, proto)
+        return self
+
+    def disconnect(self):
+        capi.nl_close(self._sock)
+
+    def sendto(self, buf):
+        ret = capi.nl_sendto(self._sock, buf, len(buf))
+        if ret < 0:
+            raise Exception('Failed to send')
+        else:
+            return ret
+
+_sockets = {}
+
+def lookup_socket(protocol):
+    try:
+        sock = _sockets[protocol]
+    except KeyError:
+        sock = Socket()
+        sock.connect(protocol)
+        _sockets[protocol] = sock
+
+    return sock
+
+class DumpParams(object):
+    """Dumping parameters"""
+
+    def __init__(self, type_=NL_DUMP_LINE):
+        self._dp = capi.alloc_dump_params()
+        if not self._dp:
+            raise Exception('Unable to allocate struct nl_dump_params')
+
+        self._dp.dp_type = type_
+
+    def __del__(self):
+        capi.free_dump_params(self._dp)
+
+    @property
+    def type(self):
+        return self._dp.dp_type
+
+    @type.setter
+    def type(self, value):
+        self._dp.dp_type = value
+
+    @property
+    def prefix(self):
+        return self._dp.dp_prefix
+
+    @prefix.setter
+    def prefix(self, value):
+        self._dp.dp_prefix = value
+
+# underscore this to make sure it is deleted first upon module deletion
+_defaultDumpParams = DumpParams(NL_DUMP_LINE)
+
+class Object(object):
+    """Cacheable object (base class)"""
+
+    def __init__(self, obj_name, name, obj=None):
+        self._obj_name = obj_name
+        self._name = name
+        self._modules = []
+
+        if not obj:
+            obj = capi.object_alloc_name(self._obj_name)
+
+        self._nl_object = obj
+
+        # Create a clone which stores the original state to notice
+        # modifications
+        clone_obj = capi.nl_object_clone(self._nl_object)
+        self._orig = self._obj2type(clone_obj)
+
+    def __del__(self):
+        if not self._nl_object:
+            raise ValueError()
+
+        capi.nl_object_put(self._nl_object)
+
+    def __str__(self):
+        if hasattr(self, 'format'):
+            return self.format()
+        else:
+            return capi.nl_object_dump_buf(self._nl_object, 4096).rstrip()
+
+    def _new_instance(self):
+        raise NotImplementedError()
+
+    def clone(self):
+        """Clone object"""
+        return self._new_instance(capi.nl_object_clone(self._nl_object))
+
+    def _module_lookup(self, path, constructor=None):
+        """Lookup object specific module and load it
+
+        Object implementations consisting of multiple types may
+        offload some type specific code to separate modules which
+        are loadable on demand, e.g. a VLAN link or a specific
+        queueing discipline implementation.
+
+        Loads the module `path` and calls the constructor if
+        supplied or `module`.init()
+
+        The constructor/init function typically assigns a new
+        object covering the type specific implementation aspects
+        to the new object, e.g. link.vlan = VLANLink()
+        """
+        try:
+            __import__(path)
+        except ImportError:
+            return
+
+        module = sys.modules[path]
+
+        if constructor:
+            ret = getattr(module, constructor)(self)
+        else:
+            ret = module.init(self)
+
+        if ret:
+            self._modules.append(ret)
+
+    def _module_brief(self):
+        ret = ''
+
+        for module in self._modules:
+            if hasattr(module, 'brief'):
+                ret += module.brief()
+
+        return ret
+
+    def dump(self, params=None):
+        """Dump object as human readable text"""
+        if params is None:
+            params = _defaultDumpParams
+
+        capi.nl_object_dump(self._nl_object, params._dp)
+
+
+    @property
+    def mark(self):
+        return bool(capi.nl_object_is_marked(self._nl_object))
+
+    @mark.setter
+    def mark(self, value):
+        if value:
+            capi.nl_object_mark(self._nl_object)
+        else:
+            capi.nl_object_unmark(self._nl_object)
+
+    @property
+    def shared(self):
+        return capi.nl_object_shared(self._nl_object) != 0
+
+    @property
+    def attrs(self):
+        attr_list = capi.nl_object_attr_list(self._nl_object, 1024)
+        return attr_list[0].split()
+
+    @property
+    def refcnt(self):
+        return capi.nl_object_get_refcnt(self._nl_object)
+
+    # this method resolves multiple levels of sub types to allow
+    # accessing properties of subclass/subtypes (e.g. link.vlan.id)
+    def _resolve(self, attr):
+        obj = self
+        l = attr.split('.')
+        while len(l) > 1:
+            obj = getattr(obj, l.pop(0))
+        return (obj, l.pop(0))
+
+    def _setattr(self, attr, val):
+        obj, attr = self._resolve(attr)
+        return setattr(obj, attr, val)
+
+    def _hasattr(self, attr):
+        obj, attr = self._resolve(attr)
+        return hasattr(obj, attr)
+
+class ObjIterator(object):
+    def __init__(self, cache, obj):
+        self._cache = cache
+        self._nl_object = None
+
+        if not obj:
+            self._end = 1
+        else:
+            capi.nl_object_get(obj)
+            self._nl_object = obj
+            self._first = 1
+            self._end = 0
+
+    def __del__(self):
+        if self._nl_object:
+            capi.nl_object_put(self._nl_object)
+
+    def __iter__(self):
+        return self
+
+    def get_next(self):
+        return capi.nl_cache_get_next(self._nl_object)
+
+    def next(self):
+        if self._end:
+            raise StopIteration()
+
+        if self._first:
+            ret = self._nl_object
+            self._first = 0
+        else:
+            ret = self.get_next()
+            if not ret:
+                self._end = 1
+                raise StopIteration()
+
+        # return ref of previous element and acquire ref of current
+        # element to have object stay around until we fetched the
+        # next ptr
+        capi.nl_object_put(self._nl_object)
+        capi.nl_object_get(ret)
+        self._nl_object = ret
+
+        # reference used inside object
+        capi.nl_object_get(ret)
+        return self._cache._new_object(ret)
+
+
+class ReverseObjIterator(ObjIterator):
+    def get_next(self):
+        return capi.nl_cache_get_prev(self._nl_object)
+
+class Cache(object):
+    """Collection of netlink objects"""
+    def __init__(self):
+        if self.__class__ is Cache:
+            raise NotImplementedError()
+        self.arg1 = None
+        self.arg2 = None
+
+    def __del__(self):
+        capi.nl_cache_free(self._nl_cache)
+
+    def __len__(self):
+        return capi.nl_cache_nitems(self._nl_cache)
+
+    def __iter__(self):
+        obj = capi.nl_cache_get_first(self._nl_cache)
+        return ObjIterator(self, obj)
+
+    def __reversed__(self):
+        obj = capi.nl_cache_get_last(self._nl_cache)
+        return ReverseObjIterator(self, obj)
+
+    def __contains__(self, item):
+        obj = capi.nl_cache_search(self._nl_cache, item._nl_object)
+        if obj is None:
+            return False
+        else:
+            capi.nl_object_put(obj)
+            return True
+
+    # called by sub classes to allocate type specific caches by name
+    @staticmethod
+    def _alloc_cache_name(name):
+        return capi.alloc_cache_name(name)
+
+    # implemented by sub classes, must return new instasnce of cacheable
+    # object
+    @staticmethod
+    def _new_object(obj):
+        raise NotImplementedError()
+
+    # implemented by sub classes, must return instance of sub class
+    def _new_cache(self, cache):
+        raise NotImplementedError()
+
+    def subset(self, filter_):
+        """Return new cache containing subset of cache
+
+        Cretes a new cache containing all objects which match the
+        specified filter.
+        """
+        if not filter_:
+            raise ValueError()
+
+        c = capi.nl_cache_subset(self._nl_cache, filter_._nl_object)
+        return self._new_cache(cache=c)
+
+    def dump(self, params=None, filter_=None):
+        """Dump (print) cache as human readable text"""
+        if not params:
+            params = _defaultDumpParams
+
+        if filter_:
+            filter_ = filter_._nl_object
+
+        capi.nl_cache_dump_filter(self._nl_cache, params._dp, filter_)
+
+    def clear(self):
+        """Remove all cache entries"""
+        capi.nl_cache_clear(self._nl_cache)
+
+    # Called by sub classes to set first cache argument
+    def _set_arg1(self, arg):
+        self.arg1 = arg
+        capi.nl_cache_set_arg1(self._nl_cache, arg)
+
+    # Called by sub classes to set second cache argument
+    def _set_arg2(self, arg):
+        self.arg2 = arg
+        capi.nl_cache_set_arg2(self._nl_cache, arg)
+
+    def refill(self, socket=None):
+        """Clear cache and refill it"""
+        if socket is None:
+            socket = lookup_socket(self._protocol)
+
+        capi.nl_cache_refill(socket._sock, self._nl_cache)
+        return self
+
+    def resync(self, socket=None, cb=None):
+        """Synchronize cache with content in kernel"""
+        if socket is None:
+            socket = lookup_socket(self._protocol)
+
+        capi.nl_cache_resync(socket._sock, self._nl_cache, cb)
+
+    def provide(self):
+        """Provide this cache to others
+
+        Caches which have been "provided" are made available
+        to other users (of the same application context) which
+        "require" it. F.e. a link cache is generally provided
+        to allow others to translate interface indexes to
+        link names
+        """
+
+        capi.nl_cache_mngt_provide(self._nl_cache)
+
+    def unprovide(self):
+        """Unprovide this cache
+
+        No longer make the cache available to others. If the cache
+        has been handed out already, that reference will still
+        be valid.
+        """
+        capi.nl_cache_mngt_unprovide(self._nl_cache)
+
+# Cache Manager (Work in Progress)
+NL_AUTO_PROVIDE = 1
+class CacheManager(object):
+    def __init__(self, protocol, flags=None):
+
+        self._sock = Socket()
+        self._sock.connect(protocol)
+
+        if not flags:
+            flags = NL_AUTO_PROVIDE
+
+        self._mngr = capi.cache_mngr_alloc(self._sock._sock, protocol, flags)
+
+    def __del__(self):
+        if self._sock:
+            self._sock.disconnect()
+
+        if self._mngr:
+            capi.nl_cache_mngr_free(self._mngr)
+
+    def add(self, name):
+        capi.cache_mngr_add(self._mngr, name, None, None)
+
+class AddressFamily(object):
+    """Address family representation
+
+    af = AddressFamily('inet6')
+    # raises:
+    #   - ValueError if family name is not known
+    #   - TypeError if invalid type is specified for family
+
+    print af        # => 'inet6' (string representation)
+    print int(af)   # => 10 (numeric representation)
+    print repr(af)  # => AddressFamily('inet6')
+    """
+    def __init__(self, family=socket.AF_UNSPEC):
+        if isinstance(family, str):
+            family = capi.nl_str2af(family)
+            if family < 0:
+                raise ValueError('Unknown family name')
+        elif not isinstance(family, int):
+            raise TypeError()
+
+        self._family = family
+
+    def __str__(self):
+        return capi.nl_af2str(self._family, 32)[0]
+
+    def __int__(self):
+        return self._family
+
+    def __repr__(self):
+        return 'AddressFamily({0!r})'.format(str(self))
+
+
+class AbstractAddress(object):
+    """Abstract address object
+
+    addr = AbstractAddress('127.0.0.1/8')
+    print addr               # => '127.0.0.1/8'
+    print addr.prefixlen     # => '8'
+    print addr.family        # => 'inet'
+    print len(addr)          # => '4' (32bit ipv4 address)
+
+    a = AbstractAddress('10.0.0.1/24')
+    b = AbstractAddress('10.0.0.2/24')
+    print a == b             # => False
+
+
+    """
+    def __init__(self, addr):
+        self._nl_addr = None
+
+        if isinstance(addr, str):
+            addr = capi.addr_parse(addr, socket.AF_UNSPEC)
+            if addr is None:
+                raise ValueError('Invalid address format')
+        elif addr:
+            capi.nl_addr_get(addr)
+
+        self._nl_addr = addr
+
+    def __del__(self):
+        if self._nl_addr:
+            capi.nl_addr_put(self._nl_addr)
+
+    def __cmp__(self, other):
+        if isinstance(other, str):
+            other = AbstractAddress(other)
+
+        diff = self.prefixlen - other.prefixlen
+        if diff == 0:
+            diff = capi.nl_addr_cmp(self._nl_addr, other._nl_addr)
+
+        return diff
+
+    def contains(self, item):
+        diff = int(self.family) - int(item.family)
+        if diff:
+            return False
+
+        if item.prefixlen < self.prefixlen:
+            return False
+
+        diff = capi.nl_addr_cmp_prefix(self._nl_addr, item._nl_addr)
+        return diff == 0
+
+    def __nonzero__(self):
+        if self._nl_addr:
+            return not capi.nl_addr_iszero(self._nl_addr)
+        else:
+            return False
+
+    def __len__(self):
+        if self._nl_addr:
+            return capi.nl_addr_get_len(self._nl_addr)
+        else:
+            return 0
+
+    def __str__(self):
+        if self._nl_addr:
+            return capi.nl_addr2str(self._nl_addr, 64)[0]
+        else:
+            return 'none'
+
+    @property
+    def shared(self):
+        """True if address is shared (multiple users)"""
+        if self._nl_addr:
+            return capi.nl_addr_shared(self._nl_addr) != 0
+        else:
+            return False
+
+    @property
+    def prefixlen(self):
+        """Length of prefix (number of bits)"""
+        if self._nl_addr:
+            return capi.nl_addr_get_prefixlen(self._nl_addr)
+        else:
+            return 0
+
+    @prefixlen.setter
+    def prefixlen(self, value):
+        if not self._nl_addr:
+            raise TypeError()
+
+        capi.nl_addr_set_prefixlen(self._nl_addr, int(value))
+
+    @property
+    def family(self):
+        """Address family"""
+        f = 0
+        if self._nl_addr:
+            f = capi.nl_addr_get_family(self._nl_addr)
+
+        return AddressFamily(f)
+
+    @family.setter
+    def family(self, value):
+        if not self._nl_addr:
+            raise TypeError()
+
+        if not isinstance(value, AddressFamily):
+            value = AddressFamily(value)
+
+        capi.nl_addr_set_family(self._nl_addr, int(value))
+
+
+# keyword:
+#   type = { int | str }
+#   immutable = { True | False }
+#   fmt = func (formatting function)
+#   title = string
+
+def nlattr(**kwds):
+    """netlink object attribute decorator
+
+    decorator used to mark mutable and immutable properties
+    of netlink objects. All properties marked as such are
+    regarded to be accessable.
+
+    @property
+    @netlink.nlattr(type=int)
+    def my_attr(self):
+        return self._my_attr
+
+    """
+
+    def wrap_fn(func):
+        func.formatinfo = kwds
+        return func
+    return wrap_fn
diff --git a/python/netlink/fixes.h b/python/netlink/fixes.h
new file mode 100644 (file)
index 0000000..9a6118b
--- /dev/null
@@ -0,0 +1 @@
+#include <stdint.h>
diff --git a/python/netlink/route/Makefile.am b/python/netlink/route/Makefile.am
new file mode 100644 (file)
index 0000000..ef714f4
--- /dev/null
@@ -0,0 +1,14 @@
+# -*- Makefile -*-
+
+EXTRA_DIST = \
+       capi.i \
+       __init__.py \
+       address.py \
+       link.py \
+       tc.py \
+       links/__init__.py \
+       links/dummy.py \
+       links/inet.py \
+       links/vlan.py \
+       qdisc/__init__.py \
+       qdisc/htb.py
diff --git a/python/netlink/route/Makefile.in b/python/netlink/route/Makefile.in
new file mode 100644 (file)
index 0000000..7ea4d10
--- /dev/null
@@ -0,0 +1,417 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = python/netlink/route
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+       capi.i \
+       __init__.py \
+       address.py \
+       link.py \
+       tc.py \
+       links/__init__.py \
+       links/dummy.py \
+       links/inet.py \
+       links/vlan.py \
+       qdisc/__init__.py \
+       qdisc/htb.py
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign python/netlink/route/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign python/netlink/route/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+       distclean distclean-generic distclean-libtool distdir dvi \
+       dvi-am html html-am info info-am install install-am \
+       install-data install-data-am install-dvi install-dvi-am \
+       install-exec install-exec-am install-html install-html-am \
+       install-info install-info-am install-man install-pdf \
+       install-pdf-am install-ps install-ps-am install-strip \
+       installcheck installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic \
+       mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/python/netlink/route/__init__.py b/python/netlink/route/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/python/netlink/route/address.py b/python/netlink/route/address.py
new file mode 100644 (file)
index 0000000..cab2a97
--- /dev/null
@@ -0,0 +1,367 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""Module providing access to network addresses
+"""
+
+from __future__ import absolute_import
+
+
+__version__ = '1.0'
+__all__ = [
+    'AddressCache',
+    'Address']
+
+import datetime
+from .. import core as netlink
+from .  import capi as capi
+from .  import link as Link
+from .. import util as util
+
+class AddressCache(netlink.Cache):
+    """Cache containing network addresses"""
+
+    def __init__(self, cache=None):
+        if not cache:
+            cache = self._alloc_cache_name('route/addr')
+
+        self._protocol = netlink.NETLINK_ROUTE
+        self._nl_cache = cache
+
+    def __getitem__(self, key):
+        # Using ifindex=0 here implies that the local address itself
+        # is unique, otherwise the first occurence is returned.
+        return self.lookup(0, key)
+
+    def lookup(self, ifindex, local):
+        if type(local) is str:
+            local = netlink.AbstractAddress(local)
+
+        addr = capi.rtnl_addr_get(self._nl_cache, ifindex,
+                      local._nl_addr)
+        if addr is None:
+            raise KeyError()
+
+        return Address._from_capi(addr)
+
+    @staticmethod
+    def _new_object(obj):
+        return Address(obj)
+
+    @staticmethod
+    def _new_cache(cache):
+        return AddressCache(cache=cache)
+
+class Address(netlink.Object):
+    """Network address"""
+
+    def __init__(self, obj=None):
+        netlink.Object.__init__(self, 'route/addr', 'address', obj)
+        self._rtnl_addr = self._obj2type(self._nl_object)
+
+    @classmethod
+    def _from_capi(cls, obj):
+        return cls(capi.addr2obj(obj))
+
+    @staticmethod
+    def _obj2type(obj):
+        return capi.obj2addr(obj)
+
+    def __cmp__(self, other):
+        # sort by:
+        #    1. network link
+        #    2. address family
+        #    3. local address (including prefixlen)
+        diff = self.ifindex - other.ifindex
+
+        if diff == 0:
+            diff = self.family - other.family
+            if diff == 0:
+                diff = capi.nl_addr_cmp(self.local, other.local)
+
+        return diff
+
+    @staticmethod
+    def _new_instance(obj):
+        return Address(obj)
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def ifindex(self):
+        """interface index"""
+        return capi.rtnl_addr_get_ifindex(self._rtnl_addr)
+
+    @ifindex.setter
+    def ifindex(self, value):
+        link = Link.resolve(value)
+        if not link:
+            raise ValueError()
+
+        self.link = link
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.string)
+    def link(self):
+        link = capi.rtnl_addr_get_link(self._rtnl_addr)
+        if not link:
+            return None
+
+        return Link.Link.from_capi(link)
+
+    @link.setter
+    def link(self, value):
+        if type(value) is str:
+            try:
+                value = Link.resolve(value)
+            except KeyError:
+                raise ValueError()
+
+        capi.rtnl_addr_set_link(self._rtnl_addr, value._rtnl_link)
+
+        # ifindex is immutable but we assume that if _orig does not
+        # have an ifindex specified, it was meant to be given here
+        if capi.rtnl_addr_get_ifindex(self._orig) == 0:
+            capi.rtnl_addr_set_ifindex(self._orig, value.ifindex)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.string)
+    def label(self):
+        """address label"""
+        return capi.rtnl_addr_get_label(self._rtnl_addr)
+
+    @label.setter
+    def label(self, value):
+        capi.rtnl_addr_set_label(self._rtnl_addr, value)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.string)
+    def flags(self):
+        """Flags
+
+        Setting this property will *Not* reset flags to value you supply in
+
+        Examples:
+        addr.flags = '+xxx' # add xxx flag
+        addr.flags = 'xxx'  # exactly the same
+        addr.flags = '-xxx' # remove xxx flag
+        addr.flags = [ '+xxx', '-yyy' ] # list operation
+        """
+        flags = capi.rtnl_addr_get_flags(self._rtnl_addr)
+        return capi.rtnl_addr_flags2str(flags, 256)[0].split(',')
+
+    def _set_flag(self, flag):
+        if flag.startswith('-'):
+            i = capi.rtnl_addr_str2flags(flag[1:])
+            capi.rtnl_addr_unset_flags(self._rtnl_addr, i)
+        elif flag.startswith('+'):
+            i = capi.rtnl_addr_str2flags(flag[1:])
+            capi.rtnl_addr_set_flags(self._rtnl_addr, i)
+        else:
+            i = capi.rtnl_addr_str2flags(flag)
+            capi.rtnl_addr_set_flags(self._rtnl_addr, i)
+
+    @flags.setter
+    def flags(self, value):
+        if type(value) is list:
+            for flag in value:
+                self._set_flag(flag)
+        else:
+            self._set_flag(value)
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def family(self):
+        """Address family"""
+        fam = capi.rtnl_addr_get_family(self._rtnl_addr)
+        return netlink.AddressFamily(fam)
+
+    @family.setter
+    def family(self, value):
+        if not isinstance(value, netlink.AddressFamily):
+            value = netlink.AddressFamily(value)
+
+        capi.rtnl_addr_set_family(self._rtnl_addr, int(value))
+
+    @property
+    @netlink.nlattr(type=int, fmt=util.num)
+    def scope(self):
+        """Address scope"""
+        scope = capi.rtnl_addr_get_scope(self._rtnl_addr)
+        return capi.rtnl_scope2str(scope, 32)[0]
+
+    @scope.setter
+    def scope(self, value):
+        if type(value) is str:
+            value = capi.rtnl_str2scope(value)
+        capi.rtnl_addr_set_scope(self._rtnl_addr, value)
+
+    @property
+    @netlink.nlattr(type=str, immutable=True, fmt=util.addr)
+    def local(self):
+        """Local address"""
+        a = capi.rtnl_addr_get_local(self._rtnl_addr)
+        return netlink.AbstractAddress(a)
+
+    @local.setter
+    def local(self, value):
+        a = netlink.AbstractAddress(value)
+        capi.rtnl_addr_set_local(self._rtnl_addr, a._nl_addr)
+
+        # local is immutable but we assume that if _orig does not
+        # have a local address specified, it was meant to be given here
+        if capi.rtnl_addr_get_local(self._orig) is None:
+            capi.rtnl_addr_set_local(self._orig, a._nl_addr)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.addr)
+    def peer(self):
+        """Peer address"""
+        a = capi.rtnl_addr_get_peer(self._rtnl_addr)
+        return netlink.AbstractAddress(a)
+
+    @peer.setter
+    def peer(self, value):
+        a = netlink.AbstractAddress(value)
+        capi.rtnl_addr_set_peer(self._rtnl_addr, a._nl_addr)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.addr)
+    def broadcast(self):
+        """Broadcast address"""
+        a = capi.rtnl_addr_get_broadcast(self._rtnl_addr)
+        return netlink.AbstractAddress(a)
+
+    @broadcast.setter
+    def broadcast(self, value):
+        a = netlink.AbstractAddress(value)
+        capi.rtnl_addr_set_broadcast(self._rtnl_addr, a._nl_addr)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.addr)
+    def multicast(self):
+        """multicast address"""
+        a = capi.rtnl_addr_get_multicast(self._rtnl_addr)
+        return netlink.AbstractAddress(a)
+
+    @multicast.setter
+    def multicast(self, value):
+        try:
+            a = netlink.AbstractAddress(value)
+        except ValueError as err:
+            raise AttributeError('multicast', err)
+
+        capi.rtnl_addr_set_multicast(self._rtnl_addr, a._nl_addr)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.addr)
+    def anycast(self):
+        """anycast address"""
+        a = capi.rtnl_addr_get_anycast(self._rtnl_addr)
+        return netlink.AbstractAddress(a)
+
+    @anycast.setter
+    def anycast(self, value):
+        a = netlink.AbstractAddress(value)
+        capi.rtnl_addr_set_anycast(self._rtnl_addr, a._nl_addr)
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def valid_lifetime(self):
+        """Valid lifetime"""
+        msecs = capi.rtnl_addr_get_valid_lifetime(self._rtnl_addr)
+        if msecs == 0xFFFFFFFF:
+            return None
+        else:
+            return datetime.timedelta(seconds=msecs)
+
+    @valid_lifetime.setter
+    def valid_lifetime(self, value):
+        capi.rtnl_addr_set_valid_lifetime(self._rtnl_addr, int(value))
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def preferred_lifetime(self):
+        """Preferred lifetime"""
+        msecs = capi.rtnl_addr_get_preferred_lifetime(self._rtnl_addr)
+        if msecs == 0xFFFFFFFF:
+            return None
+        else:
+            return datetime.timedelta(seconds=msecs)
+
+    @preferred_lifetime.setter
+    def preferred_lifetime(self, value):
+        capi.rtnl_addr_set_preferred_lifetime(self._rtnl_addr, int(value))
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def create_time(self):
+        """Creation time"""
+        hsec = capi.rtnl_addr_get_create_time(self._rtnl_addr)
+        return datetime.timedelta(milliseconds=10*hsec)
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def last_update(self):
+        """Last update"""
+        hsec = capi.rtnl_addr_get_last_update_time(self._rtnl_addr)
+        return datetime.timedelta(milliseconds=10*hsec)
+
+    def add(self, socket=None, flags=None):
+        if not socket:
+            socket = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+        if not flags:
+            flags = netlink.NLM_F_CREATE
+
+        ret = capi.rtnl_addr_add(socket._sock, self._rtnl_addr, flags)
+        if ret < 0:
+            raise netlink.KernelError(ret)
+
+    def delete(self, socket, flags=0):
+        """Attempt to delete this address in the kernel"""
+        ret = capi.rtnl_addr_delete(socket._sock, self._rtnl_addr, flags)
+        if ret < 0:
+            raise netlink.KernelError(ret)
+
+    ###################################################################
+    # private properties
+    #
+    # Used for formatting output. USE AT OWN RISK
+    @property
+    def _flags(self):
+        return ','.join(self.flags)
+
+    def format(self, details=False, stats=False, nodev=False, indent=''):
+        """Return address as formatted text"""
+        fmt = util.MyFormatter(self, indent)
+
+        buf = fmt.format('{a|local!b}')
+
+        if not nodev:
+            buf += fmt.format(' {a|ifindex}')
+
+        buf += fmt.format(' {a|scope}')
+
+        if self.label:
+            buf += fmt.format(' "{a|label}"')
+
+        buf += fmt.format(' <{a|_flags}>')
+
+        if details:
+            buf += fmt.nl('\t{t|broadcast} {t|multicast}') \
+                 + fmt.nl('\t{t|peer} {t|anycast}')
+
+            if self.valid_lifetime:
+                buf += fmt.nl('\t{s|valid-lifetime!k} '\
+                       '{a|valid_lifetime}')
+
+            if self.preferred_lifetime:
+                buf += fmt.nl('\t{s|preferred-lifetime!k} '\
+                       '{a|preferred_lifetime}')
+
+        if stats and (self.create_time or self.last_update):
+            buf += self.nl('\t{s|created!k} {a|create_time}'\
+                   ' {s|last-updated!k} {a|last_update}')
+
+        return buf
diff --git a/python/netlink/route/capi.i b/python/netlink/route/capi.i
new file mode 100644 (file)
index 0000000..8ac114b
--- /dev/null
@@ -0,0 +1,396 @@
+%module capi
+%{
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+#include <netlink/route/link/inet.h>
+
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/classifier.h>
+
+#include <netlink/route/qdisc/htb.h>
+
+#include <netlink/route/addr.h>
+%}
+
+%include <stdint.i>
+%include <cstring.i>
+
+%inline %{
+        struct nl_object *link2obj(struct rtnl_link *link)
+        {
+                return OBJ_CAST(link);
+        }
+
+        struct rtnl_link *obj2link(struct nl_object *obj)
+        {
+                return (struct rtnl_link *) obj;
+        }
+
+        struct rtnl_link *get_from_kernel(struct nl_sock *sk, int ifindex, const char *name)
+        {
+                struct rtnl_link *link;
+                if (rtnl_link_get_kernel(sk, ifindex, name, &link) < 0)
+                        return NULL;
+                return link;
+        }
+
+        uint32_t inet_get_conf(struct rtnl_link *link, const unsigned int id)
+        {
+                uint32_t result;
+
+                if (rtnl_link_inet_get_conf(link, id, &result) < 0)
+                        return 0;
+
+                return result;
+        }
+%};
+
+extern struct nl_object *link2obj(struct rtnl_link *);
+extern struct rtnl_link *obj2link(struct nl_object *);
+
+/* <netlink/route/rtnl.h> */
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *          rtnl_scope2str(int, char *buf, size_t len);
+extern int             rtnl_str2scope(const char *);
+
+/* <netlink/route/link.h> */
+
+extern struct rtnl_link *rtnl_link_alloc(void);
+
+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_build_add_request(struct rtnl_link *, int, struct nl_msg **);
+extern int rtnl_link_add(struct nl_sock *, 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_sock *, struct rtnl_link *, struct rtnl_link *, int);
+
+extern int rtnl_link_build_delete_request(const struct rtnl_link *, struct nl_msg **);
+extern int rtnl_link_delete(struct nl_sock *, const struct rtnl_link *);
+extern int rtnl_link_build_get_request(int, const char *, struct nl_msg **);
+
+extern char *rtnl_link_stat2str(int, char *, size_t);
+extern int rtnl_link_str2stat(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_flags2str(int, char *buf, size_t len);
+extern int rtnl_link_str2flags(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_operstate2str(uint8_t, char *buf, size_t len);
+extern int rtnl_link_str2operstate(const char *);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_mode2str(uint8_t, char *buf, size_t len);
+extern int rtnl_link_str2mode(const char *);
+
+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_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_txqlen(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_get_txqlen(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_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_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_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_linkmode(struct rtnl_link *, uint8_t);
+extern uint8_t rtnl_link_get_linkmode(struct rtnl_link *);
+
+extern const char *rtnl_link_get_ifalias(struct rtnl_link *);
+extern void rtnl_link_set_ifalias(struct rtnl_link *, const char *);
+
+extern int rtnl_link_get_num_vf(struct rtnl_link *, uint32_t *);
+
+extern uint64_t rtnl_link_get_stat(struct rtnl_link *, int);
+extern int rtnl_link_set_stat(struct rtnl_link *, const unsigned int, const uint64_t);
+
+extern int rtnl_link_set_type(struct rtnl_link *, const char *);
+extern char *rtnl_link_get_type(struct rtnl_link *);
+
+/* <netlink/route/link/vlan.h> */
+
+struct vlan_map
+{
+       uint32_t                vm_from;
+       uint32_t                vm_to;
+};
+
+#define VLAN_PRIO_MAX 7
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *rtnl_link_vlan_flags2str(int, char *buf, size_t len);
+extern int rtnl_link_vlan_str2flags(const char *);
+
+extern int rtnl_link_vlan_set_id(struct rtnl_link *, int);
+extern int rtnl_link_vlan_get_id(struct rtnl_link *);
+
+extern int rtnl_link_vlan_set_flags(struct rtnl_link *, unsigned int);
+extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, unsigned int);
+extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *);
+
+extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, int, uint32_t);
+extern uint32_t *rtnl_link_vlan_get_ingress_map(struct rtnl_link *);
+
+extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, uint32_t, int);
+extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, int *);
+
+/* <netlink/route/link/inet.h> */
+%cstring_output_maxsize(char *buf, size_t len)
+extern const char *rtnl_link_inet_devconf2str(int, char *buf, size_t len);
+extern unsigned int rtnl_link_inet_str2devconf(const char *);
+
+extern int rtnl_link_inet_set_conf(struct rtnl_link *, const unsigned int, uint32_t);
+
+/* <netlink/route/tc.h> */
+
+%inline %{
+        uint32_t tc_str2handle(const char *name)
+        {
+                uint32_t result;
+
+                if (rtnl_tc_str2handle(name, &result) < 0)
+                        return 0;
+
+                return result;
+        }
+%};
+
+extern void            rtnl_tc_set_ifindex(struct rtnl_tc *, int);
+extern int             rtnl_tc_get_ifindex(struct rtnl_tc *);
+extern void            rtnl_tc_set_link(struct rtnl_tc *, struct rtnl_link *);
+extern struct rtnl_link *rtnl_tc_get_link(struct rtnl_tc *);
+extern void            rtnl_tc_set_mtu(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_mtu(struct rtnl_tc *);
+extern void            rtnl_tc_set_mpu(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_mpu(struct rtnl_tc *);
+extern void            rtnl_tc_set_overhead(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_overhead(struct rtnl_tc *);
+extern void            rtnl_tc_set_linktype(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_linktype(struct rtnl_tc *);
+extern void            rtnl_tc_set_handle(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_handle(struct rtnl_tc *);
+extern void            rtnl_tc_set_parent(struct rtnl_tc *, uint32_t);
+extern uint32_t                rtnl_tc_get_parent(struct rtnl_tc *);
+extern int             rtnl_tc_set_kind(struct rtnl_tc *, const char *);
+extern char *          rtnl_tc_get_kind(struct rtnl_tc *);
+extern uint64_t                rtnl_tc_get_stat(struct rtnl_tc *, enum rtnl_tc_stat);
+
+extern int             rtnl_tc_calc_txtime(int, int);
+extern int             rtnl_tc_calc_bufsize(int, int);
+extern int             rtnl_tc_calc_cell_log(int);
+
+extern int             rtnl_tc_read_classid_file(void);
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *          rtnl_tc_handle2str(uint32_t, char *buf, size_t len);
+extern int             rtnl_classid_generate(const char *, uint32_t *, uint32_t);
+
+/* <netlink/route/qdisc.h> */
+
+%inline %{
+        struct nl_object *qdisc2obj(struct rtnl_qdisc *qdisc)
+        {
+                return OBJ_CAST(qdisc);
+        }
+
+        struct rtnl_qdisc *obj2qdisc(struct nl_object *obj)
+        {
+                return (struct rtnl_qdisc *) obj;
+        }
+
+        struct nl_object *class2obj(struct rtnl_class *cl)
+        {
+                return OBJ_CAST(cl);
+        }
+
+        struct rtnl_class *obj2class(struct nl_object *obj)
+        {
+                return (struct rtnl_class *) obj;
+        }
+
+        struct nl_object *cls2obj(struct rtnl_cls *cls)
+        {
+                return OBJ_CAST(cls);
+        }
+
+        struct rtnl_cls *obj2cls(struct nl_object *obj)
+        {
+                return (struct rtnl_cls *) obj;
+        }
+
+        struct rtnl_tc *obj2tc(struct nl_object *obj)
+        {
+                return TC_CAST(obj);
+        }
+%};
+extern struct rtnl_qdisc *
+               rtnl_qdisc_alloc(void);
+
+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_build_add_request(struct rtnl_qdisc *, int,
+                                            struct nl_msg **);
+extern int     rtnl_qdisc_add(struct nl_sock *, struct rtnl_qdisc *, int);
+
+extern int     rtnl_qdisc_build_update_request(struct rtnl_qdisc *,
+                                               struct rtnl_qdisc *,
+                                               int, struct nl_msg **);
+
+extern int     rtnl_qdisc_update(struct nl_sock *, struct rtnl_qdisc *,
+                                 struct rtnl_qdisc *, int);
+
+extern int     rtnl_qdisc_build_delete_request(struct rtnl_qdisc *,
+                                               struct nl_msg **);
+extern int     rtnl_qdisc_delete(struct nl_sock *, struct rtnl_qdisc *);
+
+/* <netlink/route/classifier.h> */
+
+extern struct rtnl_cls *rtnl_cls_alloc(void);
+extern void            rtnl_cls_put(struct rtnl_cls *);
+
+extern int             rtnl_cls_add(struct nl_sock *, struct rtnl_cls *, int);
+
+extern int             rtnl_cls_delete(struct nl_sock *, struct rtnl_cls *,
+                                       int);
+
+extern void            rtnl_cls_set_prio(struct rtnl_cls *, uint16_t);
+extern uint16_t                rtnl_cls_get_prio(struct rtnl_cls *);
+
+extern void            rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t);
+extern uint16_t                rtnl_cls_get_protocol(struct rtnl_cls *);
+
+/* <netlink/route/qdisc/htb.h> */
+
+extern uint32_t        rtnl_htb_get_rate2quantum(struct rtnl_qdisc *);
+extern int     rtnl_htb_set_rate2quantum(struct rtnl_qdisc *, uint32_t);
+extern uint32_t        rtnl_htb_get_defcls(struct rtnl_qdisc *);
+extern int     rtnl_htb_set_defcls(struct rtnl_qdisc *, uint32_t);
+
+extern uint32_t        rtnl_htb_get_prio(struct rtnl_class *);
+extern int     rtnl_htb_set_prio(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_rate(struct rtnl_class *);
+extern int     rtnl_htb_set_rate(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_ceil(struct rtnl_class *);
+extern int     rtnl_htb_set_ceil(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_rbuffer(struct rtnl_class *);
+extern int     rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_cbuffer(struct rtnl_class *);
+extern int     rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t);
+extern uint32_t        rtnl_htb_get_quantum(struct rtnl_class *);
+extern int     rtnl_htb_set_quantum(struct rtnl_class *, uint32_t);
+extern int     rtnl_htb_get_level(struct rtnl_class *);
+
+/* <netlink/route/addr.h> */
+
+%inline %{
+        struct nl_object *addr2obj(struct rtnl_addr *addr)
+        {
+                return OBJ_CAST(addr);
+        }
+
+        struct rtnl_addr *obj2addr(struct nl_object *obj)
+        {
+                return (struct rtnl_addr *) obj;
+        }
+%};
+
+extern struct rtnl_addr *rtnl_addr_alloc(void);
+
+extern struct rtnl_addr *
+               rtnl_addr_get(struct nl_cache *, int, struct nl_addr *);
+
+extern int     rtnl_addr_build_add_request(struct rtnl_addr *, int,
+                                           struct nl_msg **);
+extern int     rtnl_addr_add(struct nl_sock *, 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_sock *,
+                                struct rtnl_addr *, int);
+
+%cstring_output_maxsize(char *buf, size_t len)
+extern char *  rtnl_addr_flags2str(int, char *buf, size_t len);
+extern int     rtnl_addr_str2flags(const char *);
+
+extern int     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_link(struct rtnl_addr *, struct rtnl_link *);
+extern struct rtnl_link *
+               rtnl_addr_get_link(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_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 int     rtnl_addr_set_local(struct rtnl_addr *,
+                                           struct nl_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_broadcast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_broadcast(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_anycast(struct rtnl_addr *, struct nl_addr *);
+extern struct nl_addr *rtnl_addr_get_anycast(struct rtnl_addr *);
+
+extern uint32_t rtnl_addr_get_valid_lifetime(struct rtnl_addr *);
+extern void    rtnl_addr_set_valid_lifetime(struct rtnl_addr *, uint32_t);
+extern uint32_t rtnl_addr_get_preferred_lifetime(struct rtnl_addr *);
+extern void    rtnl_addr_set_preferred_lifetime(struct rtnl_addr *, uint32_t);
+extern uint32_t rtnl_addr_get_create_time(struct rtnl_addr *);
+extern uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *);
diff --git a/python/netlink/route/link.py b/python/netlink/route/link.py
new file mode 100644 (file)
index 0000000..36d0e9d
--- /dev/null
@@ -0,0 +1,539 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""Module providing access to network links
+
+This module provides an interface to view configured network links,
+modify them and to add and delete virtual network links.
+
+The following is a basic example:
+    import netlink.core as netlink
+    import netlink.route.link as link
+
+    sock = netlink.Socket()
+    sock.connect(netlink.NETLINK_ROUTE)
+
+    cache = link.LinkCache()   # create new empty link cache
+    cache.refill(sock)         # fill cache with all configured links
+    eth0 = cache['eth0']               # lookup link "eth0"
+    print eth0                 # print basic configuration
+
+The module contains the following public classes:
+
+  - Link -- Represents a network link. Instances can be created directly
+        via the constructor (empty link objects) or via the refill()
+        method of a LinkCache.
+  - LinkCache -- Derived from netlink.Cache, holds any number of
+         network links (Link instances). Main purpose is to keep
+         a local list of all network links configured in the
+         kernel.
+
+The following public functions exist:
+  - get_from_kernel(socket, name)
+
+"""
+
+from __future__ import absolute_import
+
+__version__ = '0.1'
+__all__ = [
+    'LinkCache',
+    'Link',
+    'get_from_kernel',
+]
+
+import socket
+from .. import core as netlink
+from .. import capi as core_capi
+from .  import capi as capi
+from .links  import inet as inet
+from .. import util as util
+
+# Link statistics definitions
+RX_PACKETS = 0
+TX_PACKETS = 1
+RX_BYTES = 2
+TX_BYTES = 3
+RX_ERRORS = 4
+TX_ERRORS = 5
+RX_DROPPED = 6
+TX_DROPPED = 7
+RX_COMPRESSED = 8
+TX_COMPRESSED = 9
+RX_FIFO_ERR = 10
+TX_FIFO_ERR = 11
+RX_LEN_ERR = 12
+RX_OVER_ERR = 13
+RX_CRC_ERR = 14
+RX_FRAME_ERR = 15
+RX_MISSED_ERR = 16
+TX_ABORT_ERR = 17
+TX_CARRIER_ERR = 18
+TX_HBEAT_ERR = 19
+TX_WIN_ERR = 20
+COLLISIONS = 21
+MULTICAST = 22
+IP6_INPKTS = 23
+IP6_INHDRERRORS = 24
+IP6_INTOOBIGERRORS = 25
+IP6_INNOROUTES = 26
+IP6_INADDRERRORS = 27
+IP6_INUNKNOWNPROTOS = 28
+IP6_INTRUNCATEDPKTS = 29
+IP6_INDISCARDS = 30
+IP6_INDELIVERS = 31
+IP6_OUTFORWDATAGRAMS = 32
+IP6_OUTPKTS = 33
+IP6_OUTDISCARDS = 34
+IP6_OUTNOROUTES = 35
+IP6_REASMTIMEOUT = 36
+IP6_REASMREQDS = 37
+IP6_REASMOKS = 38
+IP6_REASMFAILS = 39
+IP6_FRAGOKS = 40
+IP6_FRAGFAILS = 41
+IP6_FRAGCREATES = 42
+IP6_INMCASTPKTS = 43
+IP6_OUTMCASTPKTS = 44
+IP6_INBCASTPKTS = 45
+IP6_OUTBCASTPKTS = 46
+IP6_INOCTETS = 47
+IP6_OUTOCTETS = 48
+IP6_INMCASTOCTETS = 49
+IP6_OUTMCASTOCTETS = 50
+IP6_INBCASTOCTETS = 51
+IP6_OUTBCASTOCTETS = 52
+ICMP6_INMSGS = 53
+ICMP6_INERRORS = 54
+ICMP6_OUTMSGS = 55
+ICMP6_OUTERRORS = 56
+
+class LinkCache(netlink.Cache):
+    """Cache of network links"""
+
+    def __init__(self, family=socket.AF_UNSPEC, cache=None):
+        if not cache:
+            cache = self._alloc_cache_name('route/link')
+
+        self._info_module = None
+        self._protocol = netlink.NETLINK_ROUTE
+        self._nl_cache = cache
+        self._set_arg1(family)
+
+    def __getitem__(self, key):
+        if type(key) is int:
+            link = capi.rtnl_link_get(self._nl_cache, key)
+        else:
+            link = capi.rtnl_link_get_by_name(self._nl_cache, key)
+
+        if link is None:
+            raise KeyError()
+        else:
+            return Link.from_capi(link)
+
+    @staticmethod
+    def _new_object(obj):
+        return Link(obj)
+
+    def _new_cache(self, cache):
+        return LinkCache(family=self.arg1, cache=cache)
+
+class Link(netlink.Object):
+    """Network link"""
+
+    def __init__(self, obj=None):
+        netlink.Object.__init__(self, 'route/link', 'link', obj)
+        self._rtnl_link = self._obj2type(self._nl_object)
+
+        if self.type:
+            self._module_lookup('netlink.route.links.' + self.type)
+
+        self.inet = inet.InetLink(self)
+        self.af = {'inet' : self.inet }
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exc_type, exc_value, tb):
+        if exc_type is None:
+            self.change()
+        else:
+            return false
+
+    @classmethod
+    def from_capi(cls, obj):
+        return cls(capi.link2obj(obj))
+
+    @staticmethod
+    def _obj2type(obj):
+        return capi.obj2link(obj)
+
+    def __cmp__(self, other):
+        return self.ifindex - other.ifindex
+
+    @staticmethod
+    def _new_instance(obj):
+        if not obj:
+            raise ValueError()
+
+        return Link(obj)
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def ifindex(self):
+        """interface index"""
+        return capi.rtnl_link_get_ifindex(self._rtnl_link)
+
+    @ifindex.setter
+    def ifindex(self, value):
+        capi.rtnl_link_set_ifindex(self._rtnl_link, int(value))
+
+        # ifindex is immutable but we assume that if _orig does not
+        # have an ifindex specified, it was meant to be given here
+        if capi.rtnl_link_get_ifindex(self._orig) == 0:
+            capi.rtnl_link_set_ifindex(self._orig, int(value))
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.bold)
+    def name(self):
+        """Name of link"""
+        return capi.rtnl_link_get_name(self._rtnl_link)
+
+    @name.setter
+    def name(self, value):
+        capi.rtnl_link_set_name(self._rtnl_link, value)
+
+        # name is the secondary identifier, if _orig does not have
+        # the name specified yet, assume it was meant to be specified
+        # here. ifindex will always take priority, therefore if ifindex
+        # is specified as well, this will be ignored automatically.
+        if capi.rtnl_link_get_name(self._orig) is None:
+            capi.rtnl_link_set_name(self._orig, value)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.string)
+    def flags(self):
+        """Flags
+        Setting this property will *Not* reset flags to value you supply in
+        Examples:
+        link.flags = '+xxx' # add xxx flag
+        link.flags = 'xxx'  # exactly the same
+        link.flags = '-xxx' # remove xxx flag
+        link.flags = [ '+xxx', '-yyy' ] # list operation
+        """
+        flags = capi.rtnl_link_get_flags(self._rtnl_link)
+        return capi.rtnl_link_flags2str(flags, 256)[0].split(',')
+
+    def _set_flag(self, flag):
+        if flag.startswith('-'):
+            i = capi.rtnl_link_str2flags(flag[1:])
+            capi.rtnl_link_unset_flags(self._rtnl_link, i)
+        elif flag.startswith('+'):
+            i = capi.rtnl_link_str2flags(flag[1:])
+            capi.rtnl_link_set_flags(self._rtnl_link, i)
+        else:
+            i = capi.rtnl_link_str2flags(flag)
+            capi.rtnl_link_set_flags(self._rtnl_link, i)
+
+    @flags.setter
+    def flags(self, value):
+        if not (type(value) is str):
+            for flag in value:
+                self._set_flag(flag)
+        else:
+            self._set_flag(value)
+
+    @property
+    @netlink.nlattr(type=int, fmt=util.num)
+    def mtu(self):
+        """Maximum Transmission Unit"""
+        return capi.rtnl_link_get_mtu(self._rtnl_link)
+
+    @mtu.setter
+    def mtu(self, value):
+        capi.rtnl_link_set_mtu(self._rtnl_link, int(value))
+
+    @property
+    @netlink.nlattr(type=int, immutable=True, fmt=util.num)
+    def family(self):
+        """Address family"""
+        return capi.rtnl_link_get_family(self._rtnl_link)
+
+    @family.setter
+    def family(self, value):
+        capi.rtnl_link_set_family(self._rtnl_link, value)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.addr)
+    def address(self):
+        """Hardware address (MAC address)"""
+        a = capi.rtnl_link_get_addr(self._rtnl_link)
+        return netlink.AbstractAddress(a)
+
+    @address.setter
+    def address(self, value):
+        capi.rtnl_link_set_addr(self._rtnl_link, value._addr)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.addr)
+    def broadcast(self):
+        """Hardware broadcast address"""
+        a = capi.rtnl_link_get_broadcast(self._rtnl_link)
+        return netlink.AbstractAddress(a)
+
+    @broadcast.setter
+    def broadcast(self, value):
+        capi.rtnl_link_set_broadcast(self._rtnl_link, value._addr)
+
+    @property
+    @netlink.nlattr(type=str, immutable=True, fmt=util.string)
+    def qdisc(self):
+        """Name of qdisc (cannot be changed)"""
+        return capi.rtnl_link_get_qdisc(self._rtnl_link)
+
+    @qdisc.setter
+    def qdisc(self, value):
+        capi.rtnl_link_set_qdisc(self._rtnl_link, value)
+
+    @property
+    @netlink.nlattr(type=int, fmt=util.num)
+    def txqlen(self):
+        """Length of transmit queue"""
+        return capi.rtnl_link_get_txqlen(self._rtnl_link)
+
+    @txqlen.setter
+    def txqlen(self, value):
+        capi.rtnl_link_set_txqlen(self._rtnl_link, int(value))
+
+    @property
+    @netlink.nlattr(type=str, immutable=True, fmt=util.string)
+    def arptype(self):
+        """Type of link (cannot be changed)"""
+        type_ = capi.rtnl_link_get_arptype(self._rtnl_link)
+        return core_capi.nl_llproto2str(type_, 64)[0]
+
+    @arptype.setter
+    def arptype(self, value):
+        i = core_capi.nl_str2llproto(value)
+        capi.rtnl_link_set_arptype(self._rtnl_link, i)
+
+    @property
+    @netlink.nlattr(type=str, immutable=True, fmt=util.string, title='state')
+    def operstate(self):
+        """Operational status"""
+        operstate = capi.rtnl_link_get_operstate(self._rtnl_link)
+        return capi.rtnl_link_operstate2str(operstate, 32)[0]
+
+    @operstate.setter
+    def operstate(self, value):
+        i = capi.rtnl_link_str2operstate(value)
+        capi.rtnl_link_set_operstate(self._rtnl_link, i)
+
+    @property
+    @netlink.nlattr(type=str, immutable=True, fmt=util.string)
+    def mode(self):
+        """Link mode"""
+        mode = capi.rtnl_link_get_linkmode(self._rtnl_link)
+        return capi.rtnl_link_mode2str(mode, 32)[0]
+
+    @mode.setter
+    def mode(self, value):
+        i = capi.rtnl_link_str2mode(value)
+        capi.rtnl_link_set_linkmode(self._rtnl_link, i)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.string)
+    def alias(self):
+        """Interface alias (SNMP)"""
+        return capi.rtnl_link_get_ifalias(self._rtnl_link)
+
+    @alias.setter
+    def alias(self, value):
+        capi.rtnl_link_set_ifalias(self._rtnl_link, value)
+
+    @property
+    @netlink.nlattr(type=str, fmt=util.string)
+    def type(self):
+        """Link type"""
+        return capi.rtnl_link_get_type(self._rtnl_link)
+
+    @type.setter
+    def type(self, value):
+        if capi.rtnl_link_set_type(self._rtnl_link, value) < 0:
+            raise NameError('unknown info type')
+
+        self._module_lookup('netlink.route.links.' + value)
+
+    def get_stat(self, stat):
+        """Retrieve statistical information"""
+        if type(stat) is str:
+            stat = capi.rtnl_link_str2stat(stat)
+            if stat < 0:
+                raise NameError('unknown name of statistic')
+
+        return capi.rtnl_link_get_stat(self._rtnl_link, stat)
+
+    def add(self, sock=None, flags=None):
+        if not sock:
+            sock = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+        if not flags:
+            flags = netlink.NLM_F_CREATE
+
+        ret = capi.rtnl_link_add(sock._sock, self._rtnl_link, flags)
+        if ret < 0:
+            raise netlink.KernelError(ret)
+
+    def change(self, sock=None, flags=0):
+        """Commit changes made to the link object"""
+        if sock is None:
+            sock = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+        if not self._orig:
+            raise netlink.NetlinkError('Original link not available')
+        ret = capi.rtnl_link_change(sock._sock, self._orig, self._rtnl_link, flags)
+        if ret < 0:
+            raise netlink.KernelError(ret)
+
+    def delete(self, sock=None):
+        """Attempt to delete this link in the kernel"""
+        if sock is None:
+            sock = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+        ret = capi.rtnl_link_delete(sock._sock, self._rtnl_link)
+        if ret < 0:
+            raise netlink.KernelError(ret)
+
+    ###################################################################
+    # private properties
+    #
+    # Used for formatting output. USE AT OWN RISK
+    @property
+    def _state(self):
+        if 'up' in self.flags:
+            buf = util.good('up')
+            if 'lowerup' not in self.flags:
+                buf += ' ' + util.bad('no-carrier')
+        else:
+            buf = util.bad('down')
+        return buf
+
+    @property
+    def _brief(self):
+        return self._module_brief() + self._foreach_af('brief')
+
+    @property
+    def _flags(self):
+        ignore = [
+            'up',
+            'running',
+            'lowerup',
+        ]
+        return ','.join([flag for flag in self.flags if flag not in ignore])
+
+    def _foreach_af(self, name, args=None):
+        buf = ''
+        for af in self.af:
+            try:
+                func = getattr(self.af[af], name)
+                s = str(func(args))
+                if len(s) > 0:
+                    buf += ' ' + s
+            except AttributeError:
+                pass
+        return buf
+
+    def format(self, details=False, stats=False, indent=''):
+        """Return link as formatted text"""
+        fmt = util.MyFormatter(self, indent)
+
+        buf = fmt.format('{a|ifindex} {a|name} {a|arptype} {a|address} '\
+                 '{a|_state} <{a|_flags}> {a|_brief}')
+
+        if details:
+            buf += fmt.nl('\t{t|mtu} {t|txqlen} {t|weight} '\
+                      '{t|qdisc} {t|operstate}')
+            buf += fmt.nl('\t{t|broadcast} {t|alias}')
+
+            buf += self._foreach_af('details', fmt)
+
+        if stats:
+            l = [['Packets', RX_PACKETS, TX_PACKETS],
+                 ['Bytes', RX_BYTES, TX_BYTES],
+                 ['Errors', RX_ERRORS, TX_ERRORS],
+                 ['Dropped', RX_DROPPED, TX_DROPPED],
+                 ['Compressed', RX_COMPRESSED, TX_COMPRESSED],
+                 ['FIFO Errors', RX_FIFO_ERR, TX_FIFO_ERR],
+                 ['Length Errors', RX_LEN_ERR, None],
+                 ['Over Errors', RX_OVER_ERR, None],
+                 ['CRC Errors', RX_CRC_ERR, None],
+                 ['Frame Errors', RX_FRAME_ERR, None],
+                 ['Missed Errors', RX_MISSED_ERR, None],
+                 ['Abort Errors', None, TX_ABORT_ERR],
+                 ['Carrier Errors', None, TX_CARRIER_ERR],
+                 ['Heartbeat Errors', None, TX_HBEAT_ERR],
+                 ['Window Errors', None, TX_WIN_ERR],
+                 ['Collisions', None, COLLISIONS],
+                 ['Multicast', None, MULTICAST],
+                 ['', None, None],
+                 ['Ipv6:', None, None],
+                 ['Packets', IP6_INPKTS, IP6_OUTPKTS],
+                 ['Bytes', IP6_INOCTETS, IP6_OUTOCTETS],
+                 ['Discards', IP6_INDISCARDS, IP6_OUTDISCARDS],
+                 ['Multicast Packets', IP6_INMCASTPKTS, IP6_OUTMCASTPKTS],
+                 ['Multicast Bytes', IP6_INMCASTOCTETS, IP6_OUTMCASTOCTETS],
+                 ['Broadcast Packets', IP6_INBCASTPKTS, IP6_OUTBCASTPKTS],
+                 ['Broadcast Bytes', IP6_INBCASTOCTETS, IP6_OUTBCASTOCTETS],
+                 ['Delivers', IP6_INDELIVERS, None],
+                 ['Forwarded', None, IP6_OUTFORWDATAGRAMS],
+                 ['No Routes', IP6_INNOROUTES, IP6_OUTNOROUTES],
+                 ['Header Errors', IP6_INHDRERRORS, None],
+                 ['Too Big Errors', IP6_INTOOBIGERRORS, None],
+                 ['Address Errors', IP6_INADDRERRORS, None],
+                 ['Unknown Protocol', IP6_INUNKNOWNPROTOS, None],
+                 ['Truncated Packets', IP6_INTRUNCATEDPKTS, None],
+                 ['Reasm Timeouts', IP6_REASMTIMEOUT, None],
+                 ['Reasm Requests', IP6_REASMREQDS, None],
+                 ['Reasm Failures', IP6_REASMFAILS, None],
+                 ['Reasm OK', IP6_REASMOKS, None],
+                 ['Frag Created', None, IP6_FRAGCREATES],
+                 ['Frag Failures', None, IP6_FRAGFAILS],
+                 ['Frag OK', None, IP6_FRAGOKS],
+                 ['', None, None],
+                 ['ICMPv6:', None, None],
+                 ['Messages', ICMP6_INMSGS, ICMP6_OUTMSGS],
+                 ['Errors', ICMP6_INERRORS, ICMP6_OUTERRORS]]
+
+            buf += '\n\t%s%s%s%s\n' % (33 * ' ', util.title('RX'),
+                           15 * ' ', util.title('TX'))
+
+            for row in l:
+                row[0] = util.kw(row[0])
+                row[1] = self.get_stat(row[1]) if row[1] else ''
+                row[2] = self.get_stat(row[2]) if row[2] else ''
+                buf += '\t{0[0]:27} {0[1]:>16} {0[2]:>16}\n'.format(row)
+
+            buf += self._foreach_af('stats')
+
+        return buf
+
+def get(name, sock=None):
+    """Lookup Link object directly from kernel"""
+    if not name:
+        raise ValueError()
+
+    if not sock:
+        sock = netlink.lookup_socket(netlink.NETLINK_ROUTE)
+
+    link = capi.get_from_kernel(sock._sock, 0, name)
+    if not link:
+        return None
+
+    return Link.from_capi(link)
+
+_link_cache = LinkCache()
+
+def resolve(name):
+    _link_cache.refill()
+    return _link_cache[name]
diff --git a/python/netlink/route/links/__init__.py b/python/netlink/route/links/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/python/netlink/route/links/dummy.py b/python/netlink/route/links/dummy.py
new file mode 100644 (file)
index 0000000..e9491cc
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""Dummy
+
+"""
+from __future__ import absolute_import
+
+__version__ = '1.0'
+__all__ = [
+    'init',
+]
+
+
+class DummyLink(object):
+    def __init__(self, link):
+        self._rtnl_link = link
+
+    @staticmethod
+    def brief():
+        return 'dummy'
+
+def init(link):
+    link.dummy = DummyLink(link._rtnl_link)
+    return link.dummy
diff --git a/python/netlink/route/links/inet.py b/python/netlink/route/links/inet.py
new file mode 100644 (file)
index 0000000..f5f45cb
--- /dev/null
@@ -0,0 +1,158 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""IPv4
+
+"""
+
+from __future__ import absolute_import
+
+__all__ = [
+    '',
+]
+
+from ... import core as netlink
+from ..  import capi as capi
+from ... import util as util
+DEVCONF_FORWARDING = 1
+DEVCONF_MC_FORWARDING = 2
+DEVCONF_PROXY_ARP = 3
+DEVCONF_ACCEPT_REDIRECTS = 4
+DEVCONF_SECURE_REDIRECTS = 5
+DEVCONF_SEND_REDIRECTS = 6
+DEVCONF_SHARED_MEDIA = 7
+DEVCONF_RP_FILTER = 8
+DEVCONF_ACCEPT_SOURCE_ROUTE = 9
+DEVCONF_BOOTP_RELAY = 10
+DEVCONF_LOG_MARTIANS = 11
+DEVCONF_TAG = 12
+DEVCONF_ARPFILTER = 13
+DEVCONF_MEDIUM_ID = 14
+DEVCONF_NOXFRM = 15
+DEVCONF_NOPOLICY = 16
+DEVCONF_FORCE_IGMP_VERSION = 17
+DEVCONF_ARP_ANNOUNCE = 18
+DEVCONF_ARP_IGNORE = 19
+DEVCONF_PROMOTE_SECONDARIES = 20
+DEVCONF_ARP_ACCEPT = 21
+DEVCONF_ARP_NOTIFY = 22
+DEVCONF_ACCEPT_LOCAL = 23
+DEVCONF_SRC_VMARK = 24
+DEVCONF_PROXY_ARP_PVLAN = 25
+DEVCONF_MAX = DEVCONF_PROXY_ARP_PVLAN
+
+def _resolve(id):
+    if type(id) is str:
+        id = capi.rtnl_link_inet_str2devconf(id)[0]
+        if id < 0:
+            raise NameError('unknown configuration id')
+    return id
+
+class InetLink(object):
+    def __init__(self, link):
+        self._link = link
+
+    def details(self, fmt):
+        buf = fmt.nl('\n\t{0}\n\t'.format(util.title('Configuration:')))
+
+        for i in range(DEVCONF_FORWARDING, DEVCONF_MAX+1):
+            if i & 1 and i > 1:
+                buf += fmt.nl('\t')
+            txt = util.kw(capi.rtnl_link_inet_devconf2str(i, 32)[0])
+            buf += fmt.format('{0:28s} {1:12}  ', txt,
+                      self.get_conf(i))
+
+
+        return buf
+
+    def get_conf(self, id):
+        return capi.inet_get_conf(self._link._rtnl_link, _resolve(id))
+
+    def set_conf(self, id, value):
+        return capi.rtnl_link_inet_set_conf(self._link._rtnl_link,
+                        _resolve(id), int(value))
+
+    @property
+    @netlink.nlattr(type=bool, fmt=util.boolean)
+    def forwarding(self):
+        return bool(self.get_conf(DEVCONF_FORWARDING))
+
+    @forwarding.setter
+    def forwarding(self, value):
+        self.set_conf(DEVCONF_FORWARDING, int(value))
+
+
+    @property
+    @netlink.nlattr(type=bool, fmt=util.boolean)
+    def mc_forwarding(self):
+        return bool(self.get_conf(DEVCONF_MC_FORWARDING))
+
+    @mc_forwarding.setter
+    def mc_forwarding(self, value):
+        self.set_conf(DEVCONF_MC_FORWARDING, int(value))
+
+
+    @property
+    @netlink.nlattr(type=bool, fmt=util.boolean)
+    def proxy_arp(self):
+        return bool(self.get_conf(DEVCONF_PROXY_ARP))
+
+    @proxy_arp.setter
+    def proxy_arp(self, value):
+        self.set_conf(DEVCONF_PROXY_ARP, int(value))
+
+    @property
+    @netlink.nlattr(type=bool, fmt=util.boolean)
+    def accept_redirects(self):
+        return bool(self.get_conf(DEVCONF_ACCEPT_REDIRECTS))
+
+    @accept_redirects.setter
+    def accept_redirects(self, value):
+        self.set_conf(DEVCONF_ACCEPT_REDIRECTS, int(value))
+
+    @property
+    @netlink.nlattr(type=bool, fmt=util.boolean)
+    def secure_redirects(self):
+        return bool(self.get_conf(DEVCONF_SECURE_REDIRECTS))
+
+    @secure_redirects.setter
+    def secure_redirects(self, value):
+        self.set_conf(DEVCONF_SECURE_REDIRECTS, int(value))
+
+    @property
+    @netlink.nlattr(type=bool, fmt=util.boolean)
+    def send_redirects(self):
+        return bool(self.get_conf(DEVCONF_SEND_REDIRECTS))
+
+    @send_redirects.setter
+    def send_redirects(self, value):
+        self.set_conf(DEVCONF_SEND_REDIRECTS, int(value))
+
+    @property
+    @netlink.nlattr(type=bool, fmt=util.boolean)
+    def shared_media(self):
+        return bool(self.get_conf(DEVCONF_SHARED_MEDIA))
+
+    @shared_media.setter
+    def shared_media(self, value):
+        self.set_conf(DEVCONF_SHARED_MEDIA, int(value))
+
+#      IPV4_DEVCONF_RP_FILTER,
+#      IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE,
+#      IPV4_DEVCONF_BOOTP_RELAY,
+#      IPV4_DEVCONF_LOG_MARTIANS,
+#      IPV4_DEVCONF_TAG,
+#      IPV4_DEVCONF_ARPFILTER,
+#      IPV4_DEVCONF_MEDIUM_ID,
+#      IPV4_DEVCONF_NOXFRM,
+#      IPV4_DEVCONF_NOPOLICY,
+#      IPV4_DEVCONF_FORCE_IGMP_VERSION,
+#      IPV4_DEVCONF_ARP_ANNOUNCE,
+#      IPV4_DEVCONF_ARP_IGNORE,
+#      IPV4_DEVCONF_PROMOTE_SECONDARIES,
+#      IPV4_DEVCONF_ARP_ACCEPT,
+#      IPV4_DEVCONF_ARP_NOTIFY,
+#      IPV4_DEVCONF_ACCEPT_LOCAL,
+#      IPV4_DEVCONF_SRC_VMARK,
+#      IPV4_DEVCONF_PROXY_ARP_PVLAN,
diff --git a/python/netlink/route/links/vlan.py b/python/netlink/route/links/vlan.py
new file mode 100644 (file)
index 0000000..70045d5
--- /dev/null
@@ -0,0 +1,71 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""VLAN network link
+
+"""
+
+from __future__ import absolute_import
+
+
+from ... import core as netlink
+from ..  import capi as capi
+class VLANLink(object):
+    def __init__(self, link):
+        self._link = link
+
+    @property
+    @netlink.nlattr(type=int)
+    def id(self):
+        """vlan identifier"""
+        return capi.rtnl_link_vlan_get_id(self._link)
+
+    @id.setter
+    def id(self, value):
+        capi.rtnl_link_vlan_set_id(self._link, int(value))
+
+    @property
+    @netlink.nlattr(type=str)
+    def flags(self):
+        """ VLAN flags
+        Setting this property will *Not* reset flags to value you supply in
+        Examples:
+        link.flags = '+xxx' # add xxx flag
+        link.flags = 'xxx'  # exactly the same
+        link.flags = '-xxx' # remove xxx flag
+        link.flags = [ '+xxx', '-yyy' ] # list operation
+        """
+        flags = capi.rtnl_link_vlan_get_flags(self._link)
+        return capi.rtnl_link_vlan_flags2str(flags, 256)[0].split(',')
+
+    def _set_flag(self, flag):
+        if flag.startswith('-'):
+            i = capi.rtnl_link_vlan_str2flags(flag[1:])
+            capi.rtnl_link_vlan_unset_flags(self._link, i)
+        elif flag.startswith('+'):
+            i = capi.rtnl_link_vlan_str2flags(flag[1:])
+            capi.rtnl_link_vlan_set_flags(self._link, i)
+        else:
+            i = capi.rtnl_link_vlan_str2flags(flag)
+            capi.rtnl_link_vlan_set_flags(self._link, i)
+
+    @flags.setter
+    def flags(self, value):
+        if type(value) is list:
+            for flag in value:
+                self._set_flag(flag)
+        else:
+            self._set_flag(value)
+
+    ###################################################################
+    # TODO:
+    #   - ingress map
+    #   - egress map
+
+    def brief(self):
+        return 'vlan-id {0}'.format(self.id)
+
+def init(link):
+    link.vlan = VLANLink(link._link)
+    return link.vlan
diff --git a/python/netlink/route/qdisc/__init__.py b/python/netlink/route/qdisc/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/python/netlink/route/qdisc/htb.py b/python/netlink/route/qdisc/htb.py
new file mode 100644 (file)
index 0000000..d051c8d
--- /dev/null
@@ -0,0 +1,145 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""HTB qdisc
+
+"""
+
+from __future__ import absolute_import
+
+from ... import core as netlink
+from ... import util as util
+from ..  import capi as capi
+from ..  import tc as tc
+
+class HTBQdisc(object):
+    def __init__(self, qdisc):
+        self._qdisc = qdisc
+
+    @property
+    @netlink.nlattr(type=int)
+    def default_class(self):
+        return tc.Handle(capi.rtnl_htb_get_defcls(self._qdisc._rtnl_qdisc))
+
+    @default_class.setter
+    def default_class(self, value):
+        capi.rtnl_htb_set_defcls(self._qdisc._rtnl_qdisc, int(value))
+
+    @property
+    @netlink.nlattr('r2q', type=int)
+    def r2q(self):
+        return capi.rtnl_htb_get_rate2quantum(self._qdisc._rtnl_qdisc)
+
+    @r2q.setter
+    def r2q(self, value):
+        capi.rtnl_htb_get_rate2quantum(self._qdisc._rtnl_qdisc,
+                           int(value))
+
+    def brief(self):
+        fmt = util.MyFormatter(self)
+
+        ret = ' {s|default-class!k} {a|default_class}'
+
+        if self.r2q:
+            ret += ' {s|r2q!k} {a|r2q}'
+
+        return fmt.format(ret)
+
+class HTBClass(object):
+    def __init__(self, cl):
+        self._class = cl
+
+    @property
+    @netlink.nlattr(type=str)
+    def rate(self):
+        rate = capi.rtnl_htb_get_rate(self._class._rtnl_class)
+        return util.Rate(rate)
+
+    @rate.setter
+    def rate(self, value):
+        capi.rtnl_htb_set_rate(self._class._rtnl_class, int(value))
+
+    @property
+    @netlink.nlattr(type=str)
+    def ceil(self):
+        ceil = capi.rtnl_htb_get_ceil(self._class._rtnl_class)
+        return util.Rate(ceil)
+
+    @ceil.setter
+    def ceil(self, value):
+        capi.rtnl_htb_set_ceil(self._class._rtnl_class, int(value))
+
+    @property
+    @netlink.nlattr(type=str)
+    def burst(self):
+        burst = capi.rtnl_htb_get_rbuffer(self._class._rtnl_class)
+        return util.Size(burst)
+
+    @burst.setter
+    def burst(self, value):
+        capi.rtnl_htb_set_rbuffer(self._class._rtnl_class, int(value))
+
+    @property
+    @netlink.nlattr(type=str)
+    def ceil_burst(self):
+        burst = capi.rtnl_htb_get_cbuffer(self._class._rtnl_class)
+        return util.Size(burst)
+
+    @ceil_burst.setter
+    def ceil_burst(self, value):
+        capi.rtnl_htb_set_cbuffer(self._class._rtnl_class, int(value))
+
+    @property
+    @netlink.nlattr(type=int)
+    def prio(self):
+        return capi.rtnl_htb_get_prio(self._class._rtnl_class)
+
+    @prio.setter
+    def prio(self, value):
+        capi.rtnl_htb_set_prio(self._class._rtnl_class, int(value))
+
+    @property
+    @netlink.nlattr(type=int)
+    def quantum(self):
+        return capi.rtnl_htb_get_quantum(self._class._rtnl_class)
+
+    @quantum.setter
+    def quantum(self, value):
+        capi.rtnl_htb_set_quantum(self._class._rtnl_class, int(value))
+
+    @property
+    @netlink.nlattr(type=int)
+    def level(self):
+        return capi.rtnl_htb_get_level(self._class._rtnl_class)
+
+    @level.setter
+    def level(self, value):
+        capi.rtnl_htb_set_level(self._class._rtnl_class, int(value))
+
+    def brief(self):
+        fmt = util.MyFormatter(self)
+
+        ret = ' {t|prio} {t|rate}'
+
+        if self.rate != self.ceil:
+            ret += ' {s|borrow-up-to!k} {a|ceil}'
+
+        ret += ' {t|burst}'
+
+        return fmt.format(ret)
+
+    def details(self):
+        fmt = util.MyFormatter(self)
+
+        return fmt.nl('\t{t|level} {t|quantum}')
+
+def init_qdisc(qdisc):
+    qdisc.htb = HTBQdisc(qdisc)
+    return qdisc.htb
+
+def init_class(cl):
+    cl.htb = HTBClass(cl)
+    return cl.htb
+
+#extern void rtnl_htb_set_quantum(struct rtnl_class *, uint32_t quantum);
diff --git a/python/netlink/route/tc.py b/python/netlink/route/tc.py
new file mode 100644 (file)
index 0000000..0689b71
--- /dev/null
@@ -0,0 +1,595 @@
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+from __future__ import absolute_import
+
+__all__ = [
+    'TcCache',
+    'Tc',
+    'QdiscCache',
+    'Qdisc',
+    'TcClassCache',
+    'TcClass',
+]
+
+from .. import core as netlink
+from .  import capi as capi
+from .. import util as util
+from .  import link as Link
+
+TC_PACKETS = 0
+TC_BYTES = 1
+TC_RATE_BPS = 2
+TC_RATE_PPS = 3
+TC_QLEN = 4
+TC_BACKLOG = 5
+TC_DROPS = 6
+TC_REQUEUES = 7
+TC_OVERLIMITS = 9
+
+TC_H_ROOT = 0xFFFFFFFF
+TC_H_INGRESS = 0xFFFFFFF1
+
+STAT_PACKETS = 0
+STAT_BYTES = 1
+STAT_RATE_BPS = 2
+STAT_RATE_PPS = 3
+STAT_QLEN = 4
+STAT_BACKLOG = 5
+STAT_DROPS = 6
+STAT_REQUEUES = 7
+STAT_OVERLIMITS = 8
+STAT_MAX = STAT_OVERLIMITS
+
+
+class Handle(object):
+    """ Traffic control handle
+
+    Representation of a traffic control handle which uniquely identifies
+    each traffic control object in its link namespace.
+
+    handle = tc.Handle('10:20')
+    handle = tc.handle('root')
+    print int(handle)
+    print str(handle)
+    """
+    def __init__(self, val=None):
+        if type(val) is str:
+            val = capi.tc_str2handle(val)
+        elif not val:
+            val = 0
+
+        self._val = int(val)
+
+    def __cmp__(self, other):
+        if other is None:
+            other = 0
+
+        if isinstance(other, Handle):
+            return int(self) - int(other)
+        elif isinstance(other, int):
+            return int(self) - other
+        else:
+            raise TypeError()
+
+    def __int__(self):
+        return self._val
+
+    def __str__(self):
+        return capi.rtnl_tc_handle2str(self._val, 64)[0]
+
+    def isroot(self):
+        return self._val == TC_H_ROOT or self._val == TC_H_INGRESS
+
+class TcCache(netlink.Cache):
+    """Cache of traffic control object"""
+
+    def __getitem__(self, key):
+        raise NotImplementedError()
+
+class Tc(netlink.Object):
+    def __cmp__(self, other):
+        diff = self.ifindex - other.ifindex
+        if diff == 0:
+            diff = int(self.handle) - int(other.handle)
+        return diff
+
+    def _tc_module_lookup(self):
+        self._module_lookup(self._module_path + self.kind,
+                    'init_' + self._name)
+
+    @property
+    def root(self):
+        """True if tc object is a root object"""
+        return self.parent.isroot()
+
+    @property
+    def ifindex(self):
+        """interface index"""
+        return capi.rtnl_tc_get_ifindex(self._rtnl_tc)
+
+    @ifindex.setter
+    def ifindex(self, value):
+        capi.rtnl_tc_set_ifindex(self._rtnl_tc, int(value))
+
+    @property
+    def link(self):
+        link = capi.rtnl_tc_get_link(self._rtnl_tc)
+        if not link:
+            return None
+
+        return Link.Link.from_capi(link)
+
+    @link.setter
+    def link(self, value):
+        capi.rtnl_tc_set_link(self._rtnl_tc, value._link)
+
+    @property
+    def mtu(self):
+        return capi.rtnl_tc_get_mtu(self._rtnl_tc)
+
+    @mtu.setter
+    def mtu(self, value):
+        capi.rtnl_tc_set_mtu(self._rtnl_tc, int(value))
+
+    @property
+    def mpu(self):
+        return capi.rtnl_tc_get_mpu(self._rtnl_tc)
+
+    @mpu.setter
+    def mpu(self, value):
+        capi.rtnl_tc_set_mpu(self._rtnl_tc, int(value))
+
+    @property
+    def overhead(self):
+        return capi.rtnl_tc_get_overhead(self._rtnl_tc)
+
+    @overhead.setter
+    def overhead(self, value):
+        capi.rtnl_tc_set_overhead(self._rtnl_tc, int(value))
+
+    @property
+    def linktype(self):
+        return capi.rtnl_tc_get_linktype(self._rtnl_tc)
+
+    @linktype.setter
+    def linktype(self, value):
+        capi.rtnl_tc_set_linktype(self._rtnl_tc, int(value))
+
+    @property
+    @netlink.nlattr(fmt=util.handle)
+    def handle(self):
+        return Handle(capi.rtnl_tc_get_handle(self._rtnl_tc))
+
+    @handle.setter
+    def handle(self, value):
+        capi.rtnl_tc_set_handle(self._rtnl_tc, int(value))
+
+    @property
+    @netlink.nlattr(fmt=util.handle)
+    def parent(self):
+        return Handle(capi.rtnl_tc_get_parent(self._rtnl_tc))
+
+    @parent.setter
+    def parent(self, value):
+        capi.rtnl_tc_set_parent(self._rtnl_tc, int(value))
+
+    @property
+    @netlink.nlattr(fmt=util.bold)
+    def kind(self):
+        return capi.rtnl_tc_get_kind(self._rtnl_tc)
+
+    @kind.setter
+    def kind(self, value):
+        capi.rtnl_tc_set_kind(self._rtnl_tc, value)
+        self._tc_module_lookup()
+
+    def get_stat(self, id):
+        return capi.rtnl_tc_get_stat(self._rtnl_tc, id)
+
+    @property
+    def _dev(self):
+        buf = util.kw('dev') + ' '
+
+        if self.link:
+            return buf + util.string(self.link.name)
+        else:
+            return buf + util.num(self.ifindex)
+
+    def brief(self, title, nodev=False, noparent=False):
+        ret = title + ' {a|kind} {a|handle}'
+
+        if not nodev:
+            ret += ' {a|_dev}'
+
+        if not noparent:
+            ret += ' {t|parent}'
+
+        return ret + self._module_brief()
+
+    @staticmethod
+    def details():
+        return '{t|mtu} {t|mpu} {t|overhead} {t|linktype}'
+
+    @property
+    def packets(self):
+        return self.get_stat(STAT_PACKETS)
+
+    @property
+    def bytes(self):
+        return self.get_stat(STAT_BYTES)
+
+    @property
+    def qlen(self):
+        return self.get_stat(STAT_QLEN)
+
+    @staticmethod
+    def stats(fmt):
+        return fmt.nl('{t|packets} {t|bytes} {t|qlen}')
+
+class QdiscCache(netlink.Cache):
+    """Cache of qdiscs"""
+
+    def __init__(self, cache=None):
+        if not cache:
+            cache = self._alloc_cache_name('route/qdisc')
+
+        self._protocol = netlink.NETLINK_ROUTE
+        self._nl_cache = cache
+
+#      def __getitem__(self, key):
+#              if type(key) is int:
+#                        link = capi.rtnl_link_get(self._this, key)
+#                elif type(key) is str:
+#                        link = capi.rtnl_link_get_by_name(self._this, key)
+#
+#              if qdisc is None:
+#                        raise KeyError()
+#              else:
+#                        return Qdisc._from_capi(capi.qdisc2obj(qdisc))
+
+    @staticmethod
+    def _new_object(obj):
+        return Qdisc(obj)
+
+    @staticmethod
+    def _new_cache(cache):
+        return QdiscCache(cache=cache)
+
+class Qdisc(Tc):
+    """Queueing discipline"""
+
+    def __init__(self, obj=None):
+        netlink.Object.__init__(self, 'route/qdisc', 'qdisc', obj)
+        self._module_path = 'netlink.route.qdisc.'
+        self._rtnl_qdisc = self._obj2type(self._nl_object)
+        self._rtnl_tc = capi.obj2tc(self._nl_object)
+
+        if self.kind:
+            self._tc_module_lookup()
+
+    @classmethod
+    def from_capi(cls, obj):
+        return cls(capi.qdisc2obj(obj))
+
+    @staticmethod
+    def _obj2type(obj):
+        return capi.obj2qdisc(obj)
+
+    @staticmethod
+    def _new_instance(obj):
+        if not obj:
+            raise ValueError()
+
+        return Qdisc(obj)
+
+    @property
+    def childs(self):
+        ret = []
+
+        if int(self.handle):
+            ret += get_cls(self.ifindex, parent=self.handle)
+
+            if self.root:
+                ret += get_class(self.ifindex, parent=TC_H_ROOT)
+
+            ret += get_class(self.ifindex, parent=self.handle)
+
+        return ret
+
+#      def add(self, socket, flags=None):
+#              if not flags:
+#                        flags = netlink.NLM_F_CREATE
+#
+#              ret = capi.rtnl_link_add(socket._sock, self._link, flags)
+#              if ret < 0:
+#                      raise netlink.KernelError(ret)
+#
+#      def change(self, socket, flags=0):
+#              """Commit changes made to the link object"""
+#              if not self._orig:
+#                      raise NetlinkError('Original link not available')
+#              ret = capi.rtnl_link_change(socket._sock, self._orig, self._link, flags)
+#                if ret < 0:
+#                        raise netlink.KernelError(ret)
+#
+#      def delete(self, socket):
+#              """Attempt to delete this link in the kernel"""
+#              ret = capi.rtnl_link_delete(socket._sock, self._link)
+#                if ret < 0:
+#                        raise netlink.KernelError(ret)
+
+    def format(self, details=False, stats=False, nodev=False,
+           noparent=False, indent=''):
+        """Return qdisc as formatted text"""
+        fmt = util.MyFormatter(self, indent)
+
+        buf = fmt.format(self.brief('qdisc', nodev, noparent))
+
+        if details:
+            buf += fmt.nl('\t' + self.details())
+
+        if stats:
+            buf += self.stats(fmt)
+
+#              if stats:
+#                      l = [['Packets', RX_PACKETS, TX_PACKETS],
+#                           ['Bytes', RX_BYTES, TX_BYTES],
+#                           ['Errors', RX_ERRORS, TX_ERRORS],
+#                           ['Dropped', RX_DROPPED, TX_DROPPED],
+#                           ['Compressed', RX_COMPRESSED, TX_COMPRESSED],
+#                           ['FIFO Errors', RX_FIFO_ERR, TX_FIFO_ERR],
+#                           ['Length Errors', RX_LEN_ERR, None],
+#                           ['Over Errors', RX_OVER_ERR, None],
+#                           ['CRC Errors', RX_CRC_ERR, None],
+#                           ['Frame Errors', RX_FRAME_ERR, None],
+#                           ['Missed Errors', RX_MISSED_ERR, None],
+#                           ['Abort Errors', None, TX_ABORT_ERR],
+#                           ['Carrier Errors', None, TX_CARRIER_ERR],
+#                           ['Heartbeat Errors', None, TX_HBEAT_ERR],
+#                           ['Window Errors', None, TX_WIN_ERR],
+#                           ['Collisions', None, COLLISIONS],
+#                           ['Multicast', None, MULTICAST],
+#                           ['', None, None],
+#                           ['Ipv6:', None, None],
+#                           ['Packets', IP6_INPKTS, IP6_OUTPKTS],
+#                           ['Bytes', IP6_INOCTETS, IP6_OUTOCTETS],
+#                           ['Discards', IP6_INDISCARDS, IP6_OUTDISCARDS],
+#                           ['Multicast Packets', IP6_INMCASTPKTS, IP6_OUTMCASTPKTS],
+#                           ['Multicast Bytes', IP6_INMCASTOCTETS, IP6_OUTMCASTOCTETS],
+#                           ['Broadcast Packets', IP6_INBCASTPKTS, IP6_OUTBCASTPKTS],
+#                           ['Broadcast Bytes', IP6_INBCASTOCTETS, IP6_OUTBCASTOCTETS],
+#                           ['Delivers', IP6_INDELIVERS, None],
+#                           ['Forwarded', None, IP6_OUTFORWDATAGRAMS],
+#                           ['No Routes', IP6_INNOROUTES, IP6_OUTNOROUTES],
+#                           ['Header Errors', IP6_INHDRERRORS, None],
+#                           ['Too Big Errors', IP6_INTOOBIGERRORS, None],
+#                           ['Address Errors', IP6_INADDRERRORS, None],
+#                           ['Unknown Protocol', IP6_INUNKNOWNPROTOS, None],
+#                           ['Truncated Packets', IP6_INTRUNCATEDPKTS, None],
+#                           ['Reasm Timeouts', IP6_REASMTIMEOUT, None],
+#                           ['Reasm Requests', IP6_REASMREQDS, None],
+#                           ['Reasm Failures', IP6_REASMFAILS, None],
+#                           ['Reasm OK', IP6_REASMOKS, None],
+#                           ['Frag Created', None, IP6_FRAGCREATES],
+#                           ['Frag Failures', None, IP6_FRAGFAILS],
+#                           ['Frag OK', None, IP6_FRAGOKS],
+#                           ['', None, None],
+#                           ['ICMPv6:', None, None],
+#                           ['Messages', ICMP6_INMSGS, ICMP6_OUTMSGS],
+#                           ['Errors', ICMP6_INERRORS, ICMP6_OUTERRORS]]
+#
+#                      buf += '\n\t%s%s%s%s\n' % (33 * ' ', util.title('RX'),
+#                                                 15 * ' ', util.title('TX'))
+#
+#                      for row in l:
+#                              row[0] = util.kw(row[0])
+#                                row[1] = self.get_stat(row[1]) if row[1] else ''
+#                                row[2] = self.get_stat(row[2]) if row[2] else ''
+#                              buf += '\t{0:27} {1:>16} {2:>16}\n'.format(*row)
+
+        return buf
+
+class TcClassCache(netlink.Cache):
+    """Cache of traffic classes"""
+
+    def __init__(self, ifindex, cache=None):
+        if not cache:
+            cache = self._alloc_cache_name('route/class')
+
+        self._protocol = netlink.NETLINK_ROUTE
+        self._nl_cache = cache
+        self._set_arg1(ifindex)
+
+    @staticmethod
+    def _new_object(obj):
+        return TcClass(obj)
+
+    def _new_cache(self, cache):
+        return TcClassCache(self.arg1, cache=cache)
+
+class TcClass(Tc):
+    """Traffic Class"""
+
+    def __init__(self, obj=None):
+        netlink.Object.__init__(self, 'route/class', 'class', obj)
+        self._module_path = 'netlink.route.qdisc.'
+        self._rtnl_class = self._obj2type(self._nl_object)
+        self._rtnl_tc = capi.obj2tc(self._nl_object)
+
+        if self.kind:
+            self._tc_module_lookup()
+
+    @classmethod
+    def from_capi(cls, obj):
+        return cls(capi.class2obj(obj))
+
+    @staticmethod
+    def _obj2type(obj):
+        return capi.obj2class(obj)
+
+    @staticmethod
+    def _new_instance(obj):
+        if not obj:
+            raise ValueError()
+
+        return TcClass(obj)
+
+    @property
+    def childs(self):
+        ret = []
+
+        # classes can have classifiers, child classes and leaf
+        # qdiscs
+        ret += get_cls(self.ifindex, parent=self.handle)
+        ret += get_class(self.ifindex, parent=self.handle)
+        ret += get_qdisc(self.ifindex, parent=self.handle)
+
+        return ret
+
+    def format(self, details=False, _stats=False, nodev=False,
+           noparent=False, indent=''):
+        """Return class as formatted text"""
+        fmt = util.MyFormatter(self, indent)
+
+        buf = fmt.format(self.brief('class', nodev, noparent))
+
+        if details:
+            buf += fmt.nl('\t' + self.details())
+
+        return buf
+
+class ClassifierCache(netlink.Cache):
+    """Cache of traffic classifiers objects"""
+
+    def __init__(self, ifindex, parent, cache=None):
+        if not cache:
+            cache = self._alloc_cache_name('route/cls')
+
+        self._protocol = netlink.NETLINK_ROUTE
+        self._nl_cache = cache
+        self._set_arg1(ifindex)
+        self._set_arg2(int(parent))
+
+    @staticmethod
+    def _new_object(obj):
+        return Classifier(obj)
+
+    def _new_cache(self, cache):
+        return ClassifierCache(self.arg1, self.arg2, cache=cache)
+
+class Classifier(Tc):
+    """Classifier"""
+
+    def __init__(self, obj=None):
+        netlink.Object.__init__(self, 'route/cls', 'cls', obj)
+        self._module_path = 'netlink.route.cls.'
+        self._rtnl_cls = self._obj2type(self._nl_object)
+        self._rtnl_tc = capi.obj2tc(self._nl_object)
+
+    @classmethod
+    def from_capi(cls, obj):
+        return cls(capi.cls2obj(obj))
+
+    @staticmethod
+    def _obj2type(obj):
+        return capi.obj2cls(obj)
+
+    @staticmethod
+    def _new_instance(obj):
+        if not obj:
+            raise ValueError()
+
+        return Classifier(obj)
+
+    @property
+    def priority(self):
+        return capi.rtnl_cls_get_prio(self._rtnl_cls)
+
+    @priority.setter
+    def priority(self, value):
+        capi.rtnl_cls_set_prio(self._rtnl_cls, int(value))
+
+    @property
+    def protocol(self):
+        return capi.rtnl_cls_get_protocol(self._rtnl_cls)
+
+    @protocol.setter
+    def protocol(self, value):
+        capi.rtnl_cls_set_protocol(self._rtnl_cls, int(value))
+
+    @property
+    def childs(self):
+        return []
+
+    def format(self, details=False, _stats=False, nodev=False,
+           noparent=False, indent=''):
+        """Return class as formatted text"""
+        fmt = util.MyFormatter(self, indent)
+
+        buf = fmt.format(self.brief('classifier', nodev, noparent))
+        buf += fmt.format(' {t|priority} {t|protocol}')
+
+        if details:
+            buf += fmt.nl('\t' + self.details())
+
+        return buf
+
+_qdisc_cache = QdiscCache()
+
+def get_qdisc(ifindex, handle=None, parent=None):
+    l = []
+
+    _qdisc_cache.refill()
+
+    for qdisc in _qdisc_cache:
+        if qdisc.ifindex != ifindex:
+            continue
+        if (handle is not None) and (qdisc.handle != handle):
+            continue
+        if (parent is not None) and (qdisc.parent != parent):
+            continue
+        l.append(qdisc)
+
+    return l
+
+_class_cache = {}
+
+def get_class(ifindex, parent, handle=None):
+    l = []
+
+    try:
+        cache = _class_cache[ifindex]
+    except KeyError:
+        cache = TcClassCache(ifindex)
+        _class_cache[ifindex] = cache
+
+    cache.refill()
+
+    for cl in cache:
+        if (parent is not None) and (cl.parent != parent):
+            continue
+        if (handle is not None) and (cl.handle != handle):
+            continue
+        l.append(cl)
+
+    return l
+
+_cls_cache = {}
+
+def get_cls(ifindex, parent, handle=None):
+
+    chain = _cls_cache.get(ifindex, dict())
+
+    try:
+        cache = chain[parent]
+    except KeyError:
+        cache = ClassifierCache(ifindex, parent)
+        chain[parent] = cache
+
+    cache.refill()
+
+    if handle is None:
+        return [ cls for cls in cache ]
+
+    return [ cls for cls in cache if cls.handle == handle ]
diff --git a/python/netlink/util.py b/python/netlink/util.py
new file mode 100644 (file)
index 0000000..2394033
--- /dev/null
@@ -0,0 +1,174 @@
+#
+# Utilities
+#
+# Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+#
+
+"""utility module for netlink
+
+"""
+
+from __future__ import absolute_import
+
+from . import core as netlink
+from . import capi as capi
+from string import Formatter
+import types
+
+__version__ = '1.0'
+
+def _color(t, c):
+    return b'{esc}[{color}m{text}{esc}[0m'.format(esc=b'\x1b', color=c, text=t)
+
+def black(t):
+    return _color(t, 30)
+
+def red(t):
+    return _color(t, 31)
+
+def green(t):
+    return _color(t, 32)
+
+def yellow(t):
+    return _color(t, 33)
+
+def blue(t):
+    return _color(t, 34)
+
+def magenta(t):
+    return _color(t, 35)
+
+def cyan(t):
+    return _color(t, 36)
+
+def white(t):
+    return _color(t, 37)
+
+def bold(t):
+    return _color(t, 1)
+
+def kw(t):
+    return yellow(t)
+
+def num(t):
+    return str(t)
+
+def string(t):
+    return t
+
+def addr(t):
+    return str(t)
+
+def bad(t):
+    return red(t)
+
+def good(t):
+    return green(t)
+
+def title(t):
+    return t
+
+def boolean(t):
+    return str(t)
+
+def handle(t):
+    return str(t)
+
+class MyFormatter(Formatter):
+    def __init__(self, obj, indent=''):
+        self._obj = obj
+        self._indent = indent
+
+    def _nlattr(self, key):
+        value = getattr(self._obj.__class__, key)
+        if not isinstance(value, property):
+            raise ValueError('Invalid formatting string {0}'.format(key))
+
+        d = getattr(value.fget, 'formatinfo', dict())
+
+        # value = value.fget() is exactly the same
+        value = getattr(self._obj, key)
+
+        if 'fmt' in d:
+            value = d['fmt'](value)
+
+        title_ = d.get('title', None)
+
+        return title_, str(value)
+
+    def get_value(self, key, args, kwds):
+        # Let default get_value() handle ints
+        if not isinstance(key, str):
+            return Formatter.get_value(self, key, args, kwds)
+
+        # HACK, we allow defining strings via fields to allow
+        # conversions
+        if key[:2] == 's|':
+            return key[2:]
+
+        if key[:2] == 't|':
+            # title mode ("TITLE ATTR")
+            include_title = True
+        elif key[:2] == 'a|':
+            # plain attribute mode ("ATTR")
+            include_title = False
+        else:
+            # No special field, have default get_value() get it
+            return Formatter.get_value(self, key, args, kwds)
+
+        key = key[2:]
+        (title_, value) = self._nlattr(key)
+
+        if include_title:
+            if not title_:
+                title_ = key    # fall back to key as title
+            value = '{0} {1}'.format(kw(title_), value)
+
+        return value
+
+    def convert_field(self, value, conversion):
+        if conversion == 'r':
+            return repr(value)
+        elif conversion == 's':
+            return str(value)
+        elif conversion == 'k':
+            return kw(value)
+        elif conversion == 'b':
+            return bold(value)
+        elif conversion is None:
+            return value
+
+        raise ValueError('Unknown converion specifier {0!s}'.format(conversion))
+
+    def nl(self, format_string=''):
+        return '\n' + self._indent + self.format(format_string)
+
+NL_BYTE_RATE = 0
+NL_BIT_RATE = 1
+
+class Rate(object):
+    def __init__(self, rate, mode=NL_BYTE_RATE):
+        self._rate = rate
+        self._mode = mode
+
+    def __str__(self):
+        return capi.nl_rate2str(self._rate, self._mode, 32)[1]
+
+    def __int__(self):
+        return self._rate
+
+    def __cmp__(self, other):
+        return int(self) - int(other)
+
+class Size(object):
+    def __init__(self, size):
+        self._size = size
+
+    def __str__(self):
+        return capi.nl_size2str(self._size, 32)[0]
+
+    def __int__(self):
+        return self._size
+
+    def __cmp__(self, other):
+        return int(self) - int(other)
diff --git a/python/setup.py.in b/python/setup.py.in
new file mode 100644 (file)
index 0000000..7ba90d7
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+from distutils.core import setup, Extension
+
+opts = ['-O', '-nodefaultctor']
+include = ['@top_builddir@/include']
+
+netlink_capi = Extension('netlink/_capi',
+                         sources = ['netlink/capi.i'],
+                        include_dirs = include,
+                        swig_opts = opts,
+                        libraries = ['nl-3'],
+                       )
+
+route_capi = Extension('netlink/route/_capi',
+                         sources = ['netlink/route/capi.i'],
+                        include_dirs = include,
+                        swig_opts = opts,
+                        libraries = ['nl-3', 'nl-route-3'],
+                       )
+
+setup(name = 'netlink',
+      version = '1.0',
+      description = 'Python wrapper for netlink protocols',
+      author = 'Thomas Graf',
+      author_email = 'tgraf@suug.ch',
+      ext_modules = [netlink_capi, route_capi],
+      packages = ['netlink', 'netlink.route', 'netlink.route.links',
+                 'netlink.route.qdisc'],
+     )
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..c318dcc
--- /dev/null
@@ -0,0 +1,100 @@
+# -*- Makefile -*-
+
+SUBDIRS = lib
+
+AM_CPPFLAGS  = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
+
+LDADD = \
+       ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+
+sbin_PROGRAMS = \
+       genl-ctrl-list \
+       nl-qdisc-add nl-qdisc-list nl-qdisc-delete \
+       nl-class-add nl-class-list nl-class-delete \
+       nl-cls-add nl-cls-list nl-cls-delete \
+       nl-classid-lookup \
+       nl-pktloc-lookup \
+       nl-link-list
+
+noinst_PROGRAMS = \
+       nf-ct-list nf-log nf-queue nf-monitor \
+       nf-exp-list nf-exp-add nf-exp-delete \
+       nl-addr-add nl-addr-delete nl-addr-list \
+       nl-link-set nl-link-stats \
+       nl-link-ifindex2name nl-link-name2ifindex \
+       nl-neigh-add nl-neigh-delete nl-neigh-list \
+       nl-rule-list \
+       nl-neightbl-list \
+       nl-monitor \
+       nl-tctree-list \
+       nl-route-add nl-route-delete nl-route-get nl-route-list \
+       nl-fib-lookup \
+       nl-list-caches nl-list-sockets \
+       nl-util-addr \
+       nl-link-enslave \
+       nl-link-release
+
+genl_ctrl_list_SOURCES = genl-ctrl-list.c 
+
+nf_ct_list_SOURCES = nf-ct-list.c 
+nf_log_SOURCES = nf-log.c
+nf_queue_SOURCES = nf-queue.c 
+nf_monitor_SOURCES = nf-monitor.c
+
+nf_exp_list_SOURCES = nf-exp-list.c 
+nf_exp_add_SOURCES = nf-exp-add.c 
+nf_exp_delete_SOURCES = nf-exp-delete.c 
+
+nl_addr_add_SOURCES = nl-addr-add.c
+nl_addr_delete_SOURCES = nl-addr-delete.c
+nl_addr_list_SOURCES = nl-addr-list.c
+
+nl_link_list_SOURCES = nl-link-list.c
+nl_link_set_SOURCES = nl-link-set.c
+nl_link_stats_SOURCES = nl-link-stats.c
+nl_link_ifindex2name_SOURCES = nl-link-ifindex2name.c
+nl_link_name2ifindex_SOURCES = nl-link-name2ifindex.c
+
+nl_monitor_SOURCES = nl-monitor.c
+
+nl_neigh_add_SOURCES = nl-neigh-add.c
+nl_neigh_delete_SOURCES = nl-neigh-delete.c
+nl_neigh_list_SOURCES = nl-neigh-list.c
+
+nl_neightbl_list_SOURCES = nl-neightbl-list.c
+
+nl_qdisc_add_SOURCES = nl-qdisc-add.c
+nl_qdisc_delete_SOURCES = nl-qdisc-delete.c
+nl_qdisc_list_SOURCES = nl-qdisc-list.c
+
+nl_class_add_SOURCES = nl-class-add.c
+nl_class_delete_SOURCES = nl-class-delete.c
+nl_class_list_SOURCES = nl-class-list.c
+
+nl_cls_add_SOURCES = nl-cls-add.c
+nl_cls_list_SOURCES = nl-cls-list.c
+nl_cls_delete_SOURCES = nl-cls-delete.c
+
+nl_route_add_SOURCES = nl-route-add.c
+nl_route_delete_SOURCES = nl-route-delete.c
+nl_route_get_SOURCES = nl-route-get.c
+nl_route_list_SOURCES = nl-route-list.c
+
+nl_rule_list_SOURCES = nl-rule-list.c
+
+nl_tctree_list_SOURCES = nl-tctree-list.c
+
+nl_fib_lookup_SOURCES = nl-fib-lookup.c
+
+nl_list_caches_SOURCES = nl-list-caches.c
+nl_list_sockets_SOURCES = nl-list-sockets.c
+
+nl_util_addr_SOURCES = nl-util-addr.c
+
+nl_pktloc_lookup_SOURCES = nl-pktloc-lookup.c
+
+nl_classid_lookup_SOURCES = nl-classid-lookup.c
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..78abc10
--- /dev/null
@@ -0,0 +1,1374 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = genl-ctrl-list$(EXEEXT) nl-qdisc-add$(EXEEXT) \
+       nl-qdisc-list$(EXEEXT) nl-qdisc-delete$(EXEEXT) \
+       nl-class-add$(EXEEXT) nl-class-list$(EXEEXT) \
+       nl-class-delete$(EXEEXT) nl-cls-add$(EXEEXT) \
+       nl-cls-list$(EXEEXT) nl-cls-delete$(EXEEXT) \
+       nl-classid-lookup$(EXEEXT) nl-pktloc-lookup$(EXEEXT) \
+       nl-link-list$(EXEEXT)
+noinst_PROGRAMS = nf-ct-list$(EXEEXT) nf-log$(EXEEXT) \
+       nf-queue$(EXEEXT) nf-monitor$(EXEEXT) nf-exp-list$(EXEEXT) \
+       nf-exp-add$(EXEEXT) nf-exp-delete$(EXEEXT) \
+       nl-addr-add$(EXEEXT) nl-addr-delete$(EXEEXT) \
+       nl-addr-list$(EXEEXT) nl-link-set$(EXEEXT) \
+       nl-link-stats$(EXEEXT) nl-link-ifindex2name$(EXEEXT) \
+       nl-link-name2ifindex$(EXEEXT) nl-neigh-add$(EXEEXT) \
+       nl-neigh-delete$(EXEEXT) nl-neigh-list$(EXEEXT) \
+       nl-rule-list$(EXEEXT) nl-neightbl-list$(EXEEXT) \
+       nl-monitor$(EXEEXT) nl-tctree-list$(EXEEXT) \
+       nl-route-add$(EXEEXT) nl-route-delete$(EXEEXT) \
+       nl-route-get$(EXEEXT) nl-route-list$(EXEEXT) \
+       nl-fib-lookup$(EXEEXT) nl-list-caches$(EXEEXT) \
+       nl-list-sockets$(EXEEXT) nl-util-addr$(EXEEXT) \
+       nl-link-enslave$(EXEEXT) nl-link-release$(EXEEXT)
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)"
+PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS)
+am_genl_ctrl_list_OBJECTS = genl-ctrl-list.$(OBJEXT)
+genl_ctrl_list_OBJECTS = $(am_genl_ctrl_list_OBJECTS)
+genl_ctrl_list_LDADD = $(LDADD)
+genl_ctrl_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am_nf_ct_list_OBJECTS = nf-ct-list.$(OBJEXT)
+nf_ct_list_OBJECTS = $(am_nf_ct_list_OBJECTS)
+nf_ct_list_LDADD = $(LDADD)
+nf_ct_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nf_exp_add_OBJECTS = nf-exp-add.$(OBJEXT)
+nf_exp_add_OBJECTS = $(am_nf_exp_add_OBJECTS)
+nf_exp_add_LDADD = $(LDADD)
+nf_exp_add_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nf_exp_delete_OBJECTS = nf-exp-delete.$(OBJEXT)
+nf_exp_delete_OBJECTS = $(am_nf_exp_delete_OBJECTS)
+nf_exp_delete_LDADD = $(LDADD)
+nf_exp_delete_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nf_exp_list_OBJECTS = nf-exp-list.$(OBJEXT)
+nf_exp_list_OBJECTS = $(am_nf_exp_list_OBJECTS)
+nf_exp_list_LDADD = $(LDADD)
+nf_exp_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nf_log_OBJECTS = nf-log.$(OBJEXT)
+nf_log_OBJECTS = $(am_nf_log_OBJECTS)
+nf_log_LDADD = $(LDADD)
+nf_log_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nf_monitor_OBJECTS = nf-monitor.$(OBJEXT)
+nf_monitor_OBJECTS = $(am_nf_monitor_OBJECTS)
+nf_monitor_LDADD = $(LDADD)
+nf_monitor_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nf_queue_OBJECTS = nf-queue.$(OBJEXT)
+nf_queue_OBJECTS = $(am_nf_queue_OBJECTS)
+nf_queue_LDADD = $(LDADD)
+nf_queue_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_addr_add_OBJECTS = nl-addr-add.$(OBJEXT)
+nl_addr_add_OBJECTS = $(am_nl_addr_add_OBJECTS)
+nl_addr_add_LDADD = $(LDADD)
+nl_addr_add_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_addr_delete_OBJECTS = nl-addr-delete.$(OBJEXT)
+nl_addr_delete_OBJECTS = $(am_nl_addr_delete_OBJECTS)
+nl_addr_delete_LDADD = $(LDADD)
+nl_addr_delete_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_addr_list_OBJECTS = nl-addr-list.$(OBJEXT)
+nl_addr_list_OBJECTS = $(am_nl_addr_list_OBJECTS)
+nl_addr_list_LDADD = $(LDADD)
+nl_addr_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_class_add_OBJECTS = nl-class-add.$(OBJEXT)
+nl_class_add_OBJECTS = $(am_nl_class_add_OBJECTS)
+nl_class_add_LDADD = $(LDADD)
+nl_class_add_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_class_delete_OBJECTS = nl-class-delete.$(OBJEXT)
+nl_class_delete_OBJECTS = $(am_nl_class_delete_OBJECTS)
+nl_class_delete_LDADD = $(LDADD)
+nl_class_delete_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_class_list_OBJECTS = nl-class-list.$(OBJEXT)
+nl_class_list_OBJECTS = $(am_nl_class_list_OBJECTS)
+nl_class_list_LDADD = $(LDADD)
+nl_class_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_classid_lookup_OBJECTS = nl-classid-lookup.$(OBJEXT)
+nl_classid_lookup_OBJECTS = $(am_nl_classid_lookup_OBJECTS)
+nl_classid_lookup_LDADD = $(LDADD)
+nl_classid_lookup_DEPENDENCIES =  \
+       ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_cls_add_OBJECTS = nl-cls-add.$(OBJEXT)
+nl_cls_add_OBJECTS = $(am_nl_cls_add_OBJECTS)
+nl_cls_add_LDADD = $(LDADD)
+nl_cls_add_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_cls_delete_OBJECTS = nl-cls-delete.$(OBJEXT)
+nl_cls_delete_OBJECTS = $(am_nl_cls_delete_OBJECTS)
+nl_cls_delete_LDADD = $(LDADD)
+nl_cls_delete_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_cls_list_OBJECTS = nl-cls-list.$(OBJEXT)
+nl_cls_list_OBJECTS = $(am_nl_cls_list_OBJECTS)
+nl_cls_list_LDADD = $(LDADD)
+nl_cls_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_fib_lookup_OBJECTS = nl-fib-lookup.$(OBJEXT)
+nl_fib_lookup_OBJECTS = $(am_nl_fib_lookup_OBJECTS)
+nl_fib_lookup_LDADD = $(LDADD)
+nl_fib_lookup_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+nl_link_enslave_SOURCES = nl-link-enslave.c
+nl_link_enslave_OBJECTS = nl-link-enslave.$(OBJEXT)
+nl_link_enslave_LDADD = $(LDADD)
+nl_link_enslave_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_link_ifindex2name_OBJECTS = nl-link-ifindex2name.$(OBJEXT)
+nl_link_ifindex2name_OBJECTS = $(am_nl_link_ifindex2name_OBJECTS)
+nl_link_ifindex2name_LDADD = $(LDADD)
+nl_link_ifindex2name_DEPENDENCIES =  \
+       ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_link_list_OBJECTS = nl-link-list.$(OBJEXT)
+nl_link_list_OBJECTS = $(am_nl_link_list_OBJECTS)
+nl_link_list_LDADD = $(LDADD)
+nl_link_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_link_name2ifindex_OBJECTS = nl-link-name2ifindex.$(OBJEXT)
+nl_link_name2ifindex_OBJECTS = $(am_nl_link_name2ifindex_OBJECTS)
+nl_link_name2ifindex_LDADD = $(LDADD)
+nl_link_name2ifindex_DEPENDENCIES =  \
+       ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+nl_link_release_SOURCES = nl-link-release.c
+nl_link_release_OBJECTS = nl-link-release.$(OBJEXT)
+nl_link_release_LDADD = $(LDADD)
+nl_link_release_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_link_set_OBJECTS = nl-link-set.$(OBJEXT)
+nl_link_set_OBJECTS = $(am_nl_link_set_OBJECTS)
+nl_link_set_LDADD = $(LDADD)
+nl_link_set_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_link_stats_OBJECTS = nl-link-stats.$(OBJEXT)
+nl_link_stats_OBJECTS = $(am_nl_link_stats_OBJECTS)
+nl_link_stats_LDADD = $(LDADD)
+nl_link_stats_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_list_caches_OBJECTS = nl-list-caches.$(OBJEXT)
+nl_list_caches_OBJECTS = $(am_nl_list_caches_OBJECTS)
+nl_list_caches_LDADD = $(LDADD)
+nl_list_caches_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_list_sockets_OBJECTS = nl-list-sockets.$(OBJEXT)
+nl_list_sockets_OBJECTS = $(am_nl_list_sockets_OBJECTS)
+nl_list_sockets_LDADD = $(LDADD)
+nl_list_sockets_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_monitor_OBJECTS = nl-monitor.$(OBJEXT)
+nl_monitor_OBJECTS = $(am_nl_monitor_OBJECTS)
+nl_monitor_LDADD = $(LDADD)
+nl_monitor_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_neigh_add_OBJECTS = nl-neigh-add.$(OBJEXT)
+nl_neigh_add_OBJECTS = $(am_nl_neigh_add_OBJECTS)
+nl_neigh_add_LDADD = $(LDADD)
+nl_neigh_add_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_neigh_delete_OBJECTS = nl-neigh-delete.$(OBJEXT)
+nl_neigh_delete_OBJECTS = $(am_nl_neigh_delete_OBJECTS)
+nl_neigh_delete_LDADD = $(LDADD)
+nl_neigh_delete_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_neigh_list_OBJECTS = nl-neigh-list.$(OBJEXT)
+nl_neigh_list_OBJECTS = $(am_nl_neigh_list_OBJECTS)
+nl_neigh_list_LDADD = $(LDADD)
+nl_neigh_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_neightbl_list_OBJECTS = nl-neightbl-list.$(OBJEXT)
+nl_neightbl_list_OBJECTS = $(am_nl_neightbl_list_OBJECTS)
+nl_neightbl_list_LDADD = $(LDADD)
+nl_neightbl_list_DEPENDENCIES =  \
+       ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_pktloc_lookup_OBJECTS = nl-pktloc-lookup.$(OBJEXT)
+nl_pktloc_lookup_OBJECTS = $(am_nl_pktloc_lookup_OBJECTS)
+nl_pktloc_lookup_LDADD = $(LDADD)
+nl_pktloc_lookup_DEPENDENCIES =  \
+       ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_qdisc_add_OBJECTS = nl-qdisc-add.$(OBJEXT)
+nl_qdisc_add_OBJECTS = $(am_nl_qdisc_add_OBJECTS)
+nl_qdisc_add_LDADD = $(LDADD)
+nl_qdisc_add_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_qdisc_delete_OBJECTS = nl-qdisc-delete.$(OBJEXT)
+nl_qdisc_delete_OBJECTS = $(am_nl_qdisc_delete_OBJECTS)
+nl_qdisc_delete_LDADD = $(LDADD)
+nl_qdisc_delete_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_qdisc_list_OBJECTS = nl-qdisc-list.$(OBJEXT)
+nl_qdisc_list_OBJECTS = $(am_nl_qdisc_list_OBJECTS)
+nl_qdisc_list_LDADD = $(LDADD)
+nl_qdisc_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_route_add_OBJECTS = nl-route-add.$(OBJEXT)
+nl_route_add_OBJECTS = $(am_nl_route_add_OBJECTS)
+nl_route_add_LDADD = $(LDADD)
+nl_route_add_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_route_delete_OBJECTS = nl-route-delete.$(OBJEXT)
+nl_route_delete_OBJECTS = $(am_nl_route_delete_OBJECTS)
+nl_route_delete_LDADD = $(LDADD)
+nl_route_delete_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_route_get_OBJECTS = nl-route-get.$(OBJEXT)
+nl_route_get_OBJECTS = $(am_nl_route_get_OBJECTS)
+nl_route_get_LDADD = $(LDADD)
+nl_route_get_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_route_list_OBJECTS = nl-route-list.$(OBJEXT)
+nl_route_list_OBJECTS = $(am_nl_route_list_OBJECTS)
+nl_route_list_LDADD = $(LDADD)
+nl_route_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_rule_list_OBJECTS = nl-rule-list.$(OBJEXT)
+nl_rule_list_OBJECTS = $(am_nl_rule_list_OBJECTS)
+nl_rule_list_LDADD = $(LDADD)
+nl_rule_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_tctree_list_OBJECTS = nl-tctree-list.$(OBJEXT)
+nl_tctree_list_OBJECTS = $(am_nl_tctree_list_OBJECTS)
+nl_tctree_list_LDADD = $(LDADD)
+nl_tctree_list_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+am_nl_util_addr_OBJECTS = nl-util-addr.$(OBJEXT)
+nl_util_addr_OBJECTS = $(am_nl_util_addr_OBJECTS)
+nl_util_addr_LDADD = $(LDADD)
+nl_util_addr_DEPENDENCIES = ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(genl_ctrl_list_SOURCES) $(nf_ct_list_SOURCES) \
+       $(nf_exp_add_SOURCES) $(nf_exp_delete_SOURCES) \
+       $(nf_exp_list_SOURCES) $(nf_log_SOURCES) $(nf_monitor_SOURCES) \
+       $(nf_queue_SOURCES) $(nl_addr_add_SOURCES) \
+       $(nl_addr_delete_SOURCES) $(nl_addr_list_SOURCES) \
+       $(nl_class_add_SOURCES) $(nl_class_delete_SOURCES) \
+       $(nl_class_list_SOURCES) $(nl_classid_lookup_SOURCES) \
+       $(nl_cls_add_SOURCES) $(nl_cls_delete_SOURCES) \
+       $(nl_cls_list_SOURCES) $(nl_fib_lookup_SOURCES) \
+       nl-link-enslave.c $(nl_link_ifindex2name_SOURCES) \
+       $(nl_link_list_SOURCES) $(nl_link_name2ifindex_SOURCES) \
+       nl-link-release.c $(nl_link_set_SOURCES) \
+       $(nl_link_stats_SOURCES) $(nl_list_caches_SOURCES) \
+       $(nl_list_sockets_SOURCES) $(nl_monitor_SOURCES) \
+       $(nl_neigh_add_SOURCES) $(nl_neigh_delete_SOURCES) \
+       $(nl_neigh_list_SOURCES) $(nl_neightbl_list_SOURCES) \
+       $(nl_pktloc_lookup_SOURCES) $(nl_qdisc_add_SOURCES) \
+       $(nl_qdisc_delete_SOURCES) $(nl_qdisc_list_SOURCES) \
+       $(nl_route_add_SOURCES) $(nl_route_delete_SOURCES) \
+       $(nl_route_get_SOURCES) $(nl_route_list_SOURCES) \
+       $(nl_rule_list_SOURCES) $(nl_tctree_list_SOURCES) \
+       $(nl_util_addr_SOURCES)
+DIST_SOURCES = $(genl_ctrl_list_SOURCES) $(nf_ct_list_SOURCES) \
+       $(nf_exp_add_SOURCES) $(nf_exp_delete_SOURCES) \
+       $(nf_exp_list_SOURCES) $(nf_log_SOURCES) $(nf_monitor_SOURCES) \
+       $(nf_queue_SOURCES) $(nl_addr_add_SOURCES) \
+       $(nl_addr_delete_SOURCES) $(nl_addr_list_SOURCES) \
+       $(nl_class_add_SOURCES) $(nl_class_delete_SOURCES) \
+       $(nl_class_list_SOURCES) $(nl_classid_lookup_SOURCES) \
+       $(nl_cls_add_SOURCES) $(nl_cls_delete_SOURCES) \
+       $(nl_cls_list_SOURCES) $(nl_fib_lookup_SOURCES) \
+       nl-link-enslave.c $(nl_link_ifindex2name_SOURCES) \
+       $(nl_link_list_SOURCES) $(nl_link_name2ifindex_SOURCES) \
+       nl-link-release.c $(nl_link_set_SOURCES) \
+       $(nl_link_stats_SOURCES) $(nl_list_caches_SOURCES) \
+       $(nl_list_sockets_SOURCES) $(nl_monitor_SOURCES) \
+       $(nl_neigh_add_SOURCES) $(nl_neigh_delete_SOURCES) \
+       $(nl_neigh_list_SOURCES) $(nl_neightbl_list_SOURCES) \
+       $(nl_pktloc_lookup_SOURCES) $(nl_qdisc_add_SOURCES) \
+       $(nl_qdisc_delete_SOURCES) $(nl_qdisc_list_SOURCES) \
+       $(nl_route_add_SOURCES) $(nl_route_delete_SOURCES) \
+       $(nl_route_get_SOURCES) $(nl_route_list_SOURCES) \
+       $(nl_rule_list_SOURCES) $(nl_tctree_list_SOURCES) \
+       $(nl_util_addr_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+       html-recursive info-recursive install-data-recursive \
+       install-dvi-recursive install-exec-recursive \
+       install-html-recursive install-info-recursive \
+       install-pdf-recursive install-ps-recursive install-recursive \
+       installcheck-recursive installdirs-recursive pdf-recursive \
+       ps-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+       $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+       distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = lib
+AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
+LDADD = \
+       ${top_builddir}/src/lib/libnl-cli-3.la \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la
+
+genl_ctrl_list_SOURCES = genl-ctrl-list.c 
+nf_ct_list_SOURCES = nf-ct-list.c 
+nf_log_SOURCES = nf-log.c
+nf_queue_SOURCES = nf-queue.c 
+nf_monitor_SOURCES = nf-monitor.c
+nf_exp_list_SOURCES = nf-exp-list.c 
+nf_exp_add_SOURCES = nf-exp-add.c 
+nf_exp_delete_SOURCES = nf-exp-delete.c 
+nl_addr_add_SOURCES = nl-addr-add.c
+nl_addr_delete_SOURCES = nl-addr-delete.c
+nl_addr_list_SOURCES = nl-addr-list.c
+nl_link_list_SOURCES = nl-link-list.c
+nl_link_set_SOURCES = nl-link-set.c
+nl_link_stats_SOURCES = nl-link-stats.c
+nl_link_ifindex2name_SOURCES = nl-link-ifindex2name.c
+nl_link_name2ifindex_SOURCES = nl-link-name2ifindex.c
+nl_monitor_SOURCES = nl-monitor.c
+nl_neigh_add_SOURCES = nl-neigh-add.c
+nl_neigh_delete_SOURCES = nl-neigh-delete.c
+nl_neigh_list_SOURCES = nl-neigh-list.c
+nl_neightbl_list_SOURCES = nl-neightbl-list.c
+nl_qdisc_add_SOURCES = nl-qdisc-add.c
+nl_qdisc_delete_SOURCES = nl-qdisc-delete.c
+nl_qdisc_list_SOURCES = nl-qdisc-list.c
+nl_class_add_SOURCES = nl-class-add.c
+nl_class_delete_SOURCES = nl-class-delete.c
+nl_class_list_SOURCES = nl-class-list.c
+nl_cls_add_SOURCES = nl-cls-add.c
+nl_cls_list_SOURCES = nl-cls-list.c
+nl_cls_delete_SOURCES = nl-cls-delete.c
+nl_route_add_SOURCES = nl-route-add.c
+nl_route_delete_SOURCES = nl-route-delete.c
+nl_route_get_SOURCES = nl-route-get.c
+nl_route_list_SOURCES = nl-route-list.c
+nl_rule_list_SOURCES = nl-rule-list.c
+nl_tctree_list_SOURCES = nl-tctree-list.c
+nl_fib_lookup_SOURCES = nl-fib-lookup.c
+nl_list_caches_SOURCES = nl-list-caches.c
+nl_list_sockets_SOURCES = nl-list-sockets.c
+nl_util_addr_SOURCES = nl-util-addr.c
+nl_pktloc_lookup_SOURCES = nl-pktloc-lookup.c
+nl_classid_lookup_SOURCES = nl-classid-lookup.c
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+       @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+       fi; \
+       for p in $$list; do echo "$$p $$p"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p || test -f $$p1; \
+         then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+           if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+           test -z "$$files" || { \
+           echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+           } \
+       ; done
+
+uninstall-sbinPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+       files=`for p in $$list; do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' `; \
+       test -n "$$list" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+       @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+genl-ctrl-list$(EXEEXT): $(genl_ctrl_list_OBJECTS) $(genl_ctrl_list_DEPENDENCIES) $(EXTRA_genl_ctrl_list_DEPENDENCIES) 
+       @rm -f genl-ctrl-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(genl_ctrl_list_OBJECTS) $(genl_ctrl_list_LDADD) $(LIBS)
+nf-ct-list$(EXEEXT): $(nf_ct_list_OBJECTS) $(nf_ct_list_DEPENDENCIES) $(EXTRA_nf_ct_list_DEPENDENCIES) 
+       @rm -f nf-ct-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nf_ct_list_OBJECTS) $(nf_ct_list_LDADD) $(LIBS)
+nf-exp-add$(EXEEXT): $(nf_exp_add_OBJECTS) $(nf_exp_add_DEPENDENCIES) $(EXTRA_nf_exp_add_DEPENDENCIES) 
+       @rm -f nf-exp-add$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nf_exp_add_OBJECTS) $(nf_exp_add_LDADD) $(LIBS)
+nf-exp-delete$(EXEEXT): $(nf_exp_delete_OBJECTS) $(nf_exp_delete_DEPENDENCIES) $(EXTRA_nf_exp_delete_DEPENDENCIES) 
+       @rm -f nf-exp-delete$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nf_exp_delete_OBJECTS) $(nf_exp_delete_LDADD) $(LIBS)
+nf-exp-list$(EXEEXT): $(nf_exp_list_OBJECTS) $(nf_exp_list_DEPENDENCIES) $(EXTRA_nf_exp_list_DEPENDENCIES) 
+       @rm -f nf-exp-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nf_exp_list_OBJECTS) $(nf_exp_list_LDADD) $(LIBS)
+nf-log$(EXEEXT): $(nf_log_OBJECTS) $(nf_log_DEPENDENCIES) $(EXTRA_nf_log_DEPENDENCIES) 
+       @rm -f nf-log$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nf_log_OBJECTS) $(nf_log_LDADD) $(LIBS)
+nf-monitor$(EXEEXT): $(nf_monitor_OBJECTS) $(nf_monitor_DEPENDENCIES) $(EXTRA_nf_monitor_DEPENDENCIES) 
+       @rm -f nf-monitor$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nf_monitor_OBJECTS) $(nf_monitor_LDADD) $(LIBS)
+nf-queue$(EXEEXT): $(nf_queue_OBJECTS) $(nf_queue_DEPENDENCIES) $(EXTRA_nf_queue_DEPENDENCIES) 
+       @rm -f nf-queue$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nf_queue_OBJECTS) $(nf_queue_LDADD) $(LIBS)
+nl-addr-add$(EXEEXT): $(nl_addr_add_OBJECTS) $(nl_addr_add_DEPENDENCIES) $(EXTRA_nl_addr_add_DEPENDENCIES) 
+       @rm -f nl-addr-add$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_addr_add_OBJECTS) $(nl_addr_add_LDADD) $(LIBS)
+nl-addr-delete$(EXEEXT): $(nl_addr_delete_OBJECTS) $(nl_addr_delete_DEPENDENCIES) $(EXTRA_nl_addr_delete_DEPENDENCIES) 
+       @rm -f nl-addr-delete$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_addr_delete_OBJECTS) $(nl_addr_delete_LDADD) $(LIBS)
+nl-addr-list$(EXEEXT): $(nl_addr_list_OBJECTS) $(nl_addr_list_DEPENDENCIES) $(EXTRA_nl_addr_list_DEPENDENCIES) 
+       @rm -f nl-addr-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_addr_list_OBJECTS) $(nl_addr_list_LDADD) $(LIBS)
+nl-class-add$(EXEEXT): $(nl_class_add_OBJECTS) $(nl_class_add_DEPENDENCIES) $(EXTRA_nl_class_add_DEPENDENCIES) 
+       @rm -f nl-class-add$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_class_add_OBJECTS) $(nl_class_add_LDADD) $(LIBS)
+nl-class-delete$(EXEEXT): $(nl_class_delete_OBJECTS) $(nl_class_delete_DEPENDENCIES) $(EXTRA_nl_class_delete_DEPENDENCIES) 
+       @rm -f nl-class-delete$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_class_delete_OBJECTS) $(nl_class_delete_LDADD) $(LIBS)
+nl-class-list$(EXEEXT): $(nl_class_list_OBJECTS) $(nl_class_list_DEPENDENCIES) $(EXTRA_nl_class_list_DEPENDENCIES) 
+       @rm -f nl-class-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_class_list_OBJECTS) $(nl_class_list_LDADD) $(LIBS)
+nl-classid-lookup$(EXEEXT): $(nl_classid_lookup_OBJECTS) $(nl_classid_lookup_DEPENDENCIES) $(EXTRA_nl_classid_lookup_DEPENDENCIES) 
+       @rm -f nl-classid-lookup$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_classid_lookup_OBJECTS) $(nl_classid_lookup_LDADD) $(LIBS)
+nl-cls-add$(EXEEXT): $(nl_cls_add_OBJECTS) $(nl_cls_add_DEPENDENCIES) $(EXTRA_nl_cls_add_DEPENDENCIES) 
+       @rm -f nl-cls-add$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_cls_add_OBJECTS) $(nl_cls_add_LDADD) $(LIBS)
+nl-cls-delete$(EXEEXT): $(nl_cls_delete_OBJECTS) $(nl_cls_delete_DEPENDENCIES) $(EXTRA_nl_cls_delete_DEPENDENCIES) 
+       @rm -f nl-cls-delete$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_cls_delete_OBJECTS) $(nl_cls_delete_LDADD) $(LIBS)
+nl-cls-list$(EXEEXT): $(nl_cls_list_OBJECTS) $(nl_cls_list_DEPENDENCIES) $(EXTRA_nl_cls_list_DEPENDENCIES) 
+       @rm -f nl-cls-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_cls_list_OBJECTS) $(nl_cls_list_LDADD) $(LIBS)
+nl-fib-lookup$(EXEEXT): $(nl_fib_lookup_OBJECTS) $(nl_fib_lookup_DEPENDENCIES) $(EXTRA_nl_fib_lookup_DEPENDENCIES) 
+       @rm -f nl-fib-lookup$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_fib_lookup_OBJECTS) $(nl_fib_lookup_LDADD) $(LIBS)
+nl-link-enslave$(EXEEXT): $(nl_link_enslave_OBJECTS) $(nl_link_enslave_DEPENDENCIES) $(EXTRA_nl_link_enslave_DEPENDENCIES) 
+       @rm -f nl-link-enslave$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_link_enslave_OBJECTS) $(nl_link_enslave_LDADD) $(LIBS)
+nl-link-ifindex2name$(EXEEXT): $(nl_link_ifindex2name_OBJECTS) $(nl_link_ifindex2name_DEPENDENCIES) $(EXTRA_nl_link_ifindex2name_DEPENDENCIES) 
+       @rm -f nl-link-ifindex2name$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_link_ifindex2name_OBJECTS) $(nl_link_ifindex2name_LDADD) $(LIBS)
+nl-link-list$(EXEEXT): $(nl_link_list_OBJECTS) $(nl_link_list_DEPENDENCIES) $(EXTRA_nl_link_list_DEPENDENCIES) 
+       @rm -f nl-link-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_link_list_OBJECTS) $(nl_link_list_LDADD) $(LIBS)
+nl-link-name2ifindex$(EXEEXT): $(nl_link_name2ifindex_OBJECTS) $(nl_link_name2ifindex_DEPENDENCIES) $(EXTRA_nl_link_name2ifindex_DEPENDENCIES) 
+       @rm -f nl-link-name2ifindex$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_link_name2ifindex_OBJECTS) $(nl_link_name2ifindex_LDADD) $(LIBS)
+nl-link-release$(EXEEXT): $(nl_link_release_OBJECTS) $(nl_link_release_DEPENDENCIES) $(EXTRA_nl_link_release_DEPENDENCIES) 
+       @rm -f nl-link-release$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_link_release_OBJECTS) $(nl_link_release_LDADD) $(LIBS)
+nl-link-set$(EXEEXT): $(nl_link_set_OBJECTS) $(nl_link_set_DEPENDENCIES) $(EXTRA_nl_link_set_DEPENDENCIES) 
+       @rm -f nl-link-set$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_link_set_OBJECTS) $(nl_link_set_LDADD) $(LIBS)
+nl-link-stats$(EXEEXT): $(nl_link_stats_OBJECTS) $(nl_link_stats_DEPENDENCIES) $(EXTRA_nl_link_stats_DEPENDENCIES) 
+       @rm -f nl-link-stats$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_link_stats_OBJECTS) $(nl_link_stats_LDADD) $(LIBS)
+nl-list-caches$(EXEEXT): $(nl_list_caches_OBJECTS) $(nl_list_caches_DEPENDENCIES) $(EXTRA_nl_list_caches_DEPENDENCIES) 
+       @rm -f nl-list-caches$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_list_caches_OBJECTS) $(nl_list_caches_LDADD) $(LIBS)
+nl-list-sockets$(EXEEXT): $(nl_list_sockets_OBJECTS) $(nl_list_sockets_DEPENDENCIES) $(EXTRA_nl_list_sockets_DEPENDENCIES) 
+       @rm -f nl-list-sockets$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_list_sockets_OBJECTS) $(nl_list_sockets_LDADD) $(LIBS)
+nl-monitor$(EXEEXT): $(nl_monitor_OBJECTS) $(nl_monitor_DEPENDENCIES) $(EXTRA_nl_monitor_DEPENDENCIES) 
+       @rm -f nl-monitor$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_monitor_OBJECTS) $(nl_monitor_LDADD) $(LIBS)
+nl-neigh-add$(EXEEXT): $(nl_neigh_add_OBJECTS) $(nl_neigh_add_DEPENDENCIES) $(EXTRA_nl_neigh_add_DEPENDENCIES) 
+       @rm -f nl-neigh-add$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_neigh_add_OBJECTS) $(nl_neigh_add_LDADD) $(LIBS)
+nl-neigh-delete$(EXEEXT): $(nl_neigh_delete_OBJECTS) $(nl_neigh_delete_DEPENDENCIES) $(EXTRA_nl_neigh_delete_DEPENDENCIES) 
+       @rm -f nl-neigh-delete$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_neigh_delete_OBJECTS) $(nl_neigh_delete_LDADD) $(LIBS)
+nl-neigh-list$(EXEEXT): $(nl_neigh_list_OBJECTS) $(nl_neigh_list_DEPENDENCIES) $(EXTRA_nl_neigh_list_DEPENDENCIES) 
+       @rm -f nl-neigh-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_neigh_list_OBJECTS) $(nl_neigh_list_LDADD) $(LIBS)
+nl-neightbl-list$(EXEEXT): $(nl_neightbl_list_OBJECTS) $(nl_neightbl_list_DEPENDENCIES) $(EXTRA_nl_neightbl_list_DEPENDENCIES) 
+       @rm -f nl-neightbl-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_neightbl_list_OBJECTS) $(nl_neightbl_list_LDADD) $(LIBS)
+nl-pktloc-lookup$(EXEEXT): $(nl_pktloc_lookup_OBJECTS) $(nl_pktloc_lookup_DEPENDENCIES) $(EXTRA_nl_pktloc_lookup_DEPENDENCIES) 
+       @rm -f nl-pktloc-lookup$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_pktloc_lookup_OBJECTS) $(nl_pktloc_lookup_LDADD) $(LIBS)
+nl-qdisc-add$(EXEEXT): $(nl_qdisc_add_OBJECTS) $(nl_qdisc_add_DEPENDENCIES) $(EXTRA_nl_qdisc_add_DEPENDENCIES) 
+       @rm -f nl-qdisc-add$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_qdisc_add_OBJECTS) $(nl_qdisc_add_LDADD) $(LIBS)
+nl-qdisc-delete$(EXEEXT): $(nl_qdisc_delete_OBJECTS) $(nl_qdisc_delete_DEPENDENCIES) $(EXTRA_nl_qdisc_delete_DEPENDENCIES) 
+       @rm -f nl-qdisc-delete$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_qdisc_delete_OBJECTS) $(nl_qdisc_delete_LDADD) $(LIBS)
+nl-qdisc-list$(EXEEXT): $(nl_qdisc_list_OBJECTS) $(nl_qdisc_list_DEPENDENCIES) $(EXTRA_nl_qdisc_list_DEPENDENCIES) 
+       @rm -f nl-qdisc-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_qdisc_list_OBJECTS) $(nl_qdisc_list_LDADD) $(LIBS)
+nl-route-add$(EXEEXT): $(nl_route_add_OBJECTS) $(nl_route_add_DEPENDENCIES) $(EXTRA_nl_route_add_DEPENDENCIES) 
+       @rm -f nl-route-add$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_route_add_OBJECTS) $(nl_route_add_LDADD) $(LIBS)
+nl-route-delete$(EXEEXT): $(nl_route_delete_OBJECTS) $(nl_route_delete_DEPENDENCIES) $(EXTRA_nl_route_delete_DEPENDENCIES) 
+       @rm -f nl-route-delete$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_route_delete_OBJECTS) $(nl_route_delete_LDADD) $(LIBS)
+nl-route-get$(EXEEXT): $(nl_route_get_OBJECTS) $(nl_route_get_DEPENDENCIES) $(EXTRA_nl_route_get_DEPENDENCIES) 
+       @rm -f nl-route-get$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_route_get_OBJECTS) $(nl_route_get_LDADD) $(LIBS)
+nl-route-list$(EXEEXT): $(nl_route_list_OBJECTS) $(nl_route_list_DEPENDENCIES) $(EXTRA_nl_route_list_DEPENDENCIES) 
+       @rm -f nl-route-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_route_list_OBJECTS) $(nl_route_list_LDADD) $(LIBS)
+nl-rule-list$(EXEEXT): $(nl_rule_list_OBJECTS) $(nl_rule_list_DEPENDENCIES) $(EXTRA_nl_rule_list_DEPENDENCIES) 
+       @rm -f nl-rule-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_rule_list_OBJECTS) $(nl_rule_list_LDADD) $(LIBS)
+nl-tctree-list$(EXEEXT): $(nl_tctree_list_OBJECTS) $(nl_tctree_list_DEPENDENCIES) $(EXTRA_nl_tctree_list_DEPENDENCIES) 
+       @rm -f nl-tctree-list$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_tctree_list_OBJECTS) $(nl_tctree_list_LDADD) $(LIBS)
+nl-util-addr$(EXEEXT): $(nl_util_addr_OBJECTS) $(nl_util_addr_DEPENDENCIES) $(EXTRA_nl_util_addr_DEPENDENCIES) 
+       @rm -f nl-util-addr$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(nl_util_addr_OBJECTS) $(nl_util_addr_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genl-ctrl-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nf-ct-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nf-exp-add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nf-exp-delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nf-exp-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nf-log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nf-monitor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nf-queue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-addr-add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-addr-delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-addr-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-class-add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-class-delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-class-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-classid-lookup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-cls-add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-cls-delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-cls-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-fib-lookup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-link-enslave.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-link-ifindex2name.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-link-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-link-name2ifindex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-link-release.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-link-set.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-link-stats.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-list-caches.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-list-sockets.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-monitor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-neigh-add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-neigh-delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-neigh-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-neightbl-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-pktloc-lookup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-qdisc-add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-qdisc-delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-qdisc-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-route-add.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-route-delete.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-route-get.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-route-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-rule-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-tctree-list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nl-util-addr.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+       @fail= failcom='exit 1'; \
+       for f in x $$MAKEFLAGS; do \
+         case $$f in \
+           *=* | --[!k]*);; \
+           *k*) failcom='fail=yes';; \
+         esac; \
+       done; \
+       dot_seen=no; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       rev=''; for subdir in $$list; do \
+         if test "$$subdir" = "."; then :; else \
+           rev="$$subdir $$rev"; \
+         fi; \
+       done; \
+       rev="$$rev ."; \
+       target=`echo $@ | sed s/-recursive//`; \
+       for subdir in $$rev; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done && test -z "$$fail"
+tags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+       done
+ctags-recursive:
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+       done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+       for dir in "$(DESTDIR)$(sbindir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+       clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-sbinPROGRAMS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-sbinPROGRAMS
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+       install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+       all all-am check check-am clean clean-generic clean-libtool \
+       clean-noinstPROGRAMS clean-sbinPROGRAMS ctags ctags-recursive \
+       distclean distclean-compile distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-sbinPROGRAMS install-strip \
+       installcheck installcheck-am installdirs installdirs-am \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+       uninstall-sbinPROGRAMS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/genl-ctrl-list.c b/src/genl-ctrl-list.c
new file mode 100644 (file)
index 0000000..0895bcc
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * src/genl-ctrl-list.c        List Generic Netlink Families
+ *
+ *     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) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+
+static struct nl_cache *alloc_genl_family_cache(struct nl_sock *sk)
+{
+       return nl_cli_alloc_cache(sk, "generic netlink family",
+                          genl_ctrl_alloc_cache);
+}
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: genl-ctrl-list [--details]\n"
+       "\n"
+       "Options\n"
+       " -d, --details         Include detailed information in the list\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *family_cache;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_GENERIC);
+       family_cache = alloc_genl_family_cache(sock);
+       for (;;) {
+               int c, optidx = 0;
+               static struct option long_opts[] = {
+                       { "details", 0, 0, 'd' },
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "df:hv", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'd': params.dp_type = NL_DUMP_DETAILS; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               }
+       }
+
+       nl_cache_dump(family_cache, &params);
+
+       return 0;
+}
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644 (file)
index 0000000..6688e7c
--- /dev/null
@@ -0,0 +1,43 @@
+# -*- Makefile -*-
+
+AM_CPPFLAGS  = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DPKGLIBDIR=\"$(pkglibdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -rdynamic
+AM_LDFLAGS = \
+       -L${top_builddir}/lib \
+       -ldl \
+       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+#nobase_pkglib_LTLIBRARIES = cls/basic.la cls/ematch/cmp.la
+#cls_basic_la_LDFLAGS = -module -version-info 2:0:0
+#cls_ematch_cmp_la_LDFLAGS = -module -version-info 2:0:0
+
+#cls/ematch_grammar.c: cls/ematch_grammar.l
+#      $(LEX) --header-file=cls/ematch_grammar.h $(LFLAGS) -o $@ $^
+
+#cls/ematch_syntax.c: cls/ematch_syntax.y
+#      $(YACC) -d $(YFLAGS) -o $@ $^
+
+#cls/pktloc_grammar.c: cls/pktloc_grammar.l
+#      $(LEX) --header-file=cls/pktloc_grammar.h $(LFLAGS) -o $@ $^
+
+#cls/pktloc_syntax.c: cls/pktloc_syntax.y
+#      $(YACC) -d $(YFLAGS) -o $@ $^
+
+#CLEANFILES = \
+#      cls/ematch_grammar.c cls/ematch_grammar.h \
+#      cls/ematch_syntax.c cls/ematch_syntax.h \
+#      cls/pktloc_grammar.c cls/pktloc_grammar.h \
+#      cls/pktloc_syntax.c cls/pktloc_syntax.h
+
+lib_LTLIBRARIES = \
+       libnl-cli-3.la
+
+libnl_cli_3_la_LIBADD  = ${top_builddir}/lib/libnl-3.la \
+                      ${top_builddir}/lib/libnl-route-3.la \
+                      ${top_builddir}/lib/libnl-nf-3.la \
+                      ${top_builddir}/lib/libnl-genl-3.la
+
+libnl_cli_3_la_SOURCES = \
+       utils.c addr.c ct.c link.c neigh.c rule.c route.c \
+       tc.c qdisc.c class.c cls.c exp.c
+#      cls/ematch_syntax.c cls/ematch_grammar.c cls/ematch.c
+#      cls/pktloc_syntax.c cls/pktloc_grammar.c cls/utils.c
diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in
new file mode 100644 (file)
index 0000000..025484a
--- /dev/null
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/lib
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libnl_cli_3_la_DEPENDENCIES = ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la
+am_libnl_cli_3_la_OBJECTS = utils.lo addr.lo ct.lo link.lo neigh.lo \
+       rule.lo route.lo tc.lo qdisc.lo class.lo cls.lo exp.lo
+libnl_cli_3_la_OBJECTS = $(am_libnl_cli_3_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libnl_cli_3_la_SOURCES)
+DIST_SOURCES = $(libnl_cli_3_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DPKGLIBDIR=\"$(pkglibdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -rdynamic
+AM_LDFLAGS = \
+       -L${top_builddir}/lib \
+       -ldl \
+       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+
+#nobase_pkglib_LTLIBRARIES = cls/basic.la cls/ematch/cmp.la
+#cls_basic_la_LDFLAGS = -module -version-info 2:0:0
+#cls_ematch_cmp_la_LDFLAGS = -module -version-info 2:0:0
+
+#cls/ematch_grammar.c: cls/ematch_grammar.l
+#      $(LEX) --header-file=cls/ematch_grammar.h $(LFLAGS) -o $@ $^
+
+#cls/ematch_syntax.c: cls/ematch_syntax.y
+#      $(YACC) -d $(YFLAGS) -o $@ $^
+
+#cls/pktloc_grammar.c: cls/pktloc_grammar.l
+#      $(LEX) --header-file=cls/pktloc_grammar.h $(LFLAGS) -o $@ $^
+
+#cls/pktloc_syntax.c: cls/pktloc_syntax.y
+#      $(YACC) -d $(YFLAGS) -o $@ $^
+
+#CLEANFILES = \
+#      cls/ematch_grammar.c cls/ematch_grammar.h \
+#      cls/ematch_syntax.c cls/ematch_syntax.h \
+#      cls/pktloc_grammar.c cls/pktloc_grammar.h \
+#      cls/pktloc_syntax.c cls/pktloc_syntax.h
+lib_LTLIBRARIES = \
+       libnl-cli-3.la
+
+libnl_cli_3_la_LIBADD = ${top_builddir}/lib/libnl-3.la \
+                      ${top_builddir}/lib/libnl-route-3.la \
+                      ${top_builddir}/lib/libnl-nf-3.la \
+                      ${top_builddir}/lib/libnl-genl-3.la
+
+libnl_cli_3_la_SOURCES = \
+       utils.c addr.c ct.c link.c neigh.c rule.c route.c \
+       tc.c qdisc.c class.c cls.c exp.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign src/lib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       list2=; for p in $$list; do \
+         if test -f $$p; then \
+           list2="$$list2 $$p"; \
+         else :; fi; \
+       done; \
+       test -z "$$list2" || { \
+         echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+       }
+
+uninstall-libLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+       done
+
+clean-libLTLIBRARIES:
+       -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+       @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libnl-cli-3.la: $(libnl_cli_3_la_OBJECTS) $(libnl_cli_3_la_DEPENDENCIES) $(EXTRA_libnl_cli_3_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libnl_cli_3_la_OBJECTS) $(libnl_cli_3_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/class.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cls.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ct.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/neigh.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qdisc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rule.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+       for dir in "$(DESTDIR)$(libdir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-libLTLIBRARIES clean-libtool ctags distclean \
+       distclean-compile distclean-generic distclean-libtool \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am \
+       install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am uninstall-libLTLIBRARIES
+
+#      cls/ematch_syntax.c cls/ematch_grammar.c cls/ematch.c
+#      cls/pktloc_syntax.c cls/pktloc_grammar.c cls/utils.c
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/lib/addr.c b/src/lib/addr.c
new file mode 100644 (file)
index 0000000..a9c137b
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * src/lib/addr.c     Address Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_addr Addresses
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/addr.h>
+
+struct rtnl_addr *nl_cli_addr_alloc(void)
+{
+       struct rtnl_addr *addr;
+
+       addr = rtnl_addr_alloc();
+       if (!addr)
+               nl_cli_fatal(ENOMEM, "Unable to allocate address object");
+
+       return addr;
+}
+
+void nl_cli_addr_parse_family(struct rtnl_addr *addr, char *arg)
+{
+       int family;
+
+       if ((family = nl_str2af(arg)) != AF_UNSPEC)
+               rtnl_addr_set_family(addr, family);
+}
+
+void nl_cli_addr_parse_local(struct rtnl_addr *addr, char *arg)
+{
+       struct nl_addr *a;
+       int err;
+
+       a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr));
+       if ((err = rtnl_addr_set_local(addr, a)) < 0)
+               nl_cli_fatal(err, "Unable to set local address: %s",
+                            nl_geterror(err));
+
+       nl_addr_put(a);
+}
+
+void nl_cli_addr_parse_dev(struct rtnl_addr *addr, struct nl_cache *link_cache,
+                          char *arg)
+{
+       int ival;
+
+       if (!(ival = rtnl_link_name2i(link_cache, arg)))
+               nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+       rtnl_addr_set_ifindex(addr, ival);
+}
+
+void nl_cli_addr_parse_label(struct rtnl_addr *addr, char *arg)
+{
+       int err;
+
+       if ((err = rtnl_addr_set_label(addr, arg)) < 0)
+               nl_cli_fatal(err, "Unable to set address label: %s",
+                            nl_geterror(err));
+}
+
+void nl_cli_addr_parse_peer(struct rtnl_addr *addr, char *arg)
+{
+       struct nl_addr *a;
+       int err;
+
+       a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr));
+       if ((err = rtnl_addr_set_peer(addr, a)) < 0)
+               nl_cli_fatal(err, "Unable to set peer address: %s",
+                            nl_geterror(err));
+
+       nl_addr_put(a);
+}
+
+void nl_cli_addr_parse_scope(struct rtnl_addr *addr, char *arg)
+{
+       int ival;
+
+       if ((ival = rtnl_str2scope(arg)) < 0)
+               nl_cli_fatal(EINVAL, "Unknown address scope \"%s\"", arg);
+
+       rtnl_addr_set_scope(addr, ival);
+}
+
+void nl_cli_addr_parse_broadcast(struct rtnl_addr *addr, char *arg)
+{
+       struct nl_addr *a;
+       int err;
+
+       a = nl_cli_addr_parse(arg, rtnl_addr_get_family(addr));
+       if ((err = rtnl_addr_set_broadcast(addr, a)) < 0)
+               nl_cli_fatal(err, "Unable to set broadcast address: %s",
+                            nl_geterror(err));
+
+       nl_addr_put(a);
+}
+
+static uint32_t parse_lifetime(const char *arg)
+{
+       uint64_t msecs;
+       int err;
+
+       if (!strcasecmp(arg, "forever"))
+               return 0xFFFFFFFFU;
+
+       if ((err = nl_str2msec(arg, &msecs)) < 0)
+               nl_cli_fatal(err, "Unable to parse time string \"%s\": %s",
+                            arg, nl_geterror(err));
+
+       return (msecs / 1000);
+}
+
+void nl_cli_addr_parse_preferred(struct rtnl_addr *addr, char *arg)
+{
+       rtnl_addr_set_preferred_lifetime(addr, parse_lifetime(arg));
+}
+
+void nl_cli_addr_parse_valid(struct rtnl_addr *addr, char *arg)
+{
+       rtnl_addr_set_valid_lifetime(addr, parse_lifetime(arg));
+}
+
+/** @} */
diff --git a/src/lib/class.c b/src/lib/class.c
new file mode 100644 (file)
index 0000000..96f60cd
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * src/lib/class.c     CLI Class Helpers
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_class Traffic Classes
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/class.h>
+
+struct rtnl_class *nl_cli_class_alloc(void)
+{
+       struct rtnl_class *class;
+
+       if (!(class = rtnl_class_alloc()))
+               nl_cli_fatal(ENOMEM, "Unable to allocate class object");
+
+       return class;
+}
+
+struct nl_cache *nl_cli_class_alloc_cache(struct nl_sock *sock, int ifindex)
+{
+       struct nl_cache *cache;
+       int err;
+
+       if ((err = rtnl_class_alloc_cache(sock, ifindex, &cache)) < 0)
+               nl_cli_fatal(err, "Unable to allocate class cache: %s",
+                            nl_geterror(err));
+
+       nl_cache_mngt_provide(cache);
+
+       return cache;
+}
+
+/** @} */
diff --git a/src/lib/cls.c b/src/lib/cls.c
new file mode 100644 (file)
index 0000000..86d775d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * src/lib/cls.c       CLI Classifier Helpers
+ *
+ *     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) 2010-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_cls Classifiers
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/cls.h>
+#include <netlink/route/cls/ematch.h>
+
+struct rtnl_cls *nl_cli_cls_alloc(void)
+{
+       struct rtnl_cls *cls;
+
+       if (!(cls = rtnl_cls_alloc()))
+               nl_cli_fatal(ENOMEM, "Unable to allocate classifier object");
+
+       return cls;
+}
+
+struct nl_cache *nl_cli_cls_alloc_cache(struct nl_sock *sock, int ifindex,
+                                       uint32_t parent)
+{
+       struct nl_cache *cache;
+       int err;
+
+       if ((err = rtnl_cls_alloc_cache(sock, ifindex, parent, &cache)) < 0)
+               nl_cli_fatal(err, "Unable to allocate classifier cache: %s",
+                            nl_geterror(err));
+
+       return cache;
+}
+
+void nl_cli_cls_parse_proto(struct rtnl_cls *cls, char *arg)
+{
+       int proto;
+
+       if ((proto = nl_str2ether_proto(arg)) < 0)
+               nl_cli_fatal(proto, "Unknown protocol \"%s\".", arg);
+
+       rtnl_cls_set_protocol(cls, proto);
+}
+
+struct rtnl_ematch_tree *nl_cli_cls_parse_ematch(struct rtnl_cls *cls, char *arg)
+{
+       struct rtnl_ematch_tree *tree;
+       char *errstr = NULL;
+       int err;
+
+       if ((err = rtnl_ematch_parse_expr(arg, &errstr, &tree)) < 0)
+               nl_cli_fatal(err, "Unable to parse ematch expression: %s",
+                                 errstr);
+       
+       if (errstr)
+               free(errstr);
+
+       return tree;
+}
+
+/** @} */
diff --git a/src/lib/ct.c b/src/lib/ct.c
new file mode 100644 (file)
index 0000000..5bab08f
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * src/lib/ct.c                CLI Conntrack Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_ct Connection Tracking
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/ct.h>
+
+struct nfnl_ct *nl_cli_ct_alloc(void)
+{
+       struct nfnl_ct *ct;
+
+       ct = nfnl_ct_alloc();
+       if (!ct)
+               nl_cli_fatal(ENOMEM, "Unable to allocate conntrack object");
+
+       return ct;
+}
+
+struct nl_cache *nl_cli_ct_alloc_cache(struct nl_sock *sk)
+{
+       return nl_cli_alloc_cache(sk, "conntrack", nfnl_ct_alloc_cache);
+}
+
+void nl_cli_ct_parse_family(struct nfnl_ct *ct, char *arg)
+{
+       int family;
+
+       if ((family = nl_str2af(arg)) == AF_UNSPEC)
+               nl_cli_fatal(EINVAL,
+                            "Unable to nl_cli_ct_parse family \"%s\": %s",
+                            arg, nl_geterror(NLE_INVAL));
+
+       nfnl_ct_set_family(ct, family);
+}
+
+void nl_cli_ct_parse_protocol(struct nfnl_ct *ct, char *arg)
+{
+       int proto;
+
+       if ((proto = nl_str2ip_proto(arg)) < 0)
+               nl_cli_fatal(proto,
+                            "Unable to nl_cli_ct_parse protocol \"%s\": %s",
+                            arg, nl_geterror(proto));
+
+       nfnl_ct_set_proto(ct, proto);
+}
+
+void nl_cli_ct_parse_mark(struct nfnl_ct *ct, char *arg)
+{
+       uint32_t mark = nl_cli_parse_u32(arg);
+       nfnl_ct_set_mark(ct, mark);
+}
+
+void nl_cli_ct_parse_timeout(struct nfnl_ct *ct, char *arg)
+{
+       uint32_t timeout = nl_cli_parse_u32(arg);
+       nfnl_ct_set_timeout(ct, timeout);
+}
+
+void nl_cli_ct_parse_id(struct nfnl_ct *ct, char *arg)
+{
+       uint32_t id = nl_cli_parse_u32(arg);
+       nfnl_ct_set_id(ct, id);
+}
+
+void nl_cli_ct_parse_use(struct nfnl_ct *ct, char *arg)
+{
+       uint32_t use = nl_cli_parse_u32(arg);
+       nfnl_ct_set_use(ct, use);
+}
+
+void nl_cli_ct_parse_src(struct nfnl_ct *ct, int reply, char *arg)
+{
+       int err;
+       struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_ct_get_family(ct));
+       if ((err = nfnl_ct_set_src(ct, reply, a)) < 0)
+               nl_cli_fatal(err, "Unable to set source address: %s",
+                            nl_geterror(err));
+}
+
+void nl_cli_ct_parse_dst(struct nfnl_ct *ct, int reply, char *arg)
+{
+       int err;
+       struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_ct_get_family(ct));
+       if ((err = nfnl_ct_set_dst(ct, reply, a)) < 0)
+               nl_cli_fatal(err, "Unable to set destination address: %s",
+                            nl_geterror(err));
+}
+
+void nl_cli_ct_parse_src_port(struct nfnl_ct *ct, int reply, char *arg)
+{
+       uint32_t port = nl_cli_parse_u32(arg);
+       nfnl_ct_set_src_port(ct, reply, port);
+}
+
+void nl_cli_ct_parse_dst_port(struct nfnl_ct *ct, int reply, char *arg)
+{
+       uint32_t port = nl_cli_parse_u32(arg);
+       nfnl_ct_set_dst_port(ct, reply, port);
+}
+
+void nl_cli_ct_parse_tcp_state(struct nfnl_ct *ct, char *arg)
+{
+       int state;
+
+       if ((state = nfnl_ct_str2tcp_state(arg)) < 0)
+               nl_cli_fatal(state,
+                            "Unable to nl_cli_ct_parse tcp state \"%s\": %s",
+                            arg, nl_geterror(state));
+
+       nfnl_ct_set_tcp_state(ct, state);
+}
+
+void nl_cli_ct_parse_status(struct nfnl_ct *ct, char *arg)
+{
+       int status;
+
+       if ((status = nfnl_ct_str2status(arg)) < 0)
+               nl_cli_fatal(status,
+                            "Unable to nl_cli_ct_parse flags \"%s\": %s",
+                            arg, nl_geterror(status));
+
+       nfnl_ct_set_status(ct, status);
+}
+
+#if 0
+               } else if (arg_match("origicmpid")) {
+                       if (argc > ++idx)
+                               nfnl_ct_set_icmp_id(ct, 0, strtoul(argv[idx++], NULL, 0));
+               } else if (arg_match("origicmptype")) {
+                       if (argc > ++idx)
+                               nfnl_ct_set_icmp_type(ct, 0, strtoul(argv[idx++], NULL, 0));
+               } else if (arg_match("origicmpcode")) {
+                       if (argc > ++idx)
+                               nfnl_ct_set_icmp_code(ct, 0, strtoul(argv[idx++], NULL, 0));
+               } else if (arg_match("replyicmpid")) {
+                       if (argc > ++idx)
+                               nfnl_ct_set_icmp_id(ct, 1, strtoul(argv[idx++], NULL, 0));
+               } else if (arg_match("replyicmptype")) {
+                       if (argc > ++idx)
+                               nfnl_ct_set_icmp_type(ct, 1, strtoul(argv[idx++], NULL, 0));
+               } else if (arg_match("replyicmpcode")) {
+                       if (argc > ++idx)
+                               nfnl_ct_set_icmp_code(ct, 1, strtoul(argv[idx++], NULL, 0));
+               }
+#endif
+
+/** @} */
diff --git a/src/lib/exp.c b/src/lib/exp.c
new file mode 100644 (file)
index 0000000..a7a74f5
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * src/lib/exp.c               CLI Expectation Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_exp Expectation Tracking
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/exp.h>
+
+struct nfnl_exp *nl_cli_exp_alloc(void)
+{
+       struct nfnl_exp *exp;
+
+       exp = nfnl_exp_alloc();
+       if (!exp)
+               nl_cli_fatal(ENOMEM, "Unable to allocate expectation object");
+
+       return exp;
+}
+
+struct nl_cache *nl_cli_exp_alloc_cache(struct nl_sock *sk)
+{
+       return nl_cli_alloc_cache(sk, "expectation", nfnl_exp_alloc_cache);
+}
+
+void nl_cli_exp_parse_family(struct nfnl_exp *exp, char *arg)
+{
+       int family;
+
+       if ((family = nl_str2af(arg)) == AF_UNSPEC)
+               nl_cli_fatal(EINVAL,
+                            "Unable to nl_cli_exp_parse family \"%s\": %s",
+                            arg, nl_geterror(NLE_INVAL));
+
+       nfnl_exp_set_family(exp, family);
+}
+
+void nl_cli_exp_parse_timeout(struct nfnl_exp *exp, char *arg)
+{
+       uint32_t timeout = nl_cli_parse_u32(arg);
+       nfnl_exp_set_timeout(exp, timeout);
+}
+
+void nl_cli_exp_parse_id(struct nfnl_exp *exp, char *arg)
+{
+       uint32_t id = nl_cli_parse_u32(arg);
+       nfnl_exp_set_id(exp, id);
+}
+
+void nl_cli_exp_parse_helper_name(struct nfnl_exp *exp, char *arg)
+{
+       nfnl_exp_set_helper_name(exp, arg);
+}
+
+void nl_cli_exp_parse_zone(struct nfnl_exp *exp, char *arg)
+{
+       uint32_t zone = nl_cli_parse_u32(arg);
+       nfnl_exp_set_zone(exp, zone);
+}
+
+void nl_cli_exp_parse_flags(struct nfnl_exp *exp, char *arg)
+{
+       uint32_t flags = nl_cli_parse_u32(arg);
+       nfnl_exp_set_flags(exp, flags);
+}
+
+void nl_cli_exp_parse_class(struct nfnl_exp *exp, char *arg)
+{
+       uint32_t class = nl_cli_parse_u32(arg);
+       nfnl_exp_set_class(exp, class);
+}
+
+void nl_cli_exp_parse_nat_dir(struct nfnl_exp *exp, char *arg)
+{
+       uint32_t nat_dir = nl_cli_parse_u32(arg);
+       nfnl_exp_set_nat_dir(exp, nat_dir);
+}
+
+void nl_cli_exp_parse_fn(struct nfnl_exp *exp, char *arg)
+{
+       nfnl_exp_set_fn(exp, arg);
+}
+
+void nl_cli_exp_parse_src(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       int err;
+       struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_exp_get_family(exp));
+       if ((err = nfnl_exp_set_src(exp, tuple, a)) < 0)
+               nl_cli_fatal(err, "Unable to set source address: %s",
+                            nl_geterror(err));
+}
+
+void nl_cli_exp_parse_dst(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       int err;
+       struct nl_addr *a = nl_cli_addr_parse(arg, nfnl_exp_get_family(exp));
+       if ((err = nfnl_exp_set_dst(exp, tuple, a)) < 0)
+               nl_cli_fatal(err, "Unable to set destination address: %s",
+                            nl_geterror(err));
+}
+
+void nl_cli_exp_parse_l4protonum(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       int l4protonum;
+
+       if ((l4protonum = nl_str2ip_proto(arg)) < 0)
+               nl_cli_fatal(l4protonum,
+                       "Unable to nl_cli_exp_parse protocol \"%s\": %s",
+                       arg, nl_geterror(l4protonum));
+
+       nfnl_exp_set_l4protonum(exp, tuple, l4protonum);
+}
+
+void nl_cli_exp_parse_src_port(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       uint32_t sport = nl_cli_parse_u32(arg);
+       uint16_t dport = nfnl_exp_get_dst_port(exp, tuple);
+       nfnl_exp_set_ports(exp, tuple, sport, dport);
+}
+
+void nl_cli_exp_parse_dst_port(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       uint32_t dport = nl_cli_parse_u32(arg);
+       uint16_t sport = nfnl_exp_get_src_port(exp, tuple);
+       nfnl_exp_set_ports(exp, tuple, sport, dport);
+}
+
+void nl_cli_exp_parse_icmp_id(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       uint32_t id = nl_cli_parse_u32(arg);
+       uint8_t type = nfnl_exp_get_icmp_type(exp, tuple);
+       uint8_t code = nfnl_exp_get_icmp_code(exp, tuple);
+       nfnl_exp_set_icmp(exp, tuple, id, type, code);
+}
+
+void nl_cli_exp_parse_icmp_type(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       uint32_t type = nl_cli_parse_u32(arg);
+       uint16_t id = nfnl_exp_get_icmp_id(exp, tuple);
+       uint8_t code = nfnl_exp_get_icmp_code(exp, tuple);
+       nfnl_exp_set_icmp(exp, tuple, id, type, code);
+}
+
+void nl_cli_exp_parse_icmp_code(struct nfnl_exp *exp, int tuple, char *arg)
+{
+       uint32_t code = nl_cli_parse_u32(arg);
+       uint16_t id = nfnl_exp_get_icmp_id(exp, tuple);
+       uint8_t type = nfnl_exp_get_icmp_type(exp, tuple);
+       nfnl_exp_set_icmp(exp, tuple, id, type, code);
+}
+
+/** @} */
diff --git a/src/lib/link.c b/src/lib/link.c
new file mode 100644 (file)
index 0000000..5bce824
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * src/lib/link.c     CLI Link Helpers
+ *
+ *     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-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_link Links
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <linux/if.h>
+
+struct rtnl_link *nl_cli_link_alloc(void)
+{
+       struct rtnl_link *link;
+
+       link = rtnl_link_alloc();
+       if (!link)
+               nl_cli_fatal(ENOMEM, "Unable to allocate link object");
+
+       return link;
+}
+
+struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *sock, int family)
+{
+       struct nl_cache *cache;
+       int err;
+
+       if ((err = rtnl_link_alloc_cache(sock, family, &cache)) < 0)
+               nl_cli_fatal(err, "Unable to allocate link cache: %s",
+                            nl_geterror(err));
+
+       nl_cache_mngt_provide(cache);
+
+       return cache;
+}
+
+struct nl_cache *nl_cli_link_alloc_cache(struct nl_sock *sock)
+{
+       return nl_cli_link_alloc_cache_family(sock, AF_UNSPEC);
+}
+
+void nl_cli_link_parse_family(struct rtnl_link *link, char *arg)
+{
+       int family;
+
+       if ((family = nl_str2af(arg)) < 0)
+               nl_cli_fatal(EINVAL,
+                            "Unable to translate address family \"%s\"", arg);
+
+       rtnl_link_set_family(link, family);
+}
+
+void nl_cli_link_parse_name(struct rtnl_link *link, char *arg)
+{
+       rtnl_link_set_name(link, arg);
+}
+
+void nl_cli_link_parse_mtu(struct rtnl_link *link, char *arg)
+{
+       uint32_t mtu = nl_cli_parse_u32(arg);
+       rtnl_link_set_mtu(link, mtu);
+}
+
+void nl_cli_link_parse_ifindex(struct rtnl_link *link, char *arg)
+{
+       uint32_t index = nl_cli_parse_u32(arg);
+       rtnl_link_set_ifindex(link, index);
+}
+
+void nl_cli_link_parse_txqlen(struct rtnl_link *link, char *arg)
+{
+       uint32_t qlen = nl_cli_parse_u32(arg);
+       rtnl_link_set_txqlen(link, qlen);
+}
+
+void nl_cli_link_parse_weight(struct rtnl_link *link, char *arg)
+{
+}
+
+void nl_cli_link_parse_ifalias(struct rtnl_link *link, char *arg)
+{
+       if (strlen(arg) > IFALIASZ)
+               nl_cli_fatal(ERANGE,
+                       "Link ifalias too big, must not exceed %u in length.",
+                       IFALIASZ);
+
+       rtnl_link_set_ifalias(link, arg);
+}
+
+/** @} */
diff --git a/src/lib/neigh.c b/src/lib/neigh.c
new file mode 100644 (file)
index 0000000..a814bd8
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * src/lib/neigh.c     CLI Neighbour Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_neigh Neighbour
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/neigh.h>
+
+struct rtnl_neigh *nl_cli_neigh_alloc(void)
+{
+       struct rtnl_neigh *neigh;
+
+       neigh = rtnl_neigh_alloc();
+       if (!neigh)
+               nl_cli_fatal(ENOMEM, "Unable to allocate neighbout object");
+
+       return neigh;
+}
+
+void nl_cli_neigh_parse_dst(struct rtnl_neigh *neigh, char *arg)
+{
+       struct nl_addr *a;
+       int err;
+
+       a = nl_cli_addr_parse(arg, rtnl_neigh_get_family(neigh));
+       if ((err = rtnl_neigh_set_dst(neigh, a)) < 0)
+               nl_cli_fatal(err, "Unable to set local address: %s",
+                       nl_geterror(err));
+
+       nl_addr_put(a);
+}
+
+void nl_cli_neigh_parse_lladdr(struct rtnl_neigh *neigh, char *arg)
+{
+       struct nl_addr *a;
+
+       a = nl_cli_addr_parse(arg, AF_UNSPEC);
+       rtnl_neigh_set_lladdr(neigh, a);
+       nl_addr_put(a);
+}
+
+void nl_cli_neigh_parse_dev(struct rtnl_neigh *neigh,
+                           struct nl_cache *link_cache, char *arg)
+{
+       int ival;
+
+       if (!(ival = rtnl_link_name2i(link_cache, arg)))
+               nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+       rtnl_neigh_set_ifindex(neigh, ival);
+}
+
+void nl_cli_neigh_parse_family(struct rtnl_neigh *neigh, char *arg)
+{
+       int family;
+
+       if ((family = nl_str2af(arg)) == AF_UNSPEC)
+               nl_cli_fatal(EINVAL,
+                            "Unable to translate address family \"%s\"", arg);
+
+       rtnl_neigh_set_family(neigh, family);
+}
+
+void nl_cli_neigh_parse_state(struct rtnl_neigh *neigh, char *arg)
+{
+       int state;
+       
+       if ((state = rtnl_neigh_str2state(arg)) < 0)
+               nl_cli_fatal(state, "Unable to translate state \"%s\": %s",
+                       arg, state);
+
+       rtnl_neigh_set_state(neigh, state);
+}
+
+/** @} */
diff --git a/src/lib/qdisc.c b/src/lib/qdisc.c
new file mode 100644 (file)
index 0000000..ccf7d26
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * src/lib/qdisc.c     CLI QDisc Helpers
+ *
+ *     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-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_qdisc Queueing Disciplines
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/qdisc.h>
+#include <netlink/route/class.h>
+
+struct rtnl_qdisc *nl_cli_qdisc_alloc(void)
+{
+       struct rtnl_qdisc *qdisc;
+
+       if (!(qdisc = rtnl_qdisc_alloc()))
+               nl_cli_fatal(ENOMEM, "Unable to allocate qdisc object");
+
+       return qdisc;
+}
+
+/** @} */
diff --git a/src/lib/route.c b/src/lib/route.c
new file mode 100644 (file)
index 0000000..cd3e897
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * src/lib/route.c     CLI Route Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_route Routing
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/route.h>
+
+struct rtnl_route *nl_cli_route_alloc(void)
+{
+       struct rtnl_route *route;
+
+       route = rtnl_route_alloc();
+       if (!route)
+               nl_cli_fatal(ENOMEM, "Unable to allocate route object");
+
+       return route;
+}
+
+struct nl_cache *nl_cli_route_alloc_cache(struct nl_sock *sk, int flags)
+{
+       struct nl_cache *cache;
+       int err;
+
+       if ((err = rtnl_route_alloc_cache(sk, AF_UNSPEC, flags, &cache)) < 0)
+               nl_cli_fatal(err, "Unable to allocate route cache: %s\n",
+                            nl_geterror(err));
+
+       nl_cache_mngt_provide(cache);
+
+       return cache;
+}
+
+void nl_cli_route_parse_family(struct rtnl_route *route, char *arg)
+{
+       int family;
+
+       if ((family = nl_str2af(arg)) != AF_UNSPEC)
+               rtnl_route_set_family(route, family);
+}
+
+void nl_cli_route_parse_dst(struct rtnl_route *route, char *arg)
+{
+       struct nl_addr *addr;
+       int err;
+
+       addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
+       if ((err = rtnl_route_set_dst(route, addr)) < 0)
+               nl_cli_fatal(err, "Unable to set destination address: %s",
+                     nl_geterror(err));
+
+       nl_addr_put(addr);
+}
+
+void nl_cli_route_parse_src(struct rtnl_route *route, char *arg)
+{
+       struct nl_addr *addr;
+       int err;
+
+       addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
+       if ((err = rtnl_route_set_src(route, addr)) < 0)
+               nl_cli_fatal(err, "Unable to set source address: %s",
+                     nl_geterror(err));
+
+       nl_addr_put(addr);
+}
+
+void nl_cli_route_parse_pref_src(struct rtnl_route *route, char *arg)
+{
+       struct nl_addr *addr;
+       int err;
+
+       addr = nl_cli_addr_parse(arg, rtnl_route_get_family(route));
+       if ((err = rtnl_route_set_pref_src(route, addr)) < 0)
+               nl_cli_fatal(err, "Unable to set preferred source address: %s",
+                     nl_geterror(err));
+
+       nl_addr_put(addr);
+}
+
+void nl_cli_route_parse_metric(struct rtnl_route *route, char *subopts)
+{
+       /* strict equal order to RTAX_* */
+       static char *const tokens[] = {
+               "unspec",
+               "lock",
+               "mtu",
+               "window",
+               "rtt",
+               "rttvar",
+               "sstresh",
+               "cwnd",
+               "advmss",
+               "reordering",
+               "hoplimit",
+               "initcwnd",
+               "features",
+               NULL,
+       };
+       unsigned long lval;
+       char *arg, *endptr;
+
+       while (*subopts != '\0') {
+               int ret = getsubopt(&subopts, tokens, &arg);
+               if (ret == -1)
+                       nl_cli_fatal(EINVAL, "Unknown metric token \"%s\"", arg);
+
+               if (ret == 0)
+                       nl_cli_fatal(EINVAL, "Invalid metric \"%s\"", tokens[ret]);
+
+               if (arg == NULL)
+                       nl_cli_fatal(EINVAL, "Metric \"%s\", no value given", tokens[ret]);
+
+               lval = strtoul(arg, &endptr, 0);
+               if (endptr == arg)
+                       nl_cli_fatal(EINVAL, "Metric \"%s\", value not numeric", tokens[ret]);
+
+               if ((ret = rtnl_route_set_metric(route, ret, lval)) < 0)
+                       nl_cli_fatal(ret, "Unable to set metric: %s",
+                             nl_geterror(ret));
+       }
+}
+
+void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts,
+                  struct nl_cache *link_cache)
+{
+       enum {
+               NH_DEV,
+               NH_VIA,
+               NH_WEIGHT,
+       };
+       static char *const tokens[] = {
+               "dev",
+               "via",
+               "weight",
+               NULL,
+       };
+       struct rtnl_nexthop *nh;
+       unsigned long lval;
+       struct nl_addr *addr;
+       int ival;
+       char *arg, *endptr;
+
+       if (!(nh = rtnl_route_nh_alloc()))
+               nl_cli_fatal(ENOMEM, "Out of memory");
+
+       while (*subopts != '\0') {
+               int ret = getsubopt(&subopts, tokens, &arg);
+               if (ret == -1)
+                       nl_cli_fatal(EINVAL, "Unknown nexthop token \"%s\"", arg);
+
+               if (arg == NULL)
+                       nl_cli_fatal(EINVAL, "Missing argument to option \"%s\"\n",
+                               tokens[ret]);
+
+               switch (ret) {
+               case NH_DEV:
+                       if (!(ival = rtnl_link_name2i(link_cache, arg)))
+                               nl_cli_fatal(ENOENT,"Link \"%s\" does not exist", arg);
+
+                       rtnl_route_nh_set_ifindex(nh, ival);
+                       break;
+
+               case NH_VIA:
+                       addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route));
+                       rtnl_route_nh_set_gateway(nh, addr);
+                       nl_addr_put(addr);
+                       break;
+
+               case NH_WEIGHT:
+                       lval = strtoul(arg, &endptr, 0);
+                       if (endptr == arg)
+                               nl_cli_fatal(EINVAL,
+                                            "Invalid weight \"%s\", not numeric",
+                                            arg);
+                       rtnl_route_nh_set_weight(nh, lval);
+                       break;
+               }
+       }
+
+       rtnl_route_add_nexthop(route, nh);
+}
+
+void nl_cli_route_parse_table(struct rtnl_route *route, char *arg)
+{
+       unsigned long lval;
+       char *endptr;
+       int table;
+
+       lval = strtoul(arg, &endptr, 0);
+       if (endptr == arg) {
+               if ((table = rtnl_route_str2table(arg)) < 0)
+                       nl_cli_fatal(EINVAL, "Unknown table name \"%s\"", arg);
+       }
+       else {
+               table = lval;
+       }
+
+       rtnl_route_set_table(route, table);
+}
+
+void nl_cli_route_parse_prio(struct rtnl_route *route, char *arg)
+{
+       unsigned long lval;
+       char *endptr;
+
+       lval = strtoul(arg, &endptr, 0);
+       if (endptr == arg)
+               nl_cli_fatal(EINVAL, "Invalid priority value, not numeric");
+       rtnl_route_set_priority(route, lval);
+}
+
+void nl_cli_route_parse_scope(struct rtnl_route *route, char *arg)
+{
+       int ival;
+
+       if ((ival = rtnl_str2scope(arg)) < 0)
+               nl_cli_fatal(EINVAL, "Unknown routing scope \"%s\"", arg);
+
+       rtnl_route_set_scope(route, ival);
+}
+
+void nl_cli_route_parse_protocol(struct rtnl_route *route, char *arg)
+{
+       unsigned long lval;
+       char *endptr;
+       int proto;
+
+       lval = strtoul(arg, &endptr, 0);
+       if (endptr == arg) {
+               if ((proto = rtnl_route_str2proto(arg)) < 0)
+                       nl_cli_fatal(EINVAL,
+                                    "Unknown routing protocol name \"%s\"",
+                                    arg);
+       }
+       else {
+               proto = lval;
+       }
+
+       rtnl_route_set_protocol(route, proto);
+}
+
+void nl_cli_route_parse_type(struct rtnl_route *route, char *arg)
+{
+       int ival;
+
+       if ((ival = nl_str2rtntype(arg)) < 0)
+               nl_cli_fatal(EINVAL, "Unknown routing type \"%s\"", arg);
+
+       if ((ival = rtnl_route_set_type(route, ival)) < 0)
+               nl_cli_fatal(ival, "Unable to set routing type: %s",
+                     nl_geterror(ival));
+}
+
+void nl_cli_route_parse_iif(struct rtnl_route *route, char *arg, struct nl_cache *link_cache)
+{
+       int ival;
+
+       if (!(ival = rtnl_link_name2i(link_cache, arg)))
+               nl_cli_fatal(ENOENT, "Link \"%s\" does not exist", arg);
+
+       rtnl_route_set_iif(route, ival);
+}
+
+/** @} */
diff --git a/src/lib/rule.c b/src/lib/rule.c
new file mode 100644 (file)
index 0000000..96f1d4c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * src/lib/rule.c     CLI Routing Rule Helpers
+ *
+ *     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-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @ingroup cli
+ * @defgroup cli_rule Routing Rules
+ *
+ * @{
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/rule.h>
+
+struct rtnl_rule *nl_cli_rule_alloc(void)
+{
+       struct rtnl_rule *rule;
+
+       rule = rtnl_rule_alloc();
+       if (!rule)
+               nl_cli_fatal(ENOMEM, "Unable to allocate rule object");
+
+       return rule;
+}
+
+struct nl_cache *nl_cli_rule_alloc_cache(struct nl_sock *sk)
+{
+       struct nl_cache *cache;
+       int err;
+
+       if ((err = rtnl_rule_alloc_cache(sk, AF_UNSPEC, &cache)) < 0)
+               nl_cli_fatal(err, "Unable to allocate routing rule cache: %s\n",
+                            nl_geterror(err));
+
+       nl_cache_mngt_provide(cache);
+
+       return cache;
+}
+
+void nl_cli_rule_parse_family(struct rtnl_rule *rule, char *arg)
+{
+       int family;
+
+       if ((family = nl_str2af(arg)) != AF_UNSPEC)
+               rtnl_rule_set_family(rule, family);
+}
+
+/** @} */
diff --git a/src/lib/tc.c b/src/lib/tc.c
new file mode 100644 (file)
index 0000000..dde729f
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * src/lib/tc.c     CLI Traffic Control Helpers
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink-private/route/tc-api.h>
+
+/**
+ * @ingroup cli
+ * @defgroup cli_tc Traffic Control
+ * @{
+ */
+void nl_cli_tc_parse_dev(struct rtnl_tc *tc, struct nl_cache *link_cache, char *name)
+{
+       struct rtnl_link *link;
+       
+       link = rtnl_link_get_by_name(link_cache, name);
+       if (!link)
+               nl_cli_fatal(ENOENT, "Link \"%s\" does not exist.", name);
+
+       rtnl_tc_set_link(tc, link);
+       rtnl_link_put(link);
+}
+
+void nl_cli_tc_parse_parent(struct rtnl_tc *tc, char *arg)
+{
+       uint32_t parent;
+       int err;
+
+       if ((err = rtnl_tc_str2handle(arg, &parent)) < 0)
+               nl_cli_fatal(err, "Unable to parse handle \"%s\": %s",
+                     arg, nl_geterror(err));
+
+       rtnl_tc_set_parent(tc, parent);
+}
+
+void nl_cli_tc_parse_handle(struct rtnl_tc *tc, char *arg, int create)
+{
+       uint32_t handle, parent;
+       int err;
+
+       parent = rtnl_tc_get_parent(tc);
+
+       if ((err = rtnl_tc_str2handle(arg, &handle)) < 0) {
+               if (err == -NLE_OBJ_NOTFOUND && create)
+                       err = rtnl_classid_generate(arg, &handle, parent);
+
+               if (err < 0)
+                       nl_cli_fatal(err, "Unable to parse handle \"%s\": %s",
+                                    arg, nl_geterror(err));
+       }
+
+       rtnl_tc_set_handle(tc, handle);
+}
+
+void nl_cli_tc_parse_mtu(struct rtnl_tc *tc, char *arg)
+{
+       rtnl_tc_set_mtu(tc, nl_cli_parse_u32(arg));
+}
+
+void nl_cli_tc_parse_mpu(struct rtnl_tc *tc, char *arg)
+{
+       rtnl_tc_set_mpu(tc, nl_cli_parse_u32(arg));
+}
+
+void nl_cli_tc_parse_overhead(struct rtnl_tc *tc, char *arg)
+{
+       rtnl_tc_set_overhead(tc, nl_cli_parse_u32(arg));
+}
+
+void nl_cli_tc_parse_kind(struct rtnl_tc *tc, char *arg)
+{
+       rtnl_tc_set_kind(tc, arg);
+}
+
+void nl_cli_tc_parse_linktype(struct rtnl_tc *tc, char *arg)
+{
+       int type;
+
+       if ((type = nl_str2llproto(arg)) < 0)
+               nl_cli_fatal(type, "Unable to parse linktype \"%s\": %s",
+                       arg, nl_geterror(type));
+
+       rtnl_tc_set_linktype(tc, type);
+}
+
+static NL_LIST_HEAD(tc_modules);
+
+static struct nl_cli_tc_module *__nl_cli_tc_lookup(struct rtnl_tc_ops *ops)
+{
+       struct nl_cli_tc_module *tm;
+
+       nl_list_for_each_entry(tm, &tc_modules, tm_list)
+               if (tm->tm_ops == ops)
+                       return tm;
+
+       return NULL;
+}
+
+struct nl_cli_tc_module *nl_cli_tc_lookup(struct rtnl_tc_ops *ops)
+{
+       struct nl_cli_tc_module *tm;
+
+       if ((tm = __nl_cli_tc_lookup(ops)))
+               return tm;
+
+       switch (ops->to_type) {
+       case RTNL_TC_TYPE_QDISC:
+       case RTNL_TC_TYPE_CLASS:
+               nl_cli_load_module("cli/qdisc", ops->to_kind);
+               break;
+
+       case RTNL_TC_TYPE_CLS:
+               nl_cli_load_module("cli/cls", ops->to_kind);
+               break;
+
+       default:
+               nl_cli_fatal(EINVAL, "BUG: unhandled TC object type %d",
+                               ops->to_type);
+       }
+
+       if (!(tm = __nl_cli_tc_lookup(ops)))  {
+               nl_cli_fatal(EINVAL, "Application bug: The shared library for "
+                       "the tc object \"%s\" was successfully loaded but it "
+                       "seems that module did not register itself",
+                       ops->to_kind);
+       }
+
+       return tm;
+}
+
+void nl_cli_tc_register(struct nl_cli_tc_module *tm)
+{
+       struct rtnl_tc_ops *ops;
+
+       if (!(ops = rtnl_tc_lookup_ops(tm->tm_type, tm->tm_name))) {
+               nl_cli_fatal(ENOENT, "Unable to register CLI TC module "
+               "\"%s\": No matching libnl TC module found.", tm->tm_name);
+       }
+
+       if (__nl_cli_tc_lookup(ops)) {
+               nl_cli_fatal(EEXIST, "Unable to register CLI TC module "
+               "\"%s\": Module already registered.", tm->tm_name);
+       }
+
+       tm->tm_ops = ops;
+
+       nl_list_add_tail(&tm->tm_list, &tc_modules);
+}
+
+void nl_cli_tc_unregister(struct nl_cli_tc_module *tm)
+{
+       nl_list_del(&tm->tm_list);
+}
+
+
+/** @} */
diff --git a/src/lib/utils.c b/src/lib/utils.c
new file mode 100644 (file)
index 0000000..e5eacde
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * src/utils.c         Utilities
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+/**
+ * @defgroup cli Command Line Interface API
+ *
+ * @{
+ *
+ * These modules provide an interface for text based applications. The
+ * functions provided are wrappers for their libnl equivalent with
+ * added error handling. The functions check for allocation failures,
+ * invalid input, and unknown types and will print error messages
+ * accordingly via nl_cli_fatal().
+ */
+
+#include <netlink/cli/utils.h>
+
+/**
+ * Parse a text based 32 bit unsigned integer argument
+ * @arg arg            Integer in text form.
+ *
+ * Tries to convert the number provided in arg to a uint32_t. Will call
+ * nl_cli_fatal() if the conversion fails.
+ *
+ * @return 32bit unsigned integer.
+ */
+uint32_t nl_cli_parse_u32(const char *arg)
+{
+       unsigned long lval;
+       char *endptr;
+
+       lval = strtoul(arg, &endptr, 0);
+       if (endptr == arg || lval == ULONG_MAX)
+               nl_cli_fatal(EINVAL, "Unable to parse \"%s\", not a number.",
+                            arg);
+
+       return (uint32_t) lval;
+}
+
+void nl_cli_print_version(void)
+{
+       printf("libnl tools version %s\n", LIBNL_VERSION);
+       printf(
+       "Copyright (C) 2003-2010 Thomas Graf <tgraf@redhat.com>\n"
+       "\n"
+       "This program comes with ABSOLUTELY NO WARRANTY. This is free \n"
+       "software, and you are welcome to redistribute it under certain\n"
+       "conditions. See the GNU General Public License for details.\n"
+       );
+
+       exit(0);
+}
+
+/**
+ * Print error message and quit application
+ * @arg err            Error code.
+ * @arg fmt            Error message.
+ *
+ * Prints the formatted error message to stderr and quits the application
+ * using the provided error code.
+ */
+void nl_cli_fatal(int err, const char *fmt, ...)
+{
+       va_list ap;
+       char buf[256];
+
+       fprintf(stderr, "Error: ");
+
+       if (fmt) {
+               va_start(ap, fmt);
+               vfprintf(stderr, fmt, ap);
+               va_end(ap);
+               fprintf(stderr, "\n");
+       } else
+               fprintf(stderr, "%s\n", strerror_r(err, buf, sizeof(buf)));
+
+       exit(abs(err));
+}
+
+int nl_cli_connect(struct nl_sock *sk, int protocol)
+{
+       int err;
+
+       if ((err = nl_connect(sk, protocol)) < 0)
+               nl_cli_fatal(err, "Unable to connect netlink socket: %s",
+                            nl_geterror(err));
+
+       return err;
+}
+
+struct nl_sock *nl_cli_alloc_socket(void)
+{
+       struct nl_sock *sock;
+
+       if (!(sock = nl_socket_alloc()))
+               nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket");
+
+       return sock;
+}
+
+struct nl_addr *nl_cli_addr_parse(const char *str, int family)
+{
+       struct nl_addr *addr;
+       int err;
+
+       if ((err = nl_addr_parse(str, family, &addr)) < 0)
+               nl_cli_fatal(err, "Unable to parse address \"%s\": %s",
+                            str, nl_geterror(err));
+
+       return addr;
+}
+
+int nl_cli_parse_dumptype(const char *str)
+{
+       if (!strcasecmp(str, "brief"))
+               return NL_DUMP_LINE;
+       else if (!strcasecmp(str, "details") || !strcasecmp(str, "detailed"))
+               return NL_DUMP_DETAILS;
+       else if (!strcasecmp(str, "stats"))
+               return NL_DUMP_STATS;
+       else
+               nl_cli_fatal(EINVAL, "Invalid dump type \"%s\".\n", str);
+
+       return 0;
+}
+
+int nl_cli_confirm(struct nl_object *obj, struct nl_dump_params *params,
+                  int default_yes)
+{
+       nl_object_dump(obj, params);
+
+       for (;;) {
+               char buf[32] = { 0 };
+               int answer;
+
+               printf("Delete? (%c/%c) ",
+                       default_yes ? 'Y' : 'y',
+                       default_yes ? 'n' : 'N');
+
+               if (!fgets(buf, sizeof(buf), stdin)) {
+                       fprintf(stderr, "Error while reading\n.");
+                       continue;
+               }
+
+               switch ((answer = tolower(buf[0]))) {
+               case '\n':
+                       answer = default_yes ? 'y' : 'n';
+               case 'y':
+               case 'n':
+                       return answer == 'y';
+               }
+
+               fprintf(stderr, "Invalid input, try again.\n");
+       }
+
+       return 0;
+
+}
+
+struct nl_cache *nl_cli_alloc_cache(struct nl_sock *sock, const char *name,
+                           int (*ac)(struct nl_sock *, struct nl_cache **))
+{
+       struct nl_cache *cache;
+       int err;
+
+       if ((err = ac(sock, &cache)) < 0)
+               nl_cli_fatal(err, "Unable to allocate %s cache: %s",
+                            name, nl_geterror(err));
+
+       nl_cache_mngt_provide(cache);
+
+       return cache;
+}
+
+void nl_cli_load_module(const char *prefix, const char *name)
+{
+       char path[FILENAME_MAX+1];
+       void *handle;
+
+       snprintf(path, sizeof(path), "%s/%s/%s.so",
+                PKGLIBDIR, prefix, name);
+
+       if (!(handle = dlopen(path, RTLD_NOW)))
+               nl_cli_fatal(ENOENT, "Unable to load module \"%s\": %s\n",
+                       path, dlerror());
+}
+
+/** @} */
diff --git a/src/nf-ct-list.c b/src/nf-ct-list.c
new file mode 100644 (file)
index 0000000..5f72998
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * src/nf-ct-list.c     List Conntrack Entries
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/ct.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nf-ct-list [OPTION]... [CONNTRACK ENTRY]\n"
+       "\n"
+       "Options\n"
+       " -f, --format=TYPE     Output format { brief | details | stats }\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Conntrack Selection\n"
+       " -i, --id=NUM            Identifier\n"
+       " -p, --proto=PROTOCOL    Protocol\n"
+       "     --tcp-state=STATE   TCP connection state\n"
+       "     --orig-src=ADDR     Original source address\n"
+       "     --orig-sport=PORT   Original source port\n"
+       "     --orig-dst=ADDR     Original destination address\n"
+       "     --orig-dport=PORT   Original destination port\n"
+       "     --reply-src=ADDR    Reply source address\n"
+       "     --reply-sport=PORT  Reply source port\n"
+       "     --reply-dst=ADDR    Reply destination address\n"
+       "     --reply-dport=PORT  Reply destination port\n"
+       " -F, --family=FAMILY     Address family\n"
+       "     --mark=NUM          Mark value\n"
+       "     --timeout=NUM       Timeout value\n"
+       "     --refcnt=NUM        Use counter value\n"
+       "     --flags             Flags\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *ct_cache;
+       struct nfnl_ct *ct;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       ct = nl_cli_ct_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_MARK = 257,
+                       ARG_TCP_STATE = 258,
+                       ARG_ORIG_SRC,
+                       ARG_ORIG_SPORT,
+                       ARG_ORIG_DST,
+                       ARG_ORIG_DPORT,
+                       ARG_REPLY_SRC,
+                       ARG_REPLY_SPORT,
+                       ARG_REPLY_DST,
+                       ARG_REPLY_DPORT,
+                       ARG_TIMEOUT,
+                       ARG_REFCNT,
+                       ARG_FLAGS,
+               };
+               static struct option long_opts[] = {
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "id", 1, 0, 'i' },
+                       { "proto", 1, 0, 'p' },
+                       { "tcp-state", 1, 0, ARG_TCP_STATE },
+                       { "orig-src", 1, 0, ARG_ORIG_SRC },
+                       { "orig-sport", 1, 0, ARG_ORIG_SPORT },
+                       { "orig-dst", 1, 0, ARG_ORIG_DST },
+                       { "orig-dport", 1, 0, ARG_ORIG_DPORT },
+                       { "reply-src", 1, 0, ARG_REPLY_SRC },
+                       { "reply-sport", 1, 0, ARG_REPLY_SPORT },
+                       { "reply-dst", 1, 0, ARG_REPLY_DST },
+                       { "reply-dport", 1, 0, ARG_REPLY_DPORT },
+                       { "family", 1, 0, 'F' },
+                       { "mark", 1, 0, ARG_MARK },
+                       { "timeout", 1, 0, ARG_TIMEOUT },
+                       { "refcnt", 1, 0, ARG_REFCNT },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': exit(NLE_INVAL);
+               case '4': nfnl_ct_set_family(ct, AF_INET); break;
+               case '6': nfnl_ct_set_family(ct, AF_INET6); break;
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'i': nl_cli_ct_parse_id(ct, optarg); break;
+               case 'p': nl_cli_ct_parse_protocol(ct, optarg); break;
+               case ARG_TCP_STATE: nl_cli_ct_parse_tcp_state(ct, optarg); break;
+               case ARG_ORIG_SRC: nl_cli_ct_parse_src(ct, 0, optarg); break;
+               case ARG_ORIG_SPORT: nl_cli_ct_parse_src_port(ct, 0, optarg); break;
+               case ARG_ORIG_DST: nl_cli_ct_parse_dst(ct, 0, optarg); break;
+               case ARG_ORIG_DPORT: nl_cli_ct_parse_dst_port(ct, 0, optarg); break;
+               case ARG_REPLY_SRC: nl_cli_ct_parse_src(ct, 1, optarg); break;
+               case ARG_REPLY_SPORT: nl_cli_ct_parse_src_port(ct, 1, optarg); break;
+               case ARG_REPLY_DST: nl_cli_ct_parse_dst(ct, 1, optarg); break;
+               case ARG_REPLY_DPORT: nl_cli_ct_parse_dst_port(ct, 1, optarg); break;
+               case 'F': nl_cli_ct_parse_family(ct, optarg); break;
+               case ARG_MARK: nl_cli_ct_parse_mark(ct, optarg); break;
+               case ARG_TIMEOUT: nl_cli_ct_parse_timeout(ct, optarg); break;
+               case ARG_REFCNT: nl_cli_ct_parse_use(ct, optarg); break;
+               case ARG_FLAGS: nl_cli_ct_parse_status(ct, optarg); break;
+               }
+       }
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_NETFILTER);
+       ct_cache = nl_cli_ct_alloc_cache(sock);
+
+       nl_cache_dump_filter(ct_cache, &params, OBJ_CAST(ct));
+
+       return 0;
+}
diff --git a/src/nf-exp-add.c b/src/nf-exp-add.c
new file mode 100644 (file)
index 0000000..4b7f9d9
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * src/nf-exp-add.c     Create an expectation
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
+ *
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/exp.h>
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nf-exp-list [OPTION]... [CONNTRACK ENTRY]\n"
+       "\n"
+       "Options\n"
+       "     --replace             Replace the address if it exists.\n"
+       " -q, --quiet               Do not print informal notifications.\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Expectation Selection\n"
+       " -i, --id=NUM                Identifier\n"
+       "     --expect-proto=PROTOCOL Expectation protocol\n"
+       "     --expect-src=ADDR       Expectation source address\n"
+       "     --expect-sport=PORT     Expectation source port\n"
+       "     --expect-dst=ADDR       Expectation destination address\n"
+       "     --expect-dport=PORT     Expectation destination port\n"
+       "     --master-proto=PROTOCOL Master conntrack protocol\n"
+       "     --master-src=ADDR       Master conntrack source address\n"
+       "     --master-sport=PORT     Master conntrack source port\n"
+       "     --master-dst=ADDR       Master conntrack destination address\n"
+       "     --master-dport=PORT     Master conntrack destination port\n"
+       "     --mask-proto=PROTOCOL   Mask protocol\n"
+       "     --mask-src=ADDR         Mask source address\n"
+       "     --mask-sport=PORT       Mask source port\n"
+       "     --mask-dst=ADDR         Mask destination address\n"
+       "     --mask-dport=PORT       Mask destination port\n"
+       " -F, --family=FAMILY         Address family\n"
+       "     --timeout=NUM           Timeout value\n"
+       "     --helper=STRING         Helper Name\n"
+       "     --flags                 Flags (Kernel 2.6.37)\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nfnl_exp *exp;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err, nlflags = NLM_F_CREATE;
+
+       exp = nl_cli_exp_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_MARK = 270,
+                       ARG_TCP_STATE = 271,
+                       ARG_EXPECT_PROTO,
+                       ARG_EXPECT_SRC,
+                       ARG_EXPECT_SPORT,
+                       ARG_EXPECT_DST,
+                       ARG_EXPECT_DPORT,
+                       ARG_MASTER_PROTO,
+                       ARG_MASTER_SRC,
+                       ARG_MASTER_SPORT,
+                       ARG_MASTER_DST,
+                       ARG_MASTER_DPORT,
+                       ARG_MASK_PROTO,
+                       ARG_MASK_SRC,
+                       ARG_MASK_SPORT,
+                       ARG_MASK_DST,
+                       ARG_MASK_DPORT,
+            ARG_NAT_PROTO,
+            ARG_NAT_SRC,
+            ARG_NAT_SPORT,
+            ARG_NAT_DST,
+            ARG_NAT_DPORT,
+            ARG_NAT_DIR,
+                       ARG_TIMEOUT,
+                       ARG_HELPER_NAME,
+                       ARG_REPLACE,
+                       ARG_FLAGS,
+               };
+               static struct option long_opts[] = {
+                       { "replace", 1, 0, ARG_REPLACE },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "id", 1, 0, 'i' },
+                       { "expect-proto", 1, 0, ARG_EXPECT_PROTO },
+                       { "expect-src", 1, 0, ARG_EXPECT_SRC },
+                       { "expect-sport", 1, 0, ARG_EXPECT_SPORT },
+                       { "expect-dst", 1, 0, ARG_EXPECT_DST },
+                       { "expect-dport", 1, 0, ARG_EXPECT_DPORT },
+                       { "master-proto", 1, 0, ARG_MASTER_PROTO },
+                       { "master-src", 1, 0, ARG_MASTER_SRC },
+                       { "master-sport", 1, 0, ARG_MASTER_SPORT },
+                       { "master-dst", 1, 0, ARG_MASTER_DST },
+                       { "master-dport", 1, 0, ARG_MASTER_DPORT },
+                       { "mask-proto", 1, 0, ARG_MASK_PROTO },
+                       { "mask-src", 1, 0, ARG_MASK_SRC },
+                       { "mask-sport", 1, 0, ARG_MASK_SPORT },
+                       { "mask-dst", 1, 0, ARG_MASK_DST },
+                       { "mask-dport", 1, 0, ARG_MASK_DPORT },
+            { "nat-proto", 1, 0, ARG_NAT_PROTO },
+            { "nat-src", 1, 0, ARG_NAT_SRC },
+            { "nat-sport", 1, 0, ARG_NAT_SPORT },
+            { "nat-dst", 1, 0, ARG_NAT_DST },
+            { "nat-dport", 1, 0, ARG_NAT_DPORT },
+            { "nat-dir", 1, 0, ARG_NAT_DIR },
+                       { "family", 1, 0, 'F' },
+                       { "timeout", 1, 0, ARG_TIMEOUT },
+                       { "helper", 1, 0, ARG_HELPER_NAME },
+                       { "flags", 1, 0, ARG_FLAGS},
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': exit(NLE_INVAL);
+               case ARG_REPLACE: nlflags |= NLM_F_REPLACE; break;
+               case 'q': quiet = 1; break;
+               case '4': nfnl_exp_set_family(exp, AF_INET); break;
+               case '6': nfnl_exp_set_family(exp, AF_INET6); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'i': nl_cli_exp_parse_id(exp, optarg); break;
+               case ARG_EXPECT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_MASTER_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASK_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+        case ARG_NAT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+        case ARG_NAT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+        case ARG_NAT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+        case ARG_NAT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+        case ARG_NAT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+        case ARG_NAT_DIR: nl_cli_exp_parse_nat_dir(exp, optarg); break;
+               case 'F': nl_cli_exp_parse_family(exp, optarg); break;
+               case ARG_TIMEOUT: nl_cli_exp_parse_timeout(exp, optarg); break;
+               case ARG_HELPER_NAME: nl_cli_exp_parse_helper_name(exp, optarg); break;
+               case ARG_FLAGS: nl_cli_exp_parse_flags(exp, optarg); break;
+               }
+       }
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_NETFILTER);
+
+       if ((err = nfnl_exp_add(sock, exp, nlflags)) < 0)
+               nl_cli_fatal(err, "Unable to add expectation: %s", nl_geterror(err));
+
+       if (!quiet) {
+               printf("Added ");
+               nl_object_dump(OBJ_CAST(exp), &params);
+       }
+
+       return 0;
+}
diff --git a/src/nf-exp-delete.c b/src/nf-exp-delete.c
new file mode 100644 (file)
index 0000000..2ec45ae
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * src/nf-exp-delete.c     Delete an expectation
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/exp.h>
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nf-exp-list [OPTION]... [CONNTRACK ENTRY]\n"
+       "\n"
+       "Options\n"
+       "     --replace             Replace the address if it exists.\n"
+       " -q, --quiet               Do not print informal notifications.\n"
+       " -h, --help                Show this help\n"
+       " -v, --version             Show versioning information\n"
+       "\n"
+       "Expectation Selection\n"
+       " -i, --id=NUM                Identifier\n"
+       "     --expect-proto=PROTOCOL Expectation protocol\n"
+       "     --expect-src=ADDR       Expectation source address\n"
+       "     --expect-sport=PORT     Expectation source port\n"
+       "     --expect-dst=ADDR       Expectation destination address\n"
+       "     --expect-dport=PORT     Expectation destination port\n"
+       "     --master-proto=PROTOCOL Master conntrack protocol\n"
+       "     --master-src=ADDR       Master conntrack source address\n"
+       "     --master-sport=PORT     Master conntrack source port\n"
+       "     --master-dst=ADDR       Master conntrack destination address\n"
+       "     --master-dport=PORT     Master conntrack destination port\n"
+       "     --mask-proto=PROTOCOL   Mask protocol\n"
+       "     --mask-src=ADDR         Mask source address\n"
+       "     --mask-sport=PORT       Mask source port\n"
+       "     --mask-dst=ADDR         Mask destination address\n"
+       "     --mask-dport=PORT       Mask destination port\n"
+       " -F, --family=FAMILY         Address family\n"
+       "     --timeout=NUM           Timeout value\n"
+       "     --helper=STRING         Helper Name\n"
+       "     --flags                 Flags\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nfnl_exp *exp;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err, nlflags = 0;
+
+       exp = nl_cli_exp_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_MARK = 270,
+                       ARG_TCP_STATE = 271,
+                       ARG_EXPECT_PROTO,
+                       ARG_EXPECT_SRC,
+                       ARG_EXPECT_SPORT,
+                       ARG_EXPECT_DST,
+                       ARG_EXPECT_DPORT,
+                       ARG_MASTER_PROTO,
+                       ARG_MASTER_SRC,
+                       ARG_MASTER_SPORT,
+                       ARG_MASTER_DST,
+                       ARG_MASTER_DPORT,
+                       ARG_MASK_PROTO,
+                       ARG_MASK_SRC,
+                       ARG_MASK_SPORT,
+                       ARG_MASK_DST,
+                       ARG_MASK_DPORT,
+                       ARG_TIMEOUT,
+                       ARG_HELPER_NAME,
+                       ARG_FLAGS,
+               };
+               static struct option long_opts[] = {
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "id", 1, 0, 'i' },
+                       { "expect-proto", 1, 0, ARG_EXPECT_PROTO },
+                       { "expect-src", 1, 0, ARG_EXPECT_SRC },
+                       { "expect-sport", 1, 0, ARG_EXPECT_SPORT },
+                       { "expect-dst", 1, 0, ARG_EXPECT_DST },
+                       { "expect-dport", 1, 0, ARG_EXPECT_DPORT },
+                       { "master-proto", 1, 0, ARG_MASTER_PROTO },
+                       { "master-src", 1, 0, ARG_MASTER_SRC },
+                       { "master-sport", 1, 0, ARG_MASTER_SPORT },
+                       { "master-dst", 1, 0, ARG_MASTER_DST },
+                       { "master-dport", 1, 0, ARG_MASTER_DPORT },
+                       { "mask-proto", 1, 0, ARG_MASK_PROTO },
+                       { "mask-src", 1, 0, ARG_MASK_SRC },
+                       { "mask-sport", 1, 0, ARG_MASK_SPORT },
+                       { "mask-dst", 1, 0, ARG_MASK_DST },
+                       { "mask-dport", 1, 0, ARG_MASK_DPORT },
+                       { "family", 1, 0, 'F' },
+                       { "timeout", 1, 0, ARG_TIMEOUT },
+                       { "helper", 1, 0, ARG_HELPER_NAME },
+                       { "flags", 1, 0, ARG_FLAGS},
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': exit(NLE_INVAL);
+               case 'q': quiet = 1; break;
+               case '4': nfnl_exp_set_family(exp, AF_INET); break;
+               case '6': nfnl_exp_set_family(exp, AF_INET6); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'i': nl_cli_exp_parse_id(exp, optarg); break;
+               case ARG_EXPECT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_MASTER_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASK_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case ARG_MASK_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+               case 'F': nl_cli_exp_parse_family(exp, optarg); break;
+               case ARG_TIMEOUT: nl_cli_exp_parse_timeout(exp, optarg); break;
+               case ARG_HELPER_NAME: nl_cli_exp_parse_helper_name(exp, optarg); break;
+               case ARG_FLAGS: nl_cli_exp_parse_flags(exp, optarg); break;
+               }
+       }
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_NETFILTER);
+
+       if ((err = nfnl_exp_del(sock, exp, nlflags)) < 0)
+               nl_cli_fatal(err, "Unable to delete expectation: %s", nl_geterror(err));
+
+       if (!quiet) {
+               printf("Deleted ");
+               nl_object_dump(OBJ_CAST(exp), &params);
+       }
+
+       return 0;
+}
diff --git a/src/nf-exp-list.c b/src/nf-exp-list.c
new file mode 100644 (file)
index 0000000..1c6ec69
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * src/nf-exp-list.c     List Expectation Entries
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/exp.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nf-exp-list [OPTION]... [EXPECTATION ENTRY]\n"
+       "\n"
+       "Options\n"
+       " -f, --format=TYPE     Output format { brief | details }\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Expectation Selection\n"
+       " -i, --id=NUM                Identifier\n"
+       "     --expect-proto=PROTOCOL Expectation protocol\n"
+       "     --expect-src=ADDR       Expectation source address\n"
+       "     --expect-sport=PORT     Expectation source port\n"
+       "     --expect-dst=ADDR       Expectation destination address\n"
+       "     --expect-dport=PORT     Expectation destination port\n"
+       "     --master-proto=PROTOCOL Master conntrack protocol\n"
+       "     --master-src=ADDR       Master conntrack source address\n"
+       "     --master-sport=PORT     Master conntrack source port\n"
+       "     --master-dst=ADDR       Master conntrack destination address\n"
+       "     --master-dport=PORT     Master conntrack destination port\n"
+       " -F, --family=FAMILY         Address family\n"
+       "     --timeout=NUM           Timeout value\n"
+       "     --helper=STRING         Helper Name\n"
+       //"     --flags                 Flags\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *exp_cache;
+       struct nfnl_exp *exp;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       exp = nl_cli_exp_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_MARK = 270,
+                       ARG_TCP_STATE = 271,
+                       ARG_EXPECT_PROTO,
+                       ARG_EXPECT_SRC,
+                       ARG_EXPECT_SPORT,
+                       ARG_EXPECT_DST,
+                       ARG_EXPECT_DPORT,
+                       ARG_MASTER_PROTO,
+                       ARG_MASTER_SRC,
+                       ARG_MASTER_SPORT,
+                       ARG_MASTER_DST,
+                       ARG_MASTER_DPORT,
+                       ARG_TIMEOUT,
+                       ARG_HELPER_NAME,
+                       ARG_FLAGS,
+               };
+               static struct option long_opts[] = {
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "id", 1, 0, 'i' },
+                       { "expect-proto", 1, 0, ARG_EXPECT_PROTO },
+                       { "expect-src", 1, 0, ARG_EXPECT_SRC },
+                       { "expect-sport", 1, 0, ARG_EXPECT_SPORT },
+                       { "expect-dst", 1, 0, ARG_EXPECT_DST },
+                       { "expect-dport", 1, 0, ARG_EXPECT_DPORT },
+                       { "master-proto", 1, 0, ARG_MASTER_PROTO },
+                       { "master-src", 1, 0, ARG_MASTER_SRC },
+                       { "master-sport", 1, 0, ARG_MASTER_SPORT },
+                       { "master-dst", 1, 0, ARG_MASTER_DST },
+                       { "master-dport", 1, 0, ARG_MASTER_DPORT },
+                       { "family", 1, 0, 'F' },
+                       { "timeout", 1, 0, ARG_TIMEOUT },
+                       { "helper", 1, 0, ARG_HELPER_NAME },
+                       { "flags", 1, 0, ARG_FLAGS},
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': exit(NLE_INVAL);
+               case '4': nfnl_exp_set_family(exp, AF_INET); break;
+               case '6': nfnl_exp_set_family(exp, AF_INET6); break;
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'i': nl_cli_exp_parse_id(exp, optarg); break;
+               case ARG_EXPECT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_EXPECT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_EXPECT, optarg); break;
+               case ARG_MASTER_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case ARG_MASTER_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASTER, optarg); break;
+               case 'F': nl_cli_exp_parse_family(exp, optarg); break;
+               case ARG_TIMEOUT: nl_cli_exp_parse_timeout(exp, optarg); break;
+               case ARG_HELPER_NAME: nl_cli_exp_parse_helper_name(exp, optarg); break;
+               case ARG_FLAGS: nl_cli_exp_parse_flags(exp, optarg); break;
+               }
+       }
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_NETFILTER);
+       exp_cache = nl_cli_exp_alloc_cache(sock);
+
+       nl_cache_dump_filter(exp_cache, &params, OBJ_CAST(exp));
+
+       return 0;
+}
diff --git a/src/nf-log.c b/src/nf-log.c
new file mode 100644 (file)
index 0000000..913ba16
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * src/nf-log.c     Monitor netfilter log events
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <linux/netfilter/nfnetlink_log.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/log.h>
+
+static struct nfnl_log *alloc_log(void)
+{
+       struct nfnl_log *log;
+
+       log = nfnl_log_alloc();
+       if (!log)
+               nl_cli_fatal(ENOMEM, "Unable to allocate log object");
+
+       return log;
+}
+
+static void obj_input(struct nl_object *obj, void *arg)
+{
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_STATS,
+               .dp_fd = stdout,
+               .dp_dump_msgtype = 1,
+       };
+
+       nl_object_dump(obj, &dp);
+}
+
+static int event_input(struct nl_msg *msg, void *arg)
+{
+       if (nl_msg_parse(msg, &obj_input, NULL) < 0)
+               fprintf(stderr, "<<EVENT>> Unknown message type\n");
+
+       /* Exit nl_recvmsgs_def() and return to the main select() */
+       return NL_STOP;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *nf_sock;
+       struct nl_sock *rt_sock;
+        struct nl_cache *link_cache;
+       struct nfnl_log *log;
+       enum nfnl_log_copy_mode copy_mode;
+       uint32_t copy_range;
+       int err;
+       int family;
+
+       nf_sock = nl_cli_alloc_socket();
+       nl_socket_disable_seq_check(nf_sock);
+       nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+
+       if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
+               printf("Usage: nf-log family group [ copy_mode ] "
+                      "[copy_range] \n");
+               return 2;
+       }
+
+       nl_cli_connect(nf_sock, NETLINK_NETFILTER);
+
+       family = nl_str2af(argv[1]);
+       if (family == AF_UNSPEC)
+               nl_cli_fatal(NLE_INVAL, "Unknown family \"%s\": %s",
+                            argv[1], nl_geterror(family));
+
+       nfnl_log_pf_unbind(nf_sock, family);
+       if ((err = nfnl_log_pf_bind(nf_sock, family)) < 0)
+               nl_cli_fatal(err, "Unable to bind logger: %s",
+                            nl_geterror(err));
+
+       log = alloc_log();
+       nfnl_log_set_group(log, atoi(argv[2]));
+
+       copy_mode = NFNL_LOG_COPY_META;
+       if (argc > 3) {
+               copy_mode = nfnl_log_str2copy_mode(argv[3]);
+               if (copy_mode < 0)
+                       nl_cli_fatal(copy_mode,
+                                    "Unable to parse copy mode \"%s\": %s",
+                                    argv[3], nl_geterror(copy_mode));
+       }
+       nfnl_log_set_copy_mode(log, copy_mode);
+
+       copy_range = 0xFFFF;
+       if (argc > 4)
+               copy_range = atoi(argv[4]);
+       nfnl_log_set_copy_range(log, copy_range);
+
+       if ((err = nfnl_log_create(nf_sock, log)) < 0)
+               nl_cli_fatal(err, "Unable to bind instance: %s",
+                            nl_geterror(err));
+
+       {
+               struct nl_dump_params dp = {
+                       .dp_type = NL_DUMP_STATS,
+                       .dp_fd = stdout,
+                       .dp_dump_msgtype = 1,
+               };
+
+               printf("log params: ");
+               nl_object_dump((struct nl_object *) log, &dp);
+       }
+
+       rt_sock = nl_cli_alloc_socket();
+       nl_cli_connect(rt_sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(rt_sock);
+
+       while (1) {
+               fd_set rfds;
+               int nffd, rtfd, maxfd, retval;
+
+               FD_ZERO(&rfds);
+
+               maxfd = nffd = nl_socket_get_fd(nf_sock);
+               FD_SET(nffd, &rfds);
+
+               rtfd = nl_socket_get_fd(rt_sock);
+               FD_SET(rtfd, &rfds);
+               if (maxfd < rtfd)
+                       maxfd = rtfd;
+
+               /* wait for an incoming message on the netlink nf_socket */
+               retval = select(maxfd+1, &rfds, NULL, NULL, NULL);
+
+               if (retval) {
+                       if (FD_ISSET(nffd, &rfds))
+                               nl_recvmsgs_default(nf_sock);
+                       if (FD_ISSET(rtfd, &rfds))
+                               nl_recvmsgs_default(rt_sock);
+               }
+       }
+
+       return 0;
+}
diff --git a/src/nf-monitor.c b/src/nf-monitor.c
new file mode 100644 (file)
index 0000000..fe99af4
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * src/nf-monitor.c     Monitor netfilter events
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
+ * Copyright (c) 2007 Secure Computing Corporation
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/netfilter/nfnl.h>
+
+static void obj_input(struct nl_object *obj, void *arg)
+{
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_STATS,
+               .dp_fd = stdout,
+               .dp_dump_msgtype = 1,
+       };
+
+       nl_object_dump(obj, &dp);
+}
+
+static int event_input(struct nl_msg *msg, void *arg)
+{
+       if (nl_msg_parse(msg, &obj_input, NULL) < 0)
+               fprintf(stderr, "<<EVENT>> Unknown message type\n");
+
+       /* Exit nl_recvmsgs_def() and return to the main select() */
+       return NL_STOP;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       int err;
+       int i, idx;
+
+       static const struct {
+               enum nfnetlink_groups gr_id;
+               const char* gr_name;
+       } groups[] = {
+               { NFNLGRP_CONNTRACK_NEW, "ct-new" },
+               { NFNLGRP_CONNTRACK_UPDATE, "ct-update" },
+               { NFNLGRP_CONNTRACK_DESTROY, "ct-destroy" },
+               { NFNLGRP_NONE, NULL }
+       };
+
+       sock = nl_cli_alloc_socket();
+       nl_socket_disable_seq_check(sock);
+       nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+
+       if (argc > 1 && !strcasecmp(argv[1], "-h")) {
+               printf("Usage: nf-monitor [<groups>]\n");
+
+               printf("Known groups:");
+               for (i = 0; groups[i].gr_id != NFNLGRP_NONE; i++)
+                       printf(" %s", groups[i].gr_name);
+               printf("\n");
+               return 2;
+       }
+
+       nl_cli_connect(sock, NETLINK_NETFILTER);
+
+       for (idx = 1; argc > idx; idx++) {
+               for (i = 0; groups[i].gr_id != NFNLGRP_NONE; i++) {
+                       if (strcmp(argv[idx], groups[i].gr_name))
+                               continue;
+
+                       err = nl_socket_add_membership(sock, groups[i].gr_id);
+                       if (err < 0)
+                               nl_cli_fatal(err,
+                                            "Unable to add membership: %s",
+                                            nl_geterror(err));
+                       break;
+               }
+
+               if (groups[i].gr_id == NFNLGRP_NONE)
+                       nl_cli_fatal(NLE_OBJ_NOTFOUND, "Unknown group: \"%s\"",
+                                    argv[idx]);
+       }
+
+       while (1) {
+               fd_set rfds;
+               int fd, retval;
+
+               fd = nl_socket_get_fd(sock);
+
+               FD_ZERO(&rfds);
+               FD_SET(fd, &rfds);
+               /* wait for an incoming message on the netlink socket */
+               retval = select(fd+1, &rfds, NULL, NULL, NULL);
+
+               if (retval) {
+                       /* FD_ISSET(fd, &rfds) will be true */
+                       nl_recvmsgs_default(sock);
+               }
+       }
+
+       return 0;
+}
diff --git a/src/nf-queue.c b/src/nf-queue.c
new file mode 100644 (file)
index 0000000..922d9c8
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * src/nf-queue.c     Monitor netfilter queue events
+ *
+ *     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) 2007, 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2010  Karl Hiramoto <karl@hiramoto.org>
+ */
+
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <netinet/in.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <netlink/netfilter/nfnl.h>
+#include <netlink/netfilter/queue.h>
+#include <netlink/netfilter/queue_msg.h>
+
+static struct nl_sock *nf_sock;
+
+static struct nfnl_queue *alloc_queue(void)
+{
+       struct nfnl_queue *queue;
+
+       queue = nfnl_queue_alloc();
+       if (!queue)
+               nl_cli_fatal(ENOMEM, "Unable to allocate queue object");
+
+       return queue;
+}
+
+
+static void obj_input(struct nl_object *obj, void *arg)
+{
+       struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) obj;
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_STATS,
+               .dp_fd = stdout,
+               .dp_dump_msgtype = 1,
+       };
+
+       nfnl_queue_msg_set_verdict(msg, NF_ACCEPT);
+       nl_object_dump(obj, &dp);
+       nfnl_queue_msg_send_verdict(nf_sock, msg);
+}
+
+static int event_input(struct nl_msg *msg, void *arg)
+{
+       if (nl_msg_parse(msg, &obj_input, NULL) < 0)
+               fprintf(stderr, "<<EVENT>> Unknown message type\n");
+
+       /* Exit nl_recvmsgs_def() and return to the main select() */
+       return NL_STOP;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *rt_sock;
+       struct nl_cache *link_cache;
+       struct nfnl_queue *queue;
+       enum nfnl_queue_copy_mode copy_mode;
+       uint32_t copy_range;
+       int err = 1;
+       int family;
+
+       nf_sock = nfnl_queue_socket_alloc();
+       if (nf_sock == NULL)
+               nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket");
+
+       nl_socket_disable_seq_check(nf_sock);
+       nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+
+       if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
+               printf("Usage: nf-queue family group [ copy_mode ] "
+                      "[ copy_range ]\n");
+               printf("family: [ inet | inet6 | ... ] \n");
+               printf("group: the --queue-num arg that you gave to iptables\n");
+               printf("copy_mode: [ none | meta | packet ] \n");
+               return 2;
+       }
+
+       nl_cli_connect(nf_sock, NETLINK_NETFILTER);
+
+       if ((family = nl_str2af(argv[1])) == AF_UNSPEC)
+               nl_cli_fatal(NLE_INVAL, "Unknown family \"%s\"", argv[1]);
+
+       nfnl_queue_pf_unbind(nf_sock, family);
+       if ((err = nfnl_queue_pf_bind(nf_sock, family)) < 0)
+               nl_cli_fatal(err, "Unable to bind logger: %s",
+                            nl_geterror(err));
+
+       queue = alloc_queue();
+       nfnl_queue_set_group(queue, atoi(argv[2]));
+
+       copy_mode = NFNL_QUEUE_COPY_PACKET;
+       if (argc > 3) {
+               copy_mode = nfnl_queue_str2copy_mode(argv[3]);
+               if (copy_mode < 0)
+                       nl_cli_fatal(copy_mode,
+                                    "Unable to parse copy mode \"%s\": %s",
+                                    argv[3], nl_geterror(copy_mode));
+       }
+       nfnl_queue_set_copy_mode(queue, copy_mode);
+
+       copy_range = 0xFFFF;
+       if (argc > 4)
+               copy_range = atoi(argv[4]);
+       nfnl_queue_set_copy_range(queue, copy_range);
+
+       if ((err = nfnl_queue_create(nf_sock, queue)) < 0)
+               nl_cli_fatal(err, "Unable to bind queue: %s", nl_geterror(err));
+
+       rt_sock = nl_cli_alloc_socket();
+       nl_cli_connect(rt_sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(rt_sock);
+
+       nl_socket_set_buffer_size(nf_sock, 1024*127, 1024*127);
+
+       while (1) {
+               fd_set rfds;
+               int nffd, rtfd, maxfd, retval;
+
+               FD_ZERO(&rfds);
+
+               maxfd = nffd = nl_socket_get_fd(nf_sock);
+               FD_SET(nffd, &rfds);
+
+               rtfd = nl_socket_get_fd(rt_sock);
+               FD_SET(rtfd, &rfds);
+               if (maxfd < rtfd)
+                       maxfd = rtfd;
+
+               /* wait for an incoming message on the netlink socket */
+               retval = select(maxfd+1, &rfds, NULL, NULL, NULL);
+
+               if (retval) {
+                       if (FD_ISSET(nffd, &rfds))
+                               nl_recvmsgs_default(nf_sock);
+                       if (FD_ISSET(rtfd, &rfds))
+                               nl_recvmsgs_default(rt_sock);
+               }
+       }
+
+       return 0;
+}
diff --git a/src/nl-addr-add.c b/src/nl-addr-add.c
new file mode 100644 (file)
index 0000000..52995ec
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * src/nl-addr-add.c     Add addresses
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation version 2 of the License.
+ *
+ * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/addr.h>
+#include <netlink/cli/link.h>
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-addr-add [OPTION]... [ADDRESS]\n"
+"\n"
+"Options\n"
+"     --replace             Replace the address if it exists.\n"
+" -q, --quiet               Do not print informal notifications.\n"
+" -h, --help                Show this help.\n"
+" -v, --version             Show versioning information.\n"
+"\n"
+"Address Options\n"
+" -a, --local=ADDR          Address to be considered local.\n"
+" -d, --dev=DEV             Device the address should be assigned to.\n"
+"     --family=FAMILY       Address family (normally autodetected).\n"
+"     --broadcast=ADDR      Broadcast address of network (IPv4).\n"
+"     --peer=ADDR           Peer address (IPv4).\n"
+"     --label=STRING        Additional address label (IPv4).\n"
+"     --scope=SCOPE         Scope of local address (IPv4).\n"
+"     --preferred=TIME      Preferred lifetime (IPv6).\n"
+"     --valid=TIME          Valid lifetime (IPv6).\n"
+       );
+
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_addr *addr;
+       struct nl_cache *link_cache;
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err, nlflags = NLM_F_CREATE;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       addr = nl_cli_addr_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_LABEL = 258,
+                       ARG_PEER,
+                       ARG_SCOPE,
+                       ARG_BROADCAST,
+                       ARG_REPLACE,
+                       ARG_PREFERRED,
+                       ARG_VALID,
+               };
+               static struct option long_opts[] = {
+                       { "replace", 0, 0, ARG_REPLACE },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "local", 1, 0, 'a' },
+                       { "dev", 1, 0, 'd' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "label", 1, 0, ARG_LABEL },
+                       { "peer", 1, 0, ARG_PEER },
+                       { "scope", 1, 0, ARG_SCOPE },
+                       { "broadcast", 1, 0, ARG_BROADCAST },
+                       { "preferred", 1, 0, ARG_PREFERRED },
+                       { "valid", 1, 0, ARG_VALID },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "qhva:d:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': exit(NLE_INVAL);
+               case ARG_REPLACE: nlflags |= NLM_F_REPLACE; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'a': nl_cli_addr_parse_local(addr, optarg); break;
+               case 'd': nl_cli_addr_parse_dev(addr, link_cache, optarg); break;
+               case ARG_FAMILY: nl_cli_addr_parse_family(addr, optarg); break;
+               case ARG_LABEL: nl_cli_addr_parse_label(addr, optarg); break;
+               case ARG_PEER: nl_cli_addr_parse_peer(addr, optarg); break;
+               case ARG_SCOPE: nl_cli_addr_parse_scope(addr, optarg); break;
+               case ARG_BROADCAST: nl_cli_addr_parse_broadcast(addr, optarg); break;
+               case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break;
+               case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break;
+               }
+       }
+
+       if ((err = rtnl_addr_add(sock, addr, nlflags)) < 0)
+               nl_cli_fatal(err, "Unable to add address: %s",
+                            nl_geterror(err));
+
+       if (!quiet) {
+               printf("Added ");
+               nl_object_dump(OBJ_CAST(addr), &dp);
+       }
+
+       return 0;
+}
diff --git a/src/nl-addr-delete.c b/src/nl-addr-delete.c
new file mode 100644 (file)
index 0000000..2849c01
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * src/nl-addr-delete.c     Delete addresses
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation version 2 of the License.
+ *
+ * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/addr.h>
+#include <netlink/cli/link.h>
+
+static struct nl_sock *sock;
+static int interactive = 0, default_yes = 0, quiet = 0;
+static int deleted = 0;
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-addr-delete [OPTION]... [ADDRESS]\n"
+"\n"
+"Options\n"
+" -i, --interactive         Run interactively.\n"
+"     --yes                 Set default answer to yes.\n"
+" -q, --quiet               Do not print informal notifications.\n"
+" -h, --help                Show this help.\n"
+" -v, --version             Show versioning information.\n"
+"\n"
+"Address Options\n"
+" -a, --local=ADDR          Local address.\n"
+" -d, --dev=DEV             Associated network device.\n"
+"     --family=FAMILY       Family of local address.\n"
+"     --label=STRING        Address label (IPv4).\n"
+"     --peer=ADDR           Peer address (IPv4).\n"
+"     --scope=SCOPE         Address scope (IPv4).\n"
+"     --broadcast=ADDR      Broadcast address of network (IPv4).\n"
+"     --valid-lifetime=TS   Valid lifetime before route expires (IPv6).\n"
+"     --preferred=TIME      Preferred lifetime (IPv6).\n"
+"     --valid=TIME          Valid lifetime (IPv6).\n"
+       );
+
+       exit(0);
+}
+
+static void delete_cb(struct nl_object *obj, void *arg)
+{
+       struct rtnl_addr *addr = nl_object_priv(obj);
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err;
+
+       if (interactive && !nl_cli_confirm(obj, &params, default_yes))
+               return;
+
+       if ((err = rtnl_addr_delete(sock, addr, 0)) < 0)
+               nl_cli_fatal(err, "Unable to delete address: %s\n",
+                            nl_geterror(err));
+
+       if (!quiet) {
+               printf("Deleted ");
+               nl_object_dump(obj, &params);
+       }
+
+       deleted++;
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_addr *addr;
+       struct nl_cache *link_cache, *addr_cache;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       addr_cache = nl_cli_addr_alloc_cache(sock);
+       addr = nl_cli_addr_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_LABEL = 258,
+                       ARG_YES,
+                       ARG_PEER,
+                       ARG_SCOPE,
+                       ARG_BROADCAST,
+                       ARG_PREFERRED,
+                       ARG_VALID,
+               };
+               static struct option long_opts[] = {
+                       { "interactive", 0, 0, 'i' },
+                       { "yes", 0, 0, ARG_YES },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "local", 1, 0, 'a' },
+                       { "dev", 1, 0, 'd' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "label", 1, 0, ARG_LABEL },
+                       { "peer", 1, 0, ARG_PEER },
+                       { "scope", 1, 0, ARG_SCOPE },
+                       { "broadcast", 1, 0, ARG_BROADCAST },
+                       { "preferred", 1, 0, ARG_PREFERRED },
+                       { "valid", 1, 0, ARG_VALID },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "iqhva:d:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'i': interactive = 1; break;
+               case ARG_YES: default_yes = 1; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'a': nl_cli_addr_parse_local(addr, optarg); break;
+               case 'd': nl_cli_addr_parse_dev(addr, link_cache, optarg); break;
+               case ARG_FAMILY: nl_cli_addr_parse_family(addr, optarg); break;
+               case ARG_LABEL: nl_cli_addr_parse_label(addr, optarg); break;
+               case ARG_PEER: nl_cli_addr_parse_peer(addr, optarg); break;
+               case ARG_SCOPE: nl_cli_addr_parse_scope(addr, optarg); break;
+               case ARG_BROADCAST: nl_cli_addr_parse_broadcast(addr, optarg); break;
+               case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break;
+               case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break;
+               }
+       }
+
+       nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), delete_cb, NULL);
+
+       if (!quiet)
+               printf("Deleted %d addresses\n", deleted);
+
+       return 0;
+}
diff --git a/src/nl-addr-list.c b/src/nl-addr-list.c
new file mode 100644 (file)
index 0000000..20995a8
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * src/nl-addr-list.c     List addresses
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation version 2 of the License.
+ *
+ * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/addr.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-addr-list [OPTION]... [ADDRESS]\n"
+"\n"
+"Options\n"
+"     --details             Show details on multiple lines.\n"
+"     --env                 Print address details in sh env variable syntax.\n"
+"     --prefix=STRING       Prefix each printed line.\n"
+" -h, --help                Show this help.\n"
+" -v, --version             Show versioning information.\n"
+"\n"
+"Address Selection\n"
+" -a, --local=ADDR          Local address.\n"
+" -d, --dev=DEV             Associated network device.\n"
+"     --family=FAMILY       Family of local address.\n"
+"     --label=STRING        Address label (IPv4).\n"
+"     --peer=ADDR           Peer address (IPv4).\n"
+"     --scope=SCOPE         Address scope (IPv4).\n"
+"     --broadcast=ADDR      Broadcast address of network (IPv4).\n"
+"     --valid-lifetime=TS   Valid lifetime before route expires (IPv6).\n"
+"     --preferred=TIME      Preferred lifetime (IPv6).\n"
+"     --valid=TIME          Valid lifetime (IPv6).\n"
+       );
+       exit(0);
+}
+
+static char *prefix;
+
+static void print_prefix(struct nl_dump_params *p, int line)
+{
+       if (prefix)
+               nl_dump(p, "%s", prefix);
+}
+
+static void env_dump(struct nl_object *obj, void *arg)
+{
+       struct nl_dump_params *p = arg;
+       struct rtnl_addr *addr = (struct rtnl_addr *) obj;
+       struct nl_cache *link_cache;
+       struct nl_addr *a;
+       static int index = 0;
+       char buf[128], pfx[32], *s;
+
+       snprintf(pfx, sizeof(pfx), "ADDR%d", index++);
+
+       nl_dump_line(p, "%s_FAMILY=%s\n", pfx,
+                    nl_af2str(rtnl_addr_get_family(addr), buf, sizeof(buf)));
+
+       nl_dump_line(p, "%s_LOCAL=%s\n", pfx,
+                    nl_addr2str(rtnl_addr_get_local(addr), buf, sizeof(buf)));
+
+       nl_dump_line(p, "%s_IFINDEX=%u\n", pfx, rtnl_addr_get_ifindex(addr));
+       link_cache = nl_cache_mngt_require_safe("route/link");
+       if (link_cache)
+               nl_dump_line(p, "%s_IFNAME=%s\n", pfx,
+                            rtnl_link_i2name(link_cache,
+                                             rtnl_addr_get_ifindex(addr),
+                                             buf, sizeof(buf)));
+
+       if ((a = rtnl_addr_get_peer(addr)))
+               nl_dump_line(p, "%s_PEER=%s\n", pfx,
+                            nl_addr2str(a, buf, sizeof(buf)));
+
+       if ((a = rtnl_addr_get_broadcast(addr)))
+               nl_dump_line(p, "%s_BROADCAST=%s\n", pfx,
+                            nl_addr2str(a, buf, sizeof(buf)));
+
+       nl_dump_line(p, "%s_SCOPE=%s\n", pfx,
+                    rtnl_scope2str(rtnl_addr_get_scope(addr),
+                                   buf, sizeof(buf)));
+
+       if ((s = rtnl_addr_get_label(addr)))
+               nl_dump_line(p, "%s_LABEL=%s\n", pfx, s);
+
+       rtnl_addr_flags2str(rtnl_addr_get_flags(addr), buf, sizeof(buf));
+       if (buf[0])
+               nl_dump_line(p, "%s_FLAGS=%s\n", pfx, buf);
+
+       nl_dump_line(p, "%s_CACHEINFO_VALID=%u\n", pfx,
+                    rtnl_addr_get_valid_lifetime(addr));
+
+       if (link_cache)
+               nl_cache_put(link_cache);
+
+#if 0
+       if (addr->ce_mask & ADDR_ATTR_CACHEINFO) {
+               struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo;
+
+               nl_dump_line(p, "ADDR_CACHEINFO_PREFERRED=%u\n",
+                            ci->aci_prefered);
+
+               nl_dump_line(p, "ADDR_CACHEINFO_CREATED=%u\n", ci->aci_cstamp);
+               nl_dump_line(p, "ADDR_CACHEINFO_LASTUPDATE=%u\n",
+                            ci->aci_tstamp);
+       }
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_addr *addr;
+       struct nl_cache *link_cache, *addr_cache;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_nl_cb = print_prefix,
+               .dp_fd = stdout,
+       };
+       int dump_env = 0;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       addr_cache = nl_cli_addr_alloc_cache(sock);
+       addr = nl_cli_addr_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_LABEL = 258,
+                       ARG_PEER,
+                       ARG_SCOPE,
+                       ARG_BROADCAST,
+                       ARG_DETAILS,
+                       ARG_ENV,
+                       ARG_PREFIX,
+                       ARG_PREFERRED,
+                       ARG_VALID,
+               };
+               static struct option long_opts[] = {
+                       { "details", 0, 0, ARG_DETAILS },
+                       { "env", 0, 0, ARG_ENV },
+                       { "prefix", 1, 0, ARG_PREFIX },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "local", 1, 0, 'a' },
+                       { "dev", 1, 0, 'd' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "label", 1, 0, ARG_LABEL },
+                       { "peer", 1, 0, ARG_PEER },
+                       { "scope", 1, 0, ARG_SCOPE },
+                       { "broadcast", 1, 0, ARG_BROADCAST },
+                       { "preferred", 1, 0, ARG_PREFERRED },
+                       { "valid", 1, 0, ARG_VALID },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "46hva:d:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': exit(NLE_INVAL);
+               case '4': rtnl_addr_set_family(addr, AF_INET); break;
+               case '6': rtnl_addr_set_family(addr, AF_INET6); break;
+               case ARG_DETAILS: params.dp_type = NL_DUMP_DETAILS; break;
+               case ARG_ENV: dump_env = 1; break;
+               case ARG_PREFIX: prefix = strdup(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'a': nl_cli_addr_parse_local(addr, optarg); break;
+               case 'd': nl_cli_addr_parse_dev(addr, link_cache, optarg); break;
+               case ARG_FAMILY: nl_cli_addr_parse_family(addr, optarg); break;
+               case ARG_LABEL: nl_cli_addr_parse_label(addr, optarg); break;
+               case ARG_PEER: nl_cli_addr_parse_peer(addr, optarg); break;
+               case ARG_SCOPE: nl_cli_addr_parse_scope(addr, optarg); break;
+               case ARG_BROADCAST: nl_cli_addr_parse_broadcast(addr, optarg); break;
+               case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break;
+               case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break;
+               }
+       }
+
+       if (dump_env)
+               nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), env_dump,
+                                       &params);
+       else
+               nl_cache_dump_filter(addr_cache, &params, OBJ_CAST(addr));
+
+       return 0;
+}
diff --git a/src/nl-class-add.c b/src/nl-class-add.c
new file mode 100644 (file)
index 0000000..b9a17dc
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * src/nl-class-add.c     Add/Update/Replace Traffic Class
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/qdisc.h>
+#include <netlink/cli/class.h>
+#include <netlink/cli/link.h>
+
+#include <netlink-private/route/tc-api.h>
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-class-add [OPTIONS]... class [CONFIGURATION]...\n"
+"\n"
+"OPTIONS\n"
+" -q, --quiet               Do not print informal notifications.\n"
+" -h, --help                Show this help text.\n"
+" -v, --version             Show versioning information.\n"
+"     --update              Update class if it exists.\n"
+"     --update-only         Only update class, never create it.\n"
+" -d, --dev=DEV             Network device the class should be attached to.\n"
+" -i, --id=ID               ID of new class (default: auto-generated)\n"
+" -p, --parent=ID           ID of parent { root | ingress | class-ID }\n"
+"     --mtu=SIZE            Overwrite MTU (default: MTU of network device)\n"
+"     --mpu=SIZE            Minimum packet size on the link (default: 0).\n"
+"     --overhead=SIZE       Overhead in bytes per packet (default: 0).\n"
+"     --linktype=TYPE       Overwrite linktype (default: type of network device)\n"
+"\n"
+"CONFIGURATION\n"
+" -h, --help                Show help text of class specific options.\n"
+"\n"
+"EXAMPLE\n"
+"   $ nl-class-add --dev=eth1 --parent=root htb --rate=100mbit\n"
+"\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_class *class;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache;
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_DETAILS,
+               .dp_fd = stdout,
+       };
+       struct nl_cli_tc_module *tm;
+       struct rtnl_tc_ops *ops;
+       int err, flags = NLM_F_CREATE | NLM_F_EXCL;
+       char *kind, *id = NULL;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       class = nl_cli_class_alloc();
+       tc = (struct rtnl_tc *) class;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_UPDATE = 257,
+                       ARG_UPDATE_ONLY = 258,
+                       ARG_MTU,
+                       ARG_MPU,
+                       ARG_OVERHEAD,
+                       ARG_LINKTYPE,
+               };
+               static struct option long_opts[] = {
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "update", 0, 0, ARG_UPDATE },
+                       { "update-only", 0, 0, ARG_UPDATE_ONLY },
+                       { "mtu", 1, 0, ARG_MTU },
+                       { "mpu", 1, 0, ARG_MPU },
+                       { "overhead", 1, 0, ARG_OVERHEAD },
+                       { "linktype", 1, 0, ARG_LINKTYPE },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "+qhvd:p:i:",
+                               long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': id = strdup(optarg); break;
+               case ARG_UPDATE: flags = NLM_F_CREATE; break;
+               case ARG_UPDATE_ONLY: flags = 0; break;
+               case ARG_MTU: nl_cli_tc_parse_mtu(tc, optarg); break;
+               case ARG_MPU: nl_cli_tc_parse_mpu(tc, optarg); break;
+               case ARG_OVERHEAD: nl_cli_tc_parse_overhead(tc, optarg); break;
+               case ARG_LINKTYPE: nl_cli_tc_parse_linktype(tc, optarg); break;
+               }
+       }
+
+       if (optind >= argc)
+               print_usage();
+
+       if (!rtnl_tc_get_ifindex(tc))
+               nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");
+
+       if (!rtnl_tc_get_parent(tc))
+               nl_cli_fatal(EINVAL, "You must specify a parent (--parent=XXX)");
+
+       if (id) {
+               nl_cli_tc_parse_handle(tc, id, 1);
+               free(id);
+       }
+
+       kind = argv[optind++];
+       rtnl_tc_set_kind(tc, kind);
+
+       if (!(ops = rtnl_tc_get_ops(tc)))
+               nl_cli_fatal(ENOENT, "Unknown class \"%s\"", kind);
+
+       if (!(tm = nl_cli_tc_lookup(ops)))
+               nl_cli_fatal(ENOTSUP, "class type \"%s\" not supported.", kind);
+
+       tm->tm_parse_argv(tc, argc, argv);
+
+       if (!quiet) {
+               printf("Adding ");
+               nl_object_dump(OBJ_CAST(class), &dp);
+       }
+
+       if ((err = rtnl_class_add(sock, class, flags)) < 0)
+               nl_cli_fatal(EINVAL, "Unable to add class: %s", nl_geterror(err));
+
+       return 0;
+}
diff --git a/src/nl-class-delete.c b/src/nl-class-delete.c
new file mode 100644 (file)
index 0000000..37657a4
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * src/nl-class-delete.c     Delete Traffic Classes
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/class.h>
+#include <netlink/cli/link.h>
+
+static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
+static struct nl_sock *sock;
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-class-delete [OPTION]... [class]\n"
+       "\n"
+       "OPTIONS\n"
+       "     --interactive     Run interactively.\n"
+       "     --yes             Set default answer to yes.\n"
+       " -q, --quiet           Do not print informal notifications.\n"
+       " -h, --help            Show this help text and exit.\n"
+       " -v, --version         Show versioning information and exit.\n"
+       "\n"
+       " -d, --dev=DEV         Device the class is attached to.\n"
+       " -p, --parent=ID       Identifier of parent qdisc/class.\n"
+       " -i, --id=ID           Identifier\n"
+       " -k, --kind=NAME       Kind of class (e.g. pfifo_fast)\n"
+       "\n"
+       "EXAMPLE\n"
+       "    # Delete all classes on eth0 attached to parent 1:\n"
+       "    $ nl-class-delete --dev eth0 --parent 1:\n"
+       "\n"
+       );
+
+       exit(0);
+}
+
+static void delete_cb(struct nl_object *obj, void *arg)
+{
+       struct rtnl_class *class = nl_object_priv(obj);
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err;
+
+       if (interactive && !nl_cli_confirm(obj, &params, default_yes))
+               return;
+
+       if ((err = rtnl_class_delete(sock, class)) < 0)
+               nl_cli_fatal(err, "Unable to delete class: %s\n", nl_geterror(err));
+
+       if (!quiet) {
+               printf("Deleted ");
+               nl_object_dump(obj, &params);
+       }
+
+       deleted++;
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_class *class;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache, *class_cache;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       class = nl_cli_class_alloc();
+       tc = (struct rtnl_tc *) class;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_YES = 257,
+                       ARG_INTERACTIVE = 258,
+               };
+               static struct option long_opts[] = {
+                       { "interactive", 0, 0, ARG_INTERACTIVE },
+                       { "yes", 0, 0, ARG_YES },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "qhvd:p:i:k:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': nl_cli_fatal(EINVAL, "Invalid options");
+               case ARG_INTERACTIVE: interactive = 1; break;
+               case ARG_YES: default_yes = 1; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
+               case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
+               }
+       }
+
+       if (!rtnl_tc_get_ifindex(tc))
+               nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");
+
+       class_cache = nl_cli_class_alloc_cache(sock, rtnl_tc_get_ifindex(tc));
+
+       nl_cache_foreach_filter(class_cache, OBJ_CAST(class), delete_cb, NULL);
+
+       if (!quiet)
+               printf("Deleted %d classs\n", deleted);
+
+       return 0;
+}
diff --git a/src/nl-class-list.c b/src/nl-class-list.c
new file mode 100644 (file)
index 0000000..c2423fb
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * src/nl-class-list.c     List Traffic Classes
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/class.h>
+#include <netlink/cli/link.h>
+
+static struct nl_sock *sock;
+
+static struct nl_dump_params params = {
+       .dp_type = NL_DUMP_LINE,
+};
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-class-list [OPTION]...\n"
+       "\n"
+       "OPTIONS\n"
+       "     --details         Show details\n"
+       "     --stats           Show statistics\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       " -d, --dev=DEV         Device the class is attached to. (default: all)\n"
+       " -p, --parent=ID       Identifier of parent class.\n"
+       " -i, --id=ID           Identifier.\n"
+       " -k, --kind=NAME       Kind of class (e.g. pfifo_fast)\n"
+       "\n"
+       "EXAMPLE\n"
+       "    # Display statistics of all classes on eth0\n"
+       "    $ nl-class-list --stats --dev=eth0\n"
+       "\n"
+       );
+       exit(0);
+}
+
+static void __dump_class(int ifindex, struct rtnl_class *filter)
+{
+       struct nl_cache *cache;
+
+       cache = nl_cli_class_alloc_cache(sock, ifindex);
+       nl_cache_dump_filter(cache, &params, OBJ_CAST(filter));
+}
+
+static void dump_class(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = nl_object_priv(obj);
+
+       __dump_class(rtnl_link_get_ifindex(link), arg);
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_class *class;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache;
+       int ifindex;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       class = nl_cli_class_alloc();
+       tc = (struct rtnl_tc *) class;
+
+       params.dp_fd = stdout;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_DETAILS = 257,
+                       ARG_STATS = 258,
+               };
+               static struct option long_opts[] = {
+                       { "details", 0, 0, ARG_DETAILS },
+                       { "stats", 0, 0, ARG_STATS },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "hvd:p:i:k:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case ARG_DETAILS: params.dp_type = NL_DUMP_DETAILS; break;
+               case ARG_STATS: params.dp_type = NL_DUMP_STATS; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
+               case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
+               }
+       }
+
+       if ((ifindex = rtnl_tc_get_ifindex(tc)))
+               __dump_class(ifindex, class);
+        else
+               nl_cache_foreach(link_cache, dump_class, class);
+
+       return 0;
+}
diff --git a/src/nl-classid-lookup.c b/src/nl-classid-lookup.c
new file mode 100644 (file)
index 0000000..1d45d0b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * src/nl-classid-lookup.c     Lookup classid
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-classid-lookup [OPTIONS]... NAME\n"
+"\n"
+"OPTIONS\n"
+" -h, --help                Show this help text.\n"
+" -v, --version             Show versioning information.\n"
+" -r, --reverse             Do a reverse lookup, i.e. classid to name.\n"
+"     --raw                 Print the raw classid, not pretty printed.\n"
+"\n"
+"EXAMPLE\n"
+"   $ nl-classid-lookup low_latency\n"
+"   $ nl-classid-lookup -r 1:12\n"
+"\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       uint32_t classid;
+       char *name;
+       int err, reverse = 0, raw = 0;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_RAW = 257,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "reverse", 0, 0, 'r' },
+                       { "raw", 0, 0, ARG_RAW },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "hvr", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'r': reverse = 1; break;
+               case ARG_RAW: raw = 1; break;
+               }
+       }
+
+       if (optind >= argc)
+               print_usage();
+
+       name = argv[optind++];
+
+       /*
+        * We use rtnl_tc_str2handle() even while doing a reverse lookup. This
+        * allows for name -> name lookups. This is intentional, it does not
+        * do any harm and avoids duplicating a lot of code.
+        */
+       if ((err = rtnl_tc_str2handle(name, &classid)) < 0)
+               nl_cli_fatal(err, "Unable to lookup classid \"%s\": %s",
+                            name, nl_geterror(err));
+
+       if (reverse) {
+               char buf[64];
+               printf("%s\n", rtnl_tc_handle2str(classid, buf, sizeof(buf)));
+       } else if (raw)
+               printf("%#x\n", classid);
+       else
+               printf("%x:%x\n", TC_H_MAJ(classid) >> 16, TC_H_MIN(classid));
+
+       return 0;
+}
diff --git a/src/nl-cls-add.c b/src/nl-cls-add.c
new file mode 100644 (file)
index 0000000..6acb320
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * src/nl-cls-add.c     Add classifier
+ *
+ *     This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation version 2 of the License.
+ *
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/cli/link.h>
+
+#include <netlink-private/route/tc-api.h>
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-cls-add [OPTIONS]... classifier [CONFIGURATION]...\n"
+"\n"
+"OPTIONS\n"
+" -q, --quiet               Do not print informal notifications.\n"
+" -h, --help                Show this help text.\n"
+" -v, --version             Show versioning information.\n"
+"     --update              Update classifier if it exists.\n"
+"     --update-only         Only update classifier, never create it.\n"
+" -d, --dev=DEV             Network device the classifier should be attached to.\n"
+" -i, --id=ID               ID of new classifier (default: auto-generated)\n"
+" -p, --parent=ID           ID of parent { root | ingress | class-ID }\n"
+"     --protocol=PROTO      Protocol to match (default: all)\n"
+"     --prio=PRIO           Priority (default: 0)\n"
+"     --mtu=SIZE            Overwrite MTU (default: MTU of network device)\n"
+"     --mpu=SIZE            Minimum packet size on the link (default: 0).\n"
+"     --overhead=SIZE       Overhead in bytes per packet (default: 0).\n"
+"     --linktype=TYPE       Overwrite linktype (default: type of network device)\n"
+"\n"
+"CONFIGURATION\n"
+" -h, --help                Show help text of classifier specific options.\n"
+"\n"
+"EXAMPLE\n"
+"   $ nl-cls-add --dev=eth1 --parent=q_root basic --target c_www\n"
+"\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_cls *cls;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache;
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_DETAILS,
+               .dp_fd = stdout,
+       };
+       struct nl_cli_tc_module *tm;
+       struct rtnl_tc_ops *ops;
+       int err, flags = NLM_F_CREATE | NLM_F_EXCL;
+       char *kind, *id = NULL;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       cls = nl_cli_cls_alloc();
+       tc = (struct rtnl_tc *) cls;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_UPDATE = 257,
+                       ARG_UPDATE_ONLY = 258,
+                       ARG_MTU,
+                       ARG_MPU,
+                       ARG_OVERHEAD,
+                       ARG_LINKTYPE,
+                       ARG_PROTO,
+                       ARG_PRIO,
+               };
+               static struct option long_opts[] = {
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "proto", 1, 0, ARG_PROTO },
+                       { "prio", 1, 0, ARG_PRIO },
+                       { "update", 0, 0, ARG_UPDATE },
+                       { "update-only", 0, 0, ARG_UPDATE_ONLY },
+                       { "mtu", 1, 0, ARG_MTU },
+                       { "mpu", 1, 0, ARG_MPU },
+                       { "overhead", 1, 0, ARG_OVERHEAD },
+                       { "linktype", 1, 0, ARG_LINKTYPE },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "+qhvd:p:i:",
+                               long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': id = strdup(optarg); break;
+               case ARG_UPDATE: flags = NLM_F_CREATE; break;
+               case ARG_UPDATE_ONLY: flags = 0; break;
+               case ARG_MTU: nl_cli_tc_parse_mtu(tc, optarg); break;
+               case ARG_MPU: nl_cli_tc_parse_mpu(tc, optarg); break;
+               case ARG_OVERHEAD: nl_cli_tc_parse_overhead(tc, optarg); break;
+               case ARG_LINKTYPE: nl_cli_tc_parse_linktype(tc, optarg); break;
+               case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
+               case ARG_PRIO:
+                       rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
+                       break;
+               }
+       }
+
+       if (optind >= argc)
+               print_usage();
+
+       if (!rtnl_tc_get_ifindex(tc))
+               nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");
+
+       if (!rtnl_tc_get_parent(tc))
+               nl_cli_fatal(EINVAL, "You must specify a parent (--parent=XXX)");
+
+       if (id) {
+               nl_cli_tc_parse_handle(tc, id, 1);
+               free(id);
+       }
+
+       kind = argv[optind++];
+       rtnl_tc_set_kind(tc, kind);
+
+       if (!(ops = rtnl_tc_get_ops(tc)))
+               nl_cli_fatal(ENOENT, "Unknown classifier \"%s\".", kind);
+
+       if (!(tm = nl_cli_tc_lookup(ops)))
+               nl_cli_fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind);
+
+       tm->tm_parse_argv(tc, argc, argv);
+
+       if (!quiet) {
+               printf("Adding ");
+               nl_object_dump(OBJ_CAST(cls), &dp);
+       }
+
+       if ((err = rtnl_cls_add(sock, cls, flags)) < 0)
+               nl_cli_fatal(EINVAL, "Unable to add classifier: %s", nl_geterror(err));
+
+       return 0;
+}
diff --git a/src/nl-cls-delete.c b/src/nl-cls-delete.c
new file mode 100644 (file)
index 0000000..2b3db1f
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * src/nl-cls-delete.c     Delete Classifier
+ *
+ *     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-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/cls.h>
+#include <netlink/cli/link.h>
+
+static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
+static struct nl_sock *sock;
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-cls-delete [OPTION]... [class]\n"
+"\n"
+"OPTIONS\n"
+"     --interactive         Run interactively.\n"
+"     --yes                 Set default answer to yes.\n"
+" -q, --quiet               Do not print informal notifications.\n"
+" -h, --help                Show this help text and exit.\n"
+" -v, --version             Show versioning information and exit.\n"
+"\n"
+" -d, --dev=DEV             Device the classifer is attached to.\n"
+" -p, --parent=ID           Identifier of parent qdisc/class.\n"
+" -i, --id=ID               Identifier\n"
+" -k, --kind=NAME           Kind of classifier (e.g. basic, u32, fw)\n"
+"     --protocol=PROTO      Protocol to match (default: all)\n"
+"     --prio=PRIO           Priority (default: 0)\n"
+"\n"
+"EXAMPLE\n"
+"    # Delete all classifiers on eth0 attached to parent q_root:\n"
+"    $ nl-cls-delete --dev eth0 --parent q_root:\n"
+"\n"
+       );
+
+       exit(0);
+}
+
+static void delete_cb(struct nl_object *obj, void *arg)
+{
+       struct rtnl_cls *cls = nl_object_priv(obj);
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err;
+
+       if (interactive && !nl_cli_confirm(obj, &params, default_yes))
+               return;
+
+       if ((err = rtnl_cls_delete(sock, cls, 0)) < 0)
+               nl_cli_fatal(err, "Unable to delete classifier: %s\n",
+                               nl_geterror(err));
+
+       if (!quiet) {
+               printf("Deleted ");
+               nl_object_dump(obj, &params);
+       }
+
+       deleted++;
+}
+
+static void __delete_link(int ifindex, struct rtnl_cls *filter)
+{
+       struct nl_cache *cache;
+       uint32_t parent = rtnl_tc_get_parent((struct rtnl_tc *) filter);
+
+       cache = nl_cli_cls_alloc_cache(sock, ifindex, parent);
+       nl_cache_foreach_filter(cache, OBJ_CAST(filter), delete_cb, NULL);
+       nl_cache_free(cache);
+}
+
+static void delete_link(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = nl_object_priv(obj);
+
+       __delete_link(rtnl_link_get_ifindex(link), arg);
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_cls *cls;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache;
+       int ifindex;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       cls = nl_cli_cls_alloc();
+       tc = (struct rtnl_tc *) cls;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_YES = 257,
+                       ARG_INTERACTIVE = 258,
+                       ARG_PROTO,
+                       ARG_PRIO,
+               };
+               static struct option long_opts[] = {
+                       { "interactive", 0, 0, ARG_INTERACTIVE },
+                       { "yes", 0, 0, ARG_YES },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
+                       { "proto", 1, 0, ARG_PROTO },
+                       { "prio", 1, 0, ARG_PRIO },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "qhvd:p:i:k:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': nl_cli_fatal(EINVAL, "Invalid options");
+               case ARG_INTERACTIVE: interactive = 1; break;
+               case ARG_YES: default_yes = 1; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
+               case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
+               case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
+               case ARG_PRIO:
+                       rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
+                       break;
+               }
+       }
+
+       if ((ifindex = rtnl_tc_get_ifindex(tc)))
+               __delete_link(ifindex, cls);
+        else
+               nl_cache_foreach(link_cache, delete_link, cls);
+
+       if (!quiet)
+               printf("Deleted %d classs\n", deleted);
+
+       return 0;
+}
diff --git a/src/nl-cls-list.c b/src/nl-cls-list.c
new file mode 100644 (file)
index 0000000..5072585
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * src/nl-cls-list.c           List classifiers
+ *
+ *     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-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/cls.h>
+#include <netlink/cli/link.h>
+
+static struct nl_sock *sock;
+
+static struct nl_dump_params params = {
+       .dp_type = NL_DUMP_LINE,
+};
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-cls-list [OPTION]...\n"
+"\n"
+"OPTIONS\n"
+"     --details             Show details\n"
+"     --stats               Show statistics\n"
+" -h, --help                Show this help\n"
+" -v, --version             Show versioning information\n"
+"\n"
+" -d, --dev=DEV             Device the classifier is attached to. (default: all)\n"
+" -p, --parent=ID           Identifier of parent class.\n"
+" -i, --id=ID               Identifier.\n"
+" -k, --kind=NAME           Kind of classifier (e.g. basic, u32, fw)\n"
+"     --protocol=PROTO      Protocol to match (default: all)\n"
+"     --prio=PRIO           Priority (default: 0)\n"
+"\n"
+"EXAMPLE\n"
+"    # Display statistics of all classes on eth0\n"
+"    $ nl-cls-list --stats --dev=eth0\n"
+"\n"
+       );
+       exit(0);
+}
+
+static void __dump_link(int ifindex, struct rtnl_cls *filter)
+{
+       struct nl_cache *cache;
+       uint32_t parent = rtnl_tc_get_parent((struct rtnl_tc *) filter);
+
+       cache = nl_cli_cls_alloc_cache(sock, ifindex, parent);
+       nl_cache_dump_filter(cache, &params, OBJ_CAST(filter));
+       nl_cache_free(cache);
+}
+
+static void dump_link(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = nl_object_priv(obj);
+
+       __dump_link(rtnl_link_get_ifindex(link), arg);
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_cls *cls;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache;
+       int ifindex;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       cls = nl_cli_cls_alloc();
+       tc = (struct rtnl_tc *) cls;
+
+       params.dp_fd = stdout;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_DETAILS = 257,
+                       ARG_STATS = 258,
+                       ARG_PROTO,
+                       ARG_PRIO,
+               };
+               static struct option long_opts[] = {
+                       { "details", 0, 0, ARG_DETAILS },
+                       { "stats", 0, 0, ARG_STATS },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
+                       { "proto", 1, 0, ARG_PROTO },
+                       { "prio", 1, 0, ARG_PRIO },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "hvd:p:i:k:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case ARG_DETAILS: params.dp_type = NL_DUMP_DETAILS; break;
+               case ARG_STATS: params.dp_type = NL_DUMP_STATS; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
+               case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
+               case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break;
+               case ARG_PRIO:
+                       rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
+                       break;
+               }
+       }
+
+       if ((ifindex = rtnl_tc_get_ifindex(tc)))
+               __dump_link(ifindex, cls);
+        else
+               nl_cache_foreach(link_cache, dump_link, cls);
+
+       return 0;
+}
diff --git a/src/nl-fib-lookup.c b/src/nl-fib-lookup.c
new file mode 100644 (file)
index 0000000..705cf32
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * src/nl-fib-lookup.c         FIB Route Lookup
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-fib-lookup [options] <addr>\n"
+       "Options:\n"
+       "   -t, --table <table>         Table id\n"
+       "   -f, --fwmark <int>          Firewall mark\n"
+       "   -s, --scope <scope>         Routing scope\n"
+       "   -T, --tos <int>             Type of Service\n");
+       exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *nlh;
+       struct nl_cache *result;
+       struct flnl_request *request;
+       struct nl_addr *addr;
+       struct nl_dump_params params = {
+               .dp_fd = stdout,
+               .dp_type = NL_DUMP_DETAILS,
+       };
+       int table = RT_TABLE_UNSPEC, scope = RT_SCOPE_UNIVERSE;
+       int tos = 0, err = 1;
+       uint64_t fwmark = 0;
+
+       while (1) {
+               static struct option long_opts[] = {
+                       {"table", 1, 0, 't'},
+                       {"fwmark", 1, 0, 'f'},
+                       {"scope", 1, 0, 's'},
+                       {"tos", 1, 0, 'T'},
+                       {"help", 0, 0, 'h'},
+                       {0, 0, 0, 0},
+               };
+               int c, idx = 0;
+
+               c = getopt_long(argc, argv, "t:f:s:T:h", long_opts, &idx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 't':
+                       table = strtoul(optarg, NULL, 0);
+                       break;
+               case 'f':
+                       fwmark = strtoul(optarg, NULL, 0);
+                       break;
+               case 's':
+                       scope = strtoul(optarg, NULL, 0);
+                       break;
+               case 'T':
+                       tos = strtoul(optarg, NULL, 0);
+                       break;
+               default:
+                       print_usage();
+               }
+       }
+
+       if (optind >= argc)
+               print_usage();
+
+       nlh = nl_cli_alloc_socket();
+
+       if ((err = nl_addr_parse(argv[optind], AF_INET, &addr)) < 0)
+               nl_cli_fatal(err, "Unable to parse address \"%s\": %s\n",
+                       argv[optind], nl_geterror(err));
+
+       result = flnl_result_alloc_cache();
+       if (!result)
+               nl_cli_fatal(ENOMEM, "Unable to allocate cache");
+
+       request = flnl_request_alloc();
+       if (!request)
+               nl_cli_fatal(ENOMEM, "Unable to allocate request");
+
+       flnl_request_set_table(request, table);
+       flnl_request_set_fwmark(request, fwmark);
+       flnl_request_set_scope(request, scope);
+       flnl_request_set_tos(request, tos);
+
+       err = flnl_request_set_addr(request, addr);
+       nl_addr_put(addr);
+       if (err < 0)
+               nl_cli_fatal(err, "Unable to send request: %s", nl_geterror(err));
+
+       nl_cli_connect(nlh, NETLINK_FIB_LOOKUP);
+
+       err = flnl_lookup(nlh, request, result);
+       if (err < 0)
+               nl_cli_fatal(err, "Unable to lookup: %s\n", nl_geterror(err));
+
+       nl_cache_dump(result, &params);
+
+       return 0;
+}
diff --git a/src/nl-link-enslave.c b/src/nl-link-enslave.c
new file mode 100644 (file)
index 0000000..2b5d47d
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * src/nl-link-enslave.c     Enslave a link
+ *
+ *     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) 2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <netlink/route/link/bonding.h>
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache;
+       struct rtnl_link *master, *slave;
+       int err;
+
+       if (argc < 3) {
+               fprintf(stderr, "Usage: nl-link-enslave master slave\n");
+               return 1;
+       }
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       if (!(master = rtnl_link_get_by_name(link_cache, argv[1]))) {
+               fprintf(stderr, "Unknown link: %s\n", argv[1]);
+               return 1;
+       }
+
+       if (!(slave = rtnl_link_get_by_name(link_cache, argv[2]))) {
+               fprintf(stderr, "Unknown link: %s\n", argv[2]);
+               return 1;
+       }
+
+       if ((err = rtnl_link_bond_enslave(sock, master, slave)) < 0) {
+               fprintf(stderr, "Unable to enslave %s to %s: %s\n",
+                       argv[2], argv[1], nl_geterror(err));
+               return 1;
+       }
+
+       return 0;
+}
+
diff --git a/src/nl-link-ifindex2name.c b/src/nl-link-ifindex2name.c
new file mode 100644 (file)
index 0000000..68e5158
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * src/nl-link-ifindex2name.c     Transform a interface index to its name
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf("Usage: nl-link-ifindex2name <ifindex>\n");
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache;
+       char name[IFNAMSIZ];
+       uint32_t ifindex;
+
+       if (argc < 2)
+               print_usage();
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       ifindex = nl_cli_parse_u32(argv[1]);
+
+       if (!rtnl_link_i2name(link_cache, ifindex, name, sizeof(name)))
+               nl_cli_fatal(ENOENT, "Interface index %d does not exist",
+                            ifindex);
+
+       printf("%s\n", name);
+
+       return 0;
+}
diff --git a/src/nl-link-list.c b/src/nl-link-list.c
new file mode 100644 (file)
index 0000000..b5c98b4
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * src/nl-link-dump.c  Dump link attributes
+ *
+ *     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) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-link-list [OPTIONS]... \n"
+"\n"
+"OPTIONS\n"
+"     --details             Show detailed information of each link\n"
+"     --stats               Show statistics, implies --details\n"
+" -h, --help                Show this help text.\n"
+" -v, --version             Show versioning information.\n"
+"\n"
+" -n, --name=NAME          Name of link\n"
+" -i, --index               Interface index (unique identifier)\n"
+"     --family=NAME         Link address family\n"
+"     --mtu=NUM             MTU value\n"
+"     --txqlen=NUM          TX queue length\n"
+"     --weight=NUM          Weight\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache;
+       struct rtnl_link *link;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link = nl_cli_link_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_MTU = 258,
+                       ARG_TXQLEN,
+                       ARG_WEIGHT,
+                       ARG_DETAILS,
+                       ARG_STATS,
+               };
+               static struct option long_opts[] = {
+                       { "details", 0, 0, ARG_DETAILS },
+                       { "stats", 0, 0, ARG_STATS },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "name", 1, 0, 'n' },
+                       { "index", 1, 0, 'i' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "mtu", 1, 0, ARG_MTU },
+                       { "txqlen", 1, 0, ARG_TXQLEN },
+                       { "weight", 1, 0, ARG_WEIGHT },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "hvn:i:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case ARG_DETAILS: params.dp_type = NL_DUMP_DETAILS; break;
+               case ARG_STATS: params.dp_type = NL_DUMP_STATS; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'n': nl_cli_link_parse_name(link, optarg); break;
+               case 'i': nl_cli_link_parse_ifindex(link, optarg); break;
+               case ARG_FAMILY: nl_cli_link_parse_family(link, optarg); break;
+               case ARG_MTU: nl_cli_link_parse_mtu(link, optarg); break;
+               case ARG_TXQLEN: nl_cli_link_parse_txqlen(link, optarg); break;
+               case ARG_WEIGHT: nl_cli_link_parse_weight(link, optarg); break;
+               }
+       }
+
+       link_cache = nl_cli_link_alloc_cache_family(sock,
+                               rtnl_link_get_family(link));
+
+       nl_cache_dump_filter(link_cache, &params, OBJ_CAST(link));
+
+       return 0;
+}
diff --git a/src/nl-link-name2ifindex.c b/src/nl-link-name2ifindex.c
new file mode 100644 (file)
index 0000000..b8ae4bc
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * src/nl-link-name2ifindex.c     Transform a interface name to its index
+ *
+ *     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) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf("Usage: nl-link-name2ifindex <name>\n");
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache;
+       uint32_t ifindex;
+
+       if (argc < 2)
+               print_usage();
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       if (!(ifindex = rtnl_link_name2i(link_cache, argv[1])))
+               nl_cli_fatal(ENOENT, "Interface \"%s\" does not exist",
+                            argv[1]);
+
+       printf("%u\n", ifindex);
+
+       return 0;
+}
diff --git a/src/nl-link-release.c b/src/nl-link-release.c
new file mode 100644 (file)
index 0000000..4c9f15a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * src/nl-link-release.c     release a link
+ *
+ *     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) 2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <netlink/route/link/bonding.h>
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache;
+       struct rtnl_link *slave;
+       int err;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: nl-link-release slave\n");
+               return 1;
+       }
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       if (!(slave = rtnl_link_get_by_name(link_cache, argv[1]))) {
+               fprintf(stderr, "Unknown link: %s\n", argv[1]);
+               return 1;
+       }
+
+       if ((err = rtnl_link_bond_release(sock, slave)) < 0) {
+               fprintf(stderr, "Unable to release slave %s: %s\n",
+                       argv[1], nl_geterror(err));
+               return 1;
+       }
+
+       return 0;
+}
+
diff --git a/src/nl-link-set.c b/src/nl-link-set.c
new file mode 100644 (file)
index 0000000..3178a98
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * src/nl-link-set.c     Set link attributes
+ *
+ *     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) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+static struct nl_sock *sock;
+static int quiet = 0;
+
+#if 0
+       "  changes := [link LINK]\n"
+       "             [master MASTER] [qdisc QDISC] [addr ADDR] [broadcast BRD]\n"
+       "             [{ up | down }] [{ arp | noarp }] [{ promisc | nopromisc }]\n"
+       "             [{ dynamic | nodynamic }] [{ multicast | nomulticast }]\n"
+       "             [{ trailers | notrailers }] [{ allmulticast | noallmulticast }]\n");
+#endif
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-link-set [OPTION]... [LINK]\n"
+       "\n"
+       "Options\n"
+       " -q, --quiet           Do not print informal notifications\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Selecting the Link\n"
+       " -n, --name=NAME       link name\n"
+       " -i, --index           interface index\n"
+       "Change Options\n"
+       "     --rename=NAME     rename interface\n"
+       "     --mtu=NUM         MTU value\n"
+       "     --txqlen=NUM      TX queue length\n"
+       "     --weight=NUM      weight\n"
+       "     --ifalias=NAME    alias name (SNMP IfAlias)\n"
+       );
+       exit(0);
+}
+
+static void set_cb(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = nl_object_priv(obj);
+       struct rtnl_link *change = arg;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err;
+
+       if ((err = rtnl_link_change(sock, link, change, 0) < 0))
+               nl_cli_fatal(err, "Unable to change link: %s",
+                            nl_geterror(err));
+
+       if (!quiet) {
+               printf("Changed ");
+               nl_object_dump(OBJ_CAST(link), &params);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_cache *link_cache;
+       struct rtnl_link *link, *change;
+       int ok = 0;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       link = nl_cli_link_alloc();
+       change = nl_cli_link_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_RENAME = 257,
+                       ARG_MTU = 258,
+                       ARG_TXQLEN,
+                       ARG_WEIGHT,
+                       ARG_IFALIAS,
+               };
+               static struct option long_opts[] = {
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "name", 1, 0, 'n' },
+                       { "index", 1, 0, 'i' },
+                       { "rename", 1, 0, ARG_RENAME },
+                       { "mtu", 1, 0, ARG_MTU },
+                       { "txqlen", 1, 0, ARG_TXQLEN },
+                       { "weight", 1, 0, ARG_WEIGHT },
+                       { "ifalias", 1, 0, ARG_IFALIAS },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "qhvn:i:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'n': ok++; nl_cli_link_parse_name(link, optarg); break;
+               case 'i': ok++; nl_cli_link_parse_ifindex(link, optarg); break;
+               case ARG_RENAME: nl_cli_link_parse_name(change, optarg); break;
+               case ARG_MTU: nl_cli_link_parse_mtu(change, optarg); break;
+               case ARG_TXQLEN: nl_cli_link_parse_txqlen(change, optarg); break;
+               case ARG_WEIGHT: nl_cli_link_parse_weight(change, optarg); break;
+               case ARG_IFALIAS: nl_cli_link_parse_ifalias(change, optarg); break;
+               }
+       }
+
+       if (!ok)
+               print_usage();
+
+       nl_cache_foreach_filter(link_cache, OBJ_CAST(link), set_cb, change);
+
+       return 0;
+}
diff --git a/src/nl-link-stats.c b/src/nl-link-stats.c
new file mode 100644 (file)
index 0000000..4dfca86
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * src/nl-link-stats.c     Retrieve link statistics
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-link-stats [OPTION]... [LINK] [ListOfStats]\n"
+       "\n"
+       "Options\n"
+       " -l, --list            List available statistic names\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Link Options\n"
+       " -n, --name=NAME       link name\n"
+       " -i, --index=NUM       interface index\n"
+       );
+       exit(0);
+}
+
+static void list_stat_names(void)
+{
+       char buf[64];
+       int i;
+
+       for (i = 0; i < RTNL_LINK_STATS_MAX; i++)
+               printf("%s\n", rtnl_link_stat2str(i, buf, sizeof(buf)));
+
+       exit(0);
+}
+
+static int gargc;
+
+static void dump_stat(struct rtnl_link *link, int id)
+{
+       uint64_t st = rtnl_link_get_stat(link, id);
+       char buf[64];
+
+       printf("%s.%s %" PRIu64 "\n", rtnl_link_get_name(link),
+              rtnl_link_stat2str(id, buf, sizeof(buf)), st);
+}
+
+static void dump_stats(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = (struct rtnl_link *) obj;
+       char **argv = arg;
+
+       if (optind >= gargc) {
+               int i;
+
+               for (i = 0; i < RTNL_LINK_STATS_MAX; i++)
+                       dump_stat(link, i);
+       } else {
+               while (optind < gargc) {
+                       int id = rtnl_link_str2stat(argv[optind]);
+
+                       if (id < 0)
+                               fprintf(stderr, "Warning: Unknown statistic "
+                                       "\"%s\"\n", argv[optind]);
+                       else
+                               dump_stat(link, id);
+
+                       optind++;
+               }
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache;
+       struct rtnl_link *link;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       link = nl_cli_link_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               static struct option long_opts[] = {
+                       { "list", 0, 0, 'l' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "name", 1, 0, 'n' },
+                       { "index", 1, 0, 'i' },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "lhvn:i:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'l': list_stat_names(); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'n': nl_cli_link_parse_name(link, optarg); break;
+               case 'i': nl_cli_link_parse_ifindex(link, optarg); break;
+               }
+       }
+
+       gargc = argc;
+       nl_cache_foreach_filter(link_cache, OBJ_CAST(link), dump_stats, argv);
+
+       return 0;
+}
+
diff --git a/src/nl-list-caches.c b/src/nl-list-caches.c
new file mode 100644 (file)
index 0000000..853d8a4
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * nl-list-caches.c    List registered cache types
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/cli/utils.h>
+
+static void print_usage(void)
+{
+       fprintf(stderr, "Usage: nl-list-caches\n");
+       exit(1);
+}
+
+static char *id_attr_list(struct nl_object_ops *ops, char *buf, size_t len)
+{
+       if (ops->oo_attrs2str != NULL)
+               return ops->oo_attrs2str(ops->oo_id_attrs, buf, len);
+       else {
+               memset(buf, 0, len);
+               return buf;
+       }
+}
+
+static void print(struct nl_cache_ops *ops, void *arg)
+{
+       char buf[64];
+
+       printf("%s:\n" \
+              "    hdrsize: %d bytes\n" \
+              "    protocol: %s\n" \
+              "    request-update: %s\n" \
+              "    msg-parser: %s\n",
+              ops->co_name, ops->co_hdrsize,
+              nl_nlfamily2str(ops->co_protocol, buf, sizeof(buf)),
+              ops->co_request_update ? "yes" : "no",
+              ops->co_msg_parser ? "yes" : "no");
+
+       if (ops->co_obj_ops) {
+               struct nl_object_ops *obj_ops = ops->co_obj_ops;
+               const char *dump_names[NL_DUMP_MAX+1] = {
+                       "brief",
+                       "detailed",
+                       "stats",
+               };
+               int i;
+
+               printf("    cacheable object:\n" \
+                      "        name: %s:\n" \
+                      "        size: %zu bytes\n" \
+                      "        constructor: %s\n" \
+                      "        free-data: %s\n" \
+                      "        clone: %s\n" \
+                      "        compare: %s\n" \
+                      "        id attributes: %s\n" \
+                      "        dump: ",
+                      obj_ops->oo_name, obj_ops->oo_size,
+                      obj_ops->oo_constructor ? "yes" : "no",
+                      obj_ops->oo_free_data ? "yes" : "no",
+                      obj_ops->oo_clone ? "yes" : "no",
+                      obj_ops->oo_compare ? "yes" : "no",
+                      id_attr_list(obj_ops, buf, sizeof(buf)));
+
+               for (i = 0; i <= NL_DUMP_MAX; i++)
+                       if (obj_ops->oo_dump[i])
+                               printf("%s%s",
+                               i == 0 ? "" : ", ",
+                               dump_names[i]);
+
+               printf("\n");
+       }
+
+       if (ops->co_genl) {
+               struct genl_ops *genl_ops = ops->co_genl;
+
+               printf("    genl:\n" \
+                      "        name: %s\n" \
+                      "        user-hdr: %d\n" \
+                      "        id: %d\n",
+                      genl_ops->o_name, genl_ops->o_hdrsize, genl_ops->o_id);
+
+               if (genl_ops->o_ncmds) {
+                       int i;
+
+                       printf("        cmds:\n");
+
+                       for (i = 0; i < genl_ops->o_ncmds; i++) {
+                               struct genl_cmd *cmd = &genl_ops->o_cmds[i];
+
+                               printf("            %s:\n"
+                                      "                id: %d\n" \
+                                      "                maxattr: %d\n" \
+                                      "                msg-parser: %s\n" \
+                                      "                attr-policy: %s\n",
+                                      cmd->c_name, cmd->c_id, cmd->c_maxattr,
+                                      cmd->c_msg_parser ? "yes" : "no",
+                                      cmd->c_attr_policy ? "yes" : "no");
+                       }
+               }
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       if (argc > 1 && !strcasecmp(argv[1], "-h"))
+               print_usage();
+
+       nl_cache_ops_foreach(print, NULL);
+
+       return 0;
+}
diff --git a/src/nl-list-sockets.c b/src/nl-list-sockets.c
new file mode 100644 (file)
index 0000000..c2fa1cd
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * nl-list-sockets.c   Pretty-print /proc/net/netlink
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+
+#define PROC_NETLINK "/proc/net/netlink"
+
+int main(int argc, char *argv[])
+{
+       FILE *fd;
+       char buf[2048], p[64];
+
+       fd = fopen(PROC_NETLINK, "r");
+       if (fd == NULL) {
+               perror("fopen");
+               return -1;
+       }
+
+       printf("Address            Family           PID    Groups   rmem   "
+              "wmem   CB         refcnt\n");
+
+       while (fgets(buf, sizeof(buf), fd)) {
+               unsigned long sk, cb;
+               int ret, proto, pid, rmem, wmem, refcnt;
+               unsigned int groups;
+               
+               ret = sscanf(buf, "%lx %d %d %08x %d %d %lx %d\n",
+                            &sk, &proto, &pid, &groups, &rmem, &wmem,
+                            &cb, &refcnt);
+               if (ret != 8)
+                       continue;
+               
+               printf("0x%016lx %-16s %-6d %08x %-6d %-6d 0x%08lx %d\n",
+                       sk, nl_nlfamily2str(proto, p, sizeof(p)), pid,
+                       groups, rmem, wmem, cb, refcnt);
+       }
+
+       fclose(fd);
+
+       return 0;
+}
diff --git a/src/nl-monitor.c b/src/nl-monitor.c
new file mode 100644 (file)
index 0000000..fdf6497
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * src/nl-monitor.c     Monitor events
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+static void obj_input(struct nl_object *obj, void *arg)
+{
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_STATS,
+               .dp_fd = stdout,
+               .dp_dump_msgtype = 1,
+       };
+
+       nl_object_dump(obj, &dp);
+}
+
+static int event_input(struct nl_msg *msg, void *arg)
+{
+       if (nl_msg_parse(msg, &obj_input, NULL) < 0)
+               fprintf(stderr, "<<EVENT>> Unknown message type\n");
+
+       /* Exit nl_recvmsgs_def() and return to the main select() */
+       return NL_STOP;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache;
+       int err = 1;
+       int i, idx;
+
+       static const struct {
+               enum rtnetlink_groups gr_id;
+               const char* gr_name;
+       } known_groups[] = {
+               { RTNLGRP_LINK, "link" },
+               { RTNLGRP_NOTIFY, "notify" },
+               { RTNLGRP_NEIGH, "neigh" },
+               { RTNLGRP_TC, "tc" },
+               { RTNLGRP_IPV4_IFADDR, "ipv4-ifaddr" },
+               { RTNLGRP_IPV4_MROUTE, "ipv4-mroute" },
+               { RTNLGRP_IPV4_ROUTE, "ipv4-route" },
+               { RTNLGRP_IPV6_IFADDR, "ipv6-ifaddr" },
+               { RTNLGRP_IPV6_MROUTE, "ipv6-mroute" },
+               { RTNLGRP_IPV6_ROUTE, "ipv6-route" },
+               { RTNLGRP_IPV6_IFINFO, "ipv6-ifinfo" },
+               { RTNLGRP_DECnet_IFADDR, "decnet-ifaddr" },
+               { RTNLGRP_DECnet_ROUTE, "decnet-route" },
+               { RTNLGRP_IPV6_PREFIX, "ipv6-prefix" },
+               { RTNLGRP_NONE, NULL }
+       };
+
+       sock = nl_cli_alloc_socket();
+       nl_socket_disable_seq_check(sock);
+       nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
+
+       if (argc > 1 && !strcasecmp(argv[1], "-h")) {
+               printf("Usage: nl-monitor [<groups>]\n");
+
+               printf("Known groups:");
+               for (i = 0; known_groups[i].gr_id != RTNLGRP_NONE; i++)
+                       printf(" %s", known_groups[i].gr_name);
+               printf("\n");
+               return 2;
+       }
+
+       nl_cli_connect(sock, NETLINK_ROUTE);
+
+       for (idx = 1; argc > idx; idx++) {
+               for (i = 0; known_groups[i].gr_id != RTNLGRP_NONE; i++) {
+                       if (!strcmp(argv[idx], known_groups[i].gr_name)) {
+
+                               if ((err = nl_socket_add_membership(sock, known_groups[i].gr_id)) < 0) {
+                                       nl_cli_fatal(err, "%s: %s\n", argv[idx],
+                                                    nl_geterror(err));
+                               }
+
+                               break;
+                       }
+               }
+               if (known_groups[i].gr_id == RTNLGRP_NONE)
+                       fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]);
+       }
+
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       while (1) {
+               fd_set rfds;
+               int fd, retval;
+
+               fd = nl_socket_get_fd(sock);
+
+               FD_ZERO(&rfds);
+               FD_SET(fd, &rfds);
+               /* wait for an incoming message on the netlink socket */
+               retval = select(fd+1, &rfds, NULL, NULL, NULL);
+
+               if (retval) {
+                       /* FD_ISSET(fd, &rfds) will be true */
+                       nl_recvmsgs_default(sock);
+               }
+       }
+
+       return 0;
+}
diff --git a/src/nl-neigh-add.c b/src/nl-neigh-add.c
new file mode 100644 (file)
index 0000000..4cddabe
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * src/ nl-neigh-add.c     Add a neighbour
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/neigh.h>
+#include <netlink/cli/link.h>
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-neigh-add [OPTION]... NEIGHBOUR\n"
+       "\n"
+       "Options\n"
+       "     --update-only     Do not create neighbour, updates exclusively\n"
+       "     --create-only     Do not update neighbour if it exists already.\n"
+       " -q, --quiet           Do not print informal notifications\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Neighbour Options\n"
+       " -a, --addr=ADDR       Destination address of neighbour\n"
+       " -l, --lladdr=ADDR     Link layer address of neighbour\n"
+       " -d, --dev=DEV         Device the neighbour is connected to\n"
+       "     --state=STATE     Neighbour state, (default = permanent)\n"
+       "\n"
+       "Example\n"
+       "  nl-neigh-add --create-only --addr=10.0.0.1 --dev=eth0 \\\n"
+       "               --lladdr=AA:BB:CC:DD:EE:FF\n"
+       );
+
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_neigh *neigh;
+       struct nl_cache *link_cache;
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err, ok = 0, nlflags = NLM_F_REPLACE | NLM_F_CREATE;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       neigh = nl_cli_neigh_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_UPDATE_ONLY = 257,
+                       ARG_CREATE_ONLY = 258,
+                       ARG_STATE,
+               };
+               static struct option long_opts[] = {
+                       { "update-only", 0, 0, ARG_UPDATE_ONLY },
+                       { "create-only", 0, 0, ARG_CREATE_ONLY },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "addr", 1, 0, 'a' },
+                       { "lladdr", 1, 0, 'l' },
+                       { "dev", 1, 0, 'd' },
+                       { "state", 1, 0, ARG_STATE },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case ARG_UPDATE_ONLY: nlflags &= ~NLM_F_CREATE; break;
+               case ARG_CREATE_ONLY: nlflags |= NLM_F_EXCL; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'a': ok++; nl_cli_neigh_parse_dst(neigh, optarg); break;
+               case 'l': nl_cli_neigh_parse_lladdr(neigh, optarg); break;
+               case 'd': nl_cli_neigh_parse_dev(neigh, link_cache, optarg); break;
+               case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break;
+               }
+       }
+
+       if (!ok)
+               print_usage();
+
+       if ((err = rtnl_neigh_add(sock, neigh, nlflags)) < 0)
+               nl_cli_fatal(err, "Unable to add neighbour: %s",
+                            nl_geterror(err));
+
+       if (!quiet) {
+               printf("Added ");
+               nl_object_dump(OBJ_CAST(neigh), &dp);
+       }
+
+       return 0;
+}
diff --git a/src/nl-neigh-delete.c b/src/nl-neigh-delete.c
new file mode 100644 (file)
index 0000000..c418608
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * src/nl-neigh-delete.c     Delete a neighbour
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/neigh.h>
+#include <netlink/cli/link.h>
+
+static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
+static struct nl_sock *sock;
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-neigh-delete [OPTION]... [NEIGHBOUR]\n"
+       "\n"
+       "Options\n"
+       " -i, --interactive     Run interactively\n"
+       "     --yes             Set default answer to yes\n"
+       " -q, --quiet           Do not print informal notifications\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Neighbour Options\n"
+       " -a, --addr=ADDR       Destination address of neighbour\n"
+       " -l, --lladdr=ADDR     Link layer address of neighbour\n"
+       " -d, --dev=DEV         Device the neighbour is connected to\n"
+       "     --family=FAMILY   Destination address family\n"
+       "     --state=STATE     Neighbour state, (default = permanent)\n"
+       );
+
+       exit(0);
+}
+
+static void delete_cb(struct nl_object *obj, void *arg)
+{
+       struct rtnl_neigh *neigh = nl_object_priv(obj);
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err;
+
+       if (interactive && !nl_cli_confirm(obj, &params, default_yes))
+               return;
+
+       if ((err = rtnl_neigh_delete(sock, neigh, 0)) < 0)
+               nl_cli_fatal(err, "Unable to delete neighbour: %s\n",
+                            nl_geterror(err));
+
+       if (!quiet) {
+               printf("Deleted ");
+               nl_object_dump(obj, &params);
+       }
+
+       deleted++;
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_neigh *neigh;
+       struct nl_cache *link_cache, *neigh_cache;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       neigh_cache = nl_cli_neigh_alloc_cache(sock);
+       neigh = nl_cli_neigh_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_STATE = 258,
+                       ARG_YES,
+               };
+               static struct option long_opts[] = {
+                       { "interactive", 0, 0, 'i' },
+                       { "yes", 0, 0, ARG_YES },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "addr", 1, 0, 'a' },
+                       { "lladdr", 1, 0, 'l' },
+                       { "dev", 1, 0, 'd' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "state", 1, 0, ARG_STATE },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'i': interactive = 1; break;
+               case ARG_YES: default_yes = 1; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'a': nl_cli_neigh_parse_dst(neigh, optarg); break;
+               case 'l': nl_cli_neigh_parse_lladdr(neigh, optarg); break;
+               case 'd': nl_cli_neigh_parse_dev(neigh, link_cache, optarg); break;
+               case ARG_FAMILY: nl_cli_neigh_parse_family(neigh, optarg); break;
+               case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break;
+               }
+       }
+
+       nl_cache_foreach_filter(neigh_cache, OBJ_CAST(neigh), delete_cb, NULL);
+
+       if (!quiet)
+               printf("Deleted %d neighbours\n", deleted);
+
+       return 0;
+}
diff --git a/src/nl-neigh-list.c b/src/nl-neigh-list.c
new file mode 100644 (file)
index 0000000..ebf5486
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * src/nl-neigh-list.c      List Neighbours
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/neigh.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-neigh-list [OPTION]... [NEIGHBOUR]\n"
+       "\n"
+       "Options\n"
+       " -f, --format=TYPE     Output format { brief | details | stats }\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Neighbour Options\n"
+       " -a, --addr=ADDR       Destination address of neighbour\n"
+       " -l, --lladdr=ADDR     Link layer address of neighbour\n"
+       " -d, --dev=DEV         Device the neighbour is connected to\n"
+       "     --family=FAMILY   Destination address family\n"
+       "     --state=STATE     Neighbour state, (default = permanent)\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_neigh *neigh;
+       struct nl_cache *link_cache, *neigh_cache;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       neigh_cache = nl_cli_neigh_alloc_cache(sock);
+       neigh = nl_cli_neigh_alloc();
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_STATE = 258,
+               };
+               static struct option long_opts[] = {
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "addr", 1, 0, 'a' },
+                       { "lladdr", 1, 0, 'l' },
+                       { "dev", 1, 0, 'd' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "state", 1, 0, ARG_STATE },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "f:hva:l:d:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'a': nl_cli_neigh_parse_dst(neigh, optarg); break;
+               case 'l': nl_cli_neigh_parse_lladdr(neigh, optarg); break;
+               case 'd': nl_cli_neigh_parse_dev(neigh, link_cache, optarg); break;
+               case ARG_FAMILY: nl_cli_neigh_parse_family(neigh, optarg); break;
+               case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break;
+               }
+       }
+
+       nl_cache_dump_filter(neigh_cache, &params, OBJ_CAST(neigh));
+
+       return 0;
+}
diff --git a/src/nl-neightbl-list.c b/src/nl-neightbl-list.c
new file mode 100644 (file)
index 0000000..5010b92
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * src/nl-neightbl-list.c     Dump neighbour tables
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-neightbl-list [OPTION]...\n"
+       "\n"
+       "Options\n"
+       " -f, --format=TYPE     Output format { brief | details | stats }\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache, *neightbl_cache;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       neightbl_cache = nl_cli_alloc_cache(sock, "neighbour table",
+                                           rtnl_neightbl_alloc_cache);
+       for (;;) {
+               int c, optidx = 0;
+               static struct option long_opts[] = {
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               }
+       }
+
+       nl_cache_dump(neightbl_cache, &params);
+
+       return 0;
+}
diff --git a/src/nl-pktloc-lookup.c b/src/nl-pktloc-lookup.c
new file mode 100644 (file)
index 0000000..17c867b
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * src/nl-pktloc-lookup.c     Lookup packet location alias
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/route/pktloc.h>
+
+static void print_usage(void)
+{
+printf(
+"Usage: nl-pktloc-lookup [OPTIONS] <name>\n"
+"\n"
+"OPTIONS\n"
+" -h, --help                Show this help text.\n"
+" -v, --version             Show versioning information.\n"
+" -l, --list                List all packet location definitions.\n"
+"     --u32=VALUE          Print in iproute2's u32 selector style\n"
+"\n"
+"\n"
+"EXAMPLE\n"
+"   $ nl-pktloc-lookup ip.dst\n"
+"   $ nl-pktloc-lookup --list\n"
+"\n"
+);
+       exit(0);
+}
+
+static const char *align_txt[] = {
+       [TCF_EM_ALIGN_U8] = "u8",
+       [TCF_EM_ALIGN_U16] = "u16",
+       [TCF_EM_ALIGN_U32] = "u32"
+};
+
+static uint32_t align_mask[] = {
+       [TCF_EM_ALIGN_U8] = 0xff,
+       [TCF_EM_ALIGN_U16] = 0xffff,
+       [TCF_EM_ALIGN_U32] = 0xffffffff,
+};
+
+static const char *layer_txt[] = {
+       [TCF_LAYER_LINK] = "eth",
+       [TCF_LAYER_NETWORK] = "ip",
+       [TCF_LAYER_TRANSPORT] = "tcp"
+};
+
+static void dump_u32_style(struct rtnl_pktloc *loc, uint32_t value)
+{
+       if (loc->align > 4)
+               nl_cli_fatal(EINVAL, "u32 only supports alignments u8|u16|u32.");
+
+       if (loc->layer == TCF_LAYER_LINK)
+               nl_cli_fatal(EINVAL, "u32 does not support link "
+                               "layer locations.");
+
+       if (loc->shift > 0)
+               nl_cli_fatal(EINVAL, "u32 does not support shifting.");
+
+       printf("%s %x %x at %s%u\n",
+               align_txt[loc->align],
+               value, loc->mask ? loc->mask : align_mask[loc->align],
+               loc->layer == TCF_LAYER_TRANSPORT ? "nexthdr+" : "",
+               loc->offset);
+}
+
+static char *get_align_txt(struct rtnl_pktloc *loc)
+{
+       static char buf[16];
+
+       if (loc->align <= 4)
+               strcpy(buf, align_txt[loc->align]);
+       else
+               snprintf(buf, sizeof(buf), "%u", loc->align);
+
+       return buf;
+}
+
+static void dump_loc(struct rtnl_pktloc *loc)
+{
+       printf("%s = %s at %s+%u & %#x >> %u\n",
+               loc->name, get_align_txt(loc), layer_txt[loc->layer],
+               loc->offset, loc->mask, loc->shift);
+}
+
+static void list_cb(struct rtnl_pktloc *loc, void *arg)
+{
+       printf("%-26s %-5s %3s+%-4u %#-10x %-8u %u\n",
+               loc->name, get_align_txt(loc), layer_txt[loc->layer],
+               loc->offset, loc->mask, loc->shift, loc->refcnt);
+}
+
+static void do_list(void)
+{
+       printf(
+"name                      align  offset  mask     shift    refcnt\n");
+       printf("---------------------------------------------------------\n");
+
+       rtnl_pktloc_foreach(&list_cb, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_pktloc *loc;
+       int err, ustyle = 0;
+       uint32_t uvalue = 0;
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_U32 = 257,
+               };
+               static struct option long_opts[] = {
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "list", 0, 0, 'l' },
+                       { "u32", 1, 0, ARG_U32 },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "hvl", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'l': do_list(); exit(0);
+               case ARG_U32:
+                       ustyle = 1;
+                       uvalue = nl_cli_parse_u32(optarg);
+                       break;
+               }
+       }
+
+       if (optind >= argc)
+               print_usage();
+
+       if ((err = rtnl_pktloc_lookup(argv[optind++], &loc)) < 0)
+               nl_cli_fatal(err, "Unable to lookup packet location: %s",
+                       nl_geterror(err));
+
+       if (ustyle)
+               dump_u32_style(loc, uvalue);
+       else
+               dump_loc(loc);
+
+       return 0;
+}
diff --git a/src/nl-qdisc-add.c b/src/nl-qdisc-add.c
new file mode 100644 (file)
index 0000000..c2a7c9f
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * src/nl-qdisc-add.c     Add Queueing Discipline
+ *
+ *     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) 2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/qdisc.h>
+#include <netlink/cli/link.h>
+
+#include <netlink-private/route/tc-api.h>
+
+static int quiet = 0;
+
+static void print_usage(void)
+{
+       printf(
+"Usage: nl-qdisc-add [OPTIONS]... QDISC [CONFIGURATION]...\n"
+"\n"
+"OPTIONS\n"
+" -q, --quiet               Do not print informal notifications.\n"
+" -h, --help                Show this help text.\n"
+" -v, --version             Show versioning information.\n"
+"     --update              Update qdisc if it exists.\n"
+"     --replace             Replace or update qdisc if it exists.\n"
+"     --update-only         Only update qdisc, never create it.\n"
+"     --replace-only        Only replace or update qdisc, never create it.\n"
+" -d, --dev=DEV             Network device the qdisc should be attached to.\n"
+" -i, --id=ID               ID of new qdisc (default: auto-generated)r\n"
+" -p, --parent=ID           ID of parent { root | ingress | QDISC-ID }\n"
+"\n"
+"CONFIGURATION\n"
+" -h, --help                Show help text of qdisc specific options.\n"
+"\n"
+"EXAMPLE\n"
+"   $ nl-qdisc-add --dev=eth1 --parent=root htb --rate=100mbit\n"
+"\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_qdisc *qdisc;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache;
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_DETAILS,
+               .dp_fd = stdout,
+       };
+       struct nl_cli_tc_module *tm;
+       struct rtnl_tc_ops *ops;
+       int err, flags = NLM_F_CREATE | NLM_F_EXCL;
+       char *kind, *id = NULL;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+
+       link_cache = nl_cli_link_alloc_cache(sock);
+
+       qdisc = nl_cli_qdisc_alloc();
+       tc = (struct rtnl_tc *) qdisc;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_REPLACE = 257,
+                       ARG_UPDATE = 258,
+                       ARG_REPLACE_ONLY,
+                       ARG_UPDATE_ONLY,
+               };
+               static struct option long_opts[] = {
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "replace", 0, 0, ARG_REPLACE },
+                       { "update", 0, 0, ARG_UPDATE },
+                       { "replace-only", 0, 0, ARG_REPLACE_ONLY },
+                       { "update-only", 0, 0, ARG_UPDATE_ONLY },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "+qhvd:p:i:",
+                               long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': id = strdup(optarg); break;
+               case ARG_UPDATE: flags = NLM_F_CREATE; break;
+               case ARG_REPLACE: flags = NLM_F_CREATE | NLM_F_REPLACE; break;
+               case ARG_UPDATE_ONLY: flags = 0; break;
+               case ARG_REPLACE_ONLY: flags = NLM_F_REPLACE; break;
+               }
+       }
+
+       if (optind >= argc)
+               print_usage();
+
+       if (!rtnl_tc_get_ifindex(tc))
+               nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");
+
+       if (!rtnl_tc_get_parent(tc))
+               nl_cli_fatal(EINVAL, "You must specify a parent");
+
+       if (id) {
+               nl_cli_tc_parse_handle(tc, id, 1);
+               free(id);
+       }
+
+       kind = argv[optind++];
+       rtnl_tc_set_kind(tc, kind);
+
+       if (!(ops = rtnl_tc_get_ops(tc)))
+               nl_cli_fatal(ENOENT, "Unknown qdisc \"%s\"", kind);
+
+       if (!(tm = nl_cli_tc_lookup(ops)))
+               nl_cli_fatal(ENOTSUP, "Qdisc type \"%s\" not supported.", kind);
+
+       tm->tm_parse_argv(tc, argc, argv);
+
+       if (!quiet) {
+               printf("Adding ");
+               nl_object_dump(OBJ_CAST(qdisc), &dp);
+       }
+
+       if ((err = rtnl_qdisc_add(sock, qdisc, flags)) < 0)
+               nl_cli_fatal(EINVAL, "Unable to add qdisc: %s", nl_geterror(err));
+
+       return 0;
+}
diff --git a/src/nl-qdisc-delete.c b/src/nl-qdisc-delete.c
new file mode 100644 (file)
index 0000000..2f945bb
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * src/nl-qdisc-delete.c     Delete Queuing Disciplines
+ *
+ *     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) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/qdisc.h>
+#include <netlink/cli/link.h>
+
+static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
+static struct nl_sock *sock;
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-qdisc-delete [OPTION]... [QDISC]\n"
+       "\n"
+       "OPTIONS\n"
+       "     --interactive     Run interactively.\n"
+       "     --yes             Set default answer to yes.\n"
+       " -q, --quiet           Do not print informal notifications.\n"
+       " -h, --help            Show this help text and exit.\n"
+       " -v, --version         Show versioning information and exit.\n"
+       "\n"
+       " -d, --dev=DEV         Device the qdisc is attached to.\n"
+       " -p, --parent=ID       Identifier of parent qdisc/class.\n"
+       " -i, --id=ID           Identifier\n"
+       " -k, --kind=NAME       Kind of qdisc (e.g. pfifo_fast)\n"
+       );
+
+       exit(0);
+}
+
+static void delete_cb(struct nl_object *obj, void *arg)
+{
+       struct rtnl_qdisc *qdisc = nl_object_priv(obj);
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err;
+
+       /* Ignore default qdiscs, unable to delete */
+       if (rtnl_tc_get_handle((struct rtnl_tc *) qdisc) == 0)
+               return;
+
+       if (interactive && !nl_cli_confirm(obj, &params, default_yes))
+               return;
+
+       if ((err = rtnl_qdisc_delete(sock, qdisc)) < 0)
+               nl_cli_fatal(err, "Unable to delete qdisc: %s\n", nl_geterror(err));
+
+       if (!quiet) {
+               printf("Deleted ");
+               nl_object_dump(obj, &params);
+       }
+
+       deleted++;
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_qdisc *qdisc;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache, *qdisc_cache;
+       int nfilter = 0;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       qdisc_cache = nl_cli_qdisc_alloc_cache(sock);
+       qdisc = nl_cli_qdisc_alloc();
+       tc = (struct rtnl_tc *) qdisc;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_YES = 257,
+                       ARG_INTERACTIVE = 258,
+               };
+               static struct option long_opts[] = {
+                       { "interactive", 0, 0, ARG_INTERACTIVE },
+                       { "yes", 0, 0, ARG_YES },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "qhvd:p:i:k:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case '?': nl_cli_fatal(EINVAL, "Invalid options");
+               case ARG_INTERACTIVE: interactive = 1; break;
+               case ARG_YES: default_yes = 1; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd':
+                       nfilter++;
+                       nl_cli_tc_parse_dev(tc, link_cache, optarg);
+                       break;
+               case 'p':
+                       nfilter++;
+                       nl_cli_tc_parse_parent(tc, optarg);
+                       break;
+               case 'i':
+                       nfilter++;
+                       nl_cli_tc_parse_handle(tc, optarg, 0);
+                       break;
+               case 'k':
+                       nfilter++;
+                       nl_cli_tc_parse_kind(tc, optarg);
+                       break;
+               }
+       }
+
+       if (nfilter == 0 && !interactive && !default_yes) {
+               nl_cli_fatal(EINVAL,
+                       "You are attempting to delete all qdiscs on all devices.\n"
+                       "If you want to proceed, run nl-qdisc-delete --yes.\n"
+                       "Aborting...");
+       }
+
+       nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(qdisc), delete_cb, NULL);
+
+       if (!quiet)
+               printf("Deleted %d qdiscs\n", deleted);
+
+       return 0;
+}
diff --git a/src/nl-qdisc-list.c b/src/nl-qdisc-list.c
new file mode 100644 (file)
index 0000000..5b0a3f0
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * src/nl-qdisc-list.c     List Queueing Disciplines
+ *
+ *     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) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/cli/qdisc.h>
+#include <netlink/cli/class.h>
+#include <netlink/cli/cls.h>
+#include <netlink/cli/link.h>
+
+#define NUM_INDENT 4
+
+static struct nl_sock *sock;
+static int recursive = 0;
+static struct nl_dump_params params = {
+       .dp_type = NL_DUMP_LINE,
+};
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-qdisc-list [OPTION]... [QDISC]\n"
+       "\n"
+       "OPTIONS\n"
+       "     --details         Show details\n"
+       "     --stats           Show statistics\n"
+       " -r, --recursive       Show recursive tree\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       " -d, --dev=DEV         Device the qdisc is attached to. (default: all)\n"
+       " -p, --parent=ID       Identifier of parent qdisc.\n"
+       " -i, --id=ID           Identifier.\n"
+       " -k, --kind=NAME       Kind of qdisc (e.g. pfifo_fast)\n"
+       "\n"
+       "EXAMPLE\n"
+       "    # Display statistics of all qdiscs attached to eth0\n"
+       "    $ nl-qdisc-list --details --dev=eth0\n"
+       "\n"
+       );
+       exit(0);
+}
+
+static void list_classes(int ifindex, uint32_t parent);
+static void list_qdiscs(int ifindex, uint32_t parent);
+
+static void list_class(struct nl_object *obj, void *arg)
+{
+       struct rtnl_tc *tc = nl_object_priv(obj);
+       nl_object_dump(obj, &params);
+
+       list_classes(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));
+       list_qdiscs(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));
+}
+
+static void list_classes(int ifindex, uint32_t parent)
+{
+       struct nl_cache *class_cache;
+       struct rtnl_class *filter = nl_cli_class_alloc();
+
+       class_cache = nl_cli_class_alloc_cache(sock, ifindex);
+
+       rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
+       params.dp_prefix += NUM_INDENT;
+       nl_cache_foreach_filter(class_cache, OBJ_CAST(filter), list_class, NULL);
+       params.dp_prefix -= NUM_INDENT;
+
+       rtnl_class_put(filter);
+       nl_cache_free(class_cache);
+}
+
+static void list_cls(int ifindex, uint32_t parent)
+{
+       struct nl_cache *cls_cache;
+
+       cls_cache = nl_cli_cls_alloc_cache(sock, ifindex, parent);
+
+       params.dp_prefix += NUM_INDENT;
+       nl_cache_dump(cls_cache, &params);
+       params.dp_prefix -= NUM_INDENT;
+
+       nl_cache_free(cls_cache);
+}
+
+static void list_qdisc(struct nl_object *obj, void *arg)
+{
+       struct rtnl_qdisc *qdisc = nl_object_priv(obj);
+       struct rtnl_tc *tc = (struct rtnl_tc *) qdisc;
+
+       nl_object_dump(obj, &params);
+
+       list_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));
+
+       if (rtnl_tc_get_parent(tc) == TC_H_ROOT) {
+               list_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT);
+               list_classes(rtnl_tc_get_ifindex(tc), TC_H_ROOT);
+       }
+
+       list_classes(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc));
+}
+
+static void list_qdiscs(int ifindex, uint32_t parent)
+{
+       struct nl_cache *qdisc_cache;
+       struct rtnl_qdisc *filter = nl_cli_qdisc_alloc();
+
+       qdisc_cache = nl_cli_qdisc_alloc_cache(sock);
+
+       rtnl_tc_set_ifindex((struct rtnl_tc *) filter, ifindex);
+       rtnl_tc_set_parent((struct rtnl_tc *) filter, parent);
+       params.dp_prefix += NUM_INDENT;
+       nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter), list_qdisc, NULL);
+       params.dp_prefix -= NUM_INDENT;
+
+       rtnl_qdisc_put(filter);
+       nl_cache_free(qdisc_cache);
+}
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_qdisc *qdisc;
+       struct rtnl_tc *tc;
+       struct nl_cache *link_cache, *qdisc_cache;
+       params.dp_fd = stdout;
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       qdisc_cache = nl_cli_qdisc_alloc_cache(sock);
+       qdisc = nl_cli_qdisc_alloc();
+       tc = (struct rtnl_tc *) qdisc;
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_DETAILS = 257,
+                       ARG_STATS = 258,
+               };
+               static struct option long_opts[] = {
+                       { "details", 0, 0, ARG_DETAILS },
+                       { "stats", 0, 0, ARG_STATS },
+                       { "recursive", 0, 0, 'r' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dev", 1, 0, 'd' },
+                       { "parent", 1, 0, 'p' },
+                       { "id", 1, 0, 'i' },
+                       { "kind", 1, 0, 'k' },
+                       { 0, 0, 0, 0 }
+               };
+       
+               c = getopt_long(argc, argv, "rhvd:p:i:k:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case ARG_DETAILS: params.dp_type = NL_DUMP_DETAILS; break;
+               case ARG_STATS: params.dp_type = NL_DUMP_STATS; break;
+               case 'r': recursive = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break;
+               case 'p': nl_cli_tc_parse_parent(tc, optarg); break;
+               case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
+               case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
+               }
+       }
+
+       if (recursive)
+               nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(qdisc), list_qdisc, NULL);
+       else
+               nl_cache_dump_filter(qdisc_cache, &params, OBJ_CAST(qdisc));
+
+       return 0;
+}
diff --git a/src/nl-route-add.c b/src/nl-route-add.c
new file mode 100644 (file)
index 0000000..d4aa767
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * src/nl-route-add.c     Route addition utility
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/route.h>
+#include <netlink/cli/link.h>
+
+static int quiet = 0;
+static struct nl_cache *link_cache, *route_cache;
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-route-add [OPTION]... [ROUTE]\n"
+       "\n"
+       "Options\n"
+       " -q, --quiet           Do not print informal notifications\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Route Options\n"
+       " -d, --dst=ADDR        destination prefix, e.g. 10.10.0.0/16\n"
+       " -n, --nexthop=NH      nexthop configuration:\n"
+       "                         dev=DEV         route via device\n"
+       "                         weight=WEIGHT   weight of nexthop\n"
+       "                         flags=FLAGS\n"
+       "                         via=GATEWAY     route via other node\n"
+       "                         realms=REALMS\n"
+       "                         e.g. dev=eth0,via=192.168.1.12\n"
+       " -t, --table=TABLE     Routing table\n"
+       "     --family=FAMILY   Address family\n"
+       "     --src=ADDR        Source prefix\n"
+       "     --iif=DEV         Incomming interface\n"
+       "     --pref-src=ADDR   Preferred source address\n"
+       "     --metrics=OPTS    Metrics configurations\n"
+       "     --priority=NUM    Priotity\n"
+       "     --scope=SCOPE     Scope\n"
+       "     --protocol=PROTO  Protocol\n"
+       "     --type=TYPE       { unicast | local | broadcast | multicast }\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_route *route;
+       struct nl_dump_params dp = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err = 1;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       route_cache = nl_cli_route_alloc_cache(sock, 0);
+       route = nl_cli_route_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_SRC = 258,
+                       ARG_IIF,
+                       ARG_PREF_SRC,
+                       ARG_METRICS,
+                       ARG_PRIORITY,
+                       ARG_SCOPE,
+                       ARG_PROTOCOL,
+                       ARG_TYPE,
+               };
+               static struct option long_opts[] = {
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dst", 1, 0, 'd' },
+                       { "nexthop", 1, 0, 'n' },
+                       { "table", 1, 0, 't' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "src", 1, 0, ARG_SRC },
+                       { "iif", 1, 0, ARG_IIF },
+                       { "pref-src", 1, 0, ARG_PREF_SRC },
+                       { "metrics", 1, 0, ARG_METRICS },
+                       { "priority", 1, 0, ARG_PRIORITY },
+                       { "scope", 1, 0, ARG_SCOPE },
+                       { "protocol", 1, 0, ARG_PROTOCOL },
+                       { "type", 1, 0, ARG_TYPE },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "qhvd:n:t:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_route_parse_dst(route, optarg); break;
+               case 'n': nl_cli_route_parse_nexthop(route, optarg, link_cache); break;
+               case 't': nl_cli_route_parse_table(route, optarg); break;
+               case ARG_FAMILY: nl_cli_route_parse_family(route, optarg); break;
+               case ARG_SRC: nl_cli_route_parse_src(route, optarg); break;
+               case ARG_IIF: nl_cli_route_parse_iif(route, optarg, link_cache); break;
+               case ARG_PREF_SRC: nl_cli_route_parse_pref_src(route, optarg); break;
+               case ARG_METRICS: nl_cli_route_parse_metric(route, optarg); break;
+               case ARG_PRIORITY: nl_cli_route_parse_prio(route, optarg); break;
+               case ARG_SCOPE: nl_cli_route_parse_scope(route, optarg); break;
+               case ARG_PROTOCOL: nl_cli_route_parse_protocol(route, optarg); break;
+               case ARG_TYPE: nl_cli_route_parse_type(route, optarg); break;
+               }
+       }
+
+       if ((err = rtnl_route_add(sock, route, NLM_F_EXCL)) < 0)
+               nl_cli_fatal(err, "Unable to add route: %s", nl_geterror(err));
+
+       if (!quiet) {
+               printf("Added ");
+               nl_object_dump(OBJ_CAST(route), &dp);
+       }
+
+       return 0;
+}
diff --git a/src/nl-route-delete.c b/src/nl-route-delete.c
new file mode 100644 (file)
index 0000000..884fd7f
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * src/nl-route-delete.c     Delete Routes
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/route.h>
+#include <netlink/cli/link.h>
+
+static int interactive = 0, default_yes = 0, quiet = 0;
+static int deleted = 0;
+static struct nl_sock *sock;
+
+static void print_version(void)
+{
+       fprintf(stderr, "%s\n", LIBNL_STRING);
+       exit(0);
+}
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-route-delete [OPTION]... [ROUTE]\n"
+       "\n"
+       "Options\n"
+       " -i, --interactive     Run interactively\n"
+       "     --yes             Set default answer to yes\n"
+       " -q, --quiet           Do not print informal notifications\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Route Options\n"
+       " -d, --dst=ADDR        destination prefix, e.g. 10.10.0.0/16\n"
+       " -n, --nexthop=NH      nexthop configuration:\n"
+       "                         dev=DEV         route via device\n"
+       "                         weight=WEIGHT   weight of nexthop\n"
+       "                         flags=FLAGS\n"
+       "                         via=GATEWAY     route via other node\n"
+       "                         realms=REALMS\n"
+       "                         e.g. dev=eth0,via=192.168.1.12\n"
+       " -t, --table=TABLE     Routing table\n"
+       "     --family=FAMILY   Address family\n"
+       "     --src=ADDR        Source prefix\n"
+       "     --iif=DEV         Incomming interface\n"
+       "     --pref-src=ADDR   Preferred source address\n"
+       "     --metrics=OPTS    Metrics configurations\n"
+       "     --priority=NUM    Priotity\n"
+       "     --scope=SCOPE     Scope\n"
+       "     --protocol=PROTO  Protocol\n"
+       "     --type=TYPE       { unicast | local | broadcast | multicast }\n"
+       );
+       exit(0);
+}
+
+static void delete_cb(struct nl_object *obj, void *arg)
+{
+       struct rtnl_route *route = (struct rtnl_route *) obj;
+       struct nl_dump_params params = {
+               .dp_type = NL_DUMP_LINE,
+               .dp_fd = stdout,
+       };
+       int err;
+
+       if (interactive && !nl_cli_confirm(obj, &params, default_yes))
+               return;
+
+       if ((err = rtnl_route_delete(sock, route, 0)) < 0)
+               nl_cli_fatal(err, "Unable to delete route: %s", nl_geterror(err));
+
+       if (!quiet) {
+               printf("Deleted ");
+               nl_object_dump(obj, &params);
+       }
+
+       deleted++;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_cache *link_cache, *route_cache;
+       struct rtnl_route *route;
+       int nf = 0;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       route_cache = nl_cli_route_alloc_cache(sock, 0);
+       route = nl_cli_route_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_SRC = 258,
+                       ARG_IIF,
+                       ARG_PREF_SRC,
+                       ARG_METRICS,
+                       ARG_PRIORITY,
+                       ARG_SCOPE,
+                       ARG_PROTOCOL,
+                       ARG_TYPE,
+                       ARG_YES,
+               };
+               static struct option long_opts[] = {
+                       { "interactive", 0, 0, 'i' },
+                       { "yes", 0, 0, ARG_YES },
+                       { "quiet", 0, 0, 'q' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dst", 1, 0, 'd' },
+                       { "nexthop", 1, 0, 'n' },
+                       { "table", 1, 0, 't' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "src", 1, 0, ARG_SRC },
+                       { "iif", 1, 0, ARG_IIF },
+                       { "pref-src", 1, 0, ARG_PREF_SRC },
+                       { "metrics", 1, 0, ARG_METRICS },
+                       { "priority", 1, 0, ARG_PRIORITY },
+                       { "scope", 1, 0, ARG_SCOPE },
+                       { "protocol", 1, 0, ARG_PROTOCOL },
+                       { "type", 1, 0, ARG_TYPE },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "iqhvd:n:t:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'i': interactive = 1; break;
+               case ARG_YES: default_yes = 1; break;
+               case 'q': quiet = 1; break;
+               case 'h': print_usage(); break;
+               case 'v': print_version(); break;
+               case 'd': nf++; nl_cli_route_parse_dst(route, optarg); break;
+               case 'n': nf++; nl_cli_route_parse_nexthop(route, optarg, link_cache); break;
+               case 't': nf++; nl_cli_route_parse_table(route, optarg); break;
+               case ARG_FAMILY: nf++; nl_cli_route_parse_family(route, optarg); break;
+               case ARG_SRC: nf++; nl_cli_route_parse_src(route, optarg); break;
+               case ARG_IIF: nf++; nl_cli_route_parse_iif(route, optarg, link_cache); break;
+               case ARG_PREF_SRC: nf++; nl_cli_route_parse_pref_src(route, optarg); break;
+               case ARG_METRICS: nf++; nl_cli_route_parse_metric(route, optarg); break;
+               case ARG_PRIORITY: nf++; nl_cli_route_parse_prio(route, optarg); break;
+               case ARG_SCOPE: nf++; nl_cli_route_parse_scope(route, optarg); break;
+               case ARG_PROTOCOL: nf++; nl_cli_route_parse_protocol(route, optarg); break;
+               case ARG_TYPE: nf++; nl_cli_route_parse_type(route, optarg); break;
+               }
+       }
+
+       if (nf == 0 && !interactive && !default_yes) {
+               fprintf(stderr, "You attempted to delete all routes in "
+                       "non-interactive mode, aborting.\n");
+               exit(0);
+       }
+
+       nl_cache_foreach_filter(route_cache, OBJ_CAST(route), delete_cb, NULL);
+
+       if (!quiet)
+               printf("Deleted %d routes\n", deleted);
+
+       return 0;
+}
diff --git a/src/nl-route-get.c b/src/nl-route-get.c
new file mode 100644 (file)
index 0000000..c2f07d4
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * src/nl-route-get.c     Get Route Attributes
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/route.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf("Usage: nl-route-get <addr>\n");
+       exit(1);
+}
+
+static void parse_cb(struct nl_object *obj, void *arg)
+{
+       //struct rtnl_route *route = (struct rtnl_route *) obj;
+       struct nl_dump_params params = {
+               .dp_fd = stdout,
+               .dp_type = NL_DUMP_DETAILS,
+       };
+
+       nl_object_dump(obj, &params);
+}
+
+static int cb(struct nl_msg *msg, void *arg)
+{
+       int err;
+
+       if ((err = nl_msg_parse(msg, &parse_cb, NULL)) < 0)
+               nl_cli_fatal(err, "Unable to parse object: %s", nl_geterror(err));
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache, *route_cache;
+       struct nl_addr *dst;
+       int err = 1;
+
+       if (argc < 2 || !strcmp(argv[1], "-h"))
+               print_usage();
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       route_cache = nl_cli_route_alloc_cache(sock, 0);
+
+       dst = nl_cli_addr_parse(argv[1], AF_INET);
+
+       {
+               struct nl_msg *m;
+               struct rtmsg rmsg = {
+                       .rtm_family = nl_addr_get_family(dst),
+                       .rtm_dst_len = nl_addr_get_prefixlen(dst),
+               };
+
+               m = nlmsg_alloc_simple(RTM_GETROUTE, 0);
+               nlmsg_append(m, &rmsg, sizeof(rmsg), NLMSG_ALIGNTO);
+               nla_put_addr(m, RTA_DST, dst);
+
+               err = nl_send_auto_complete(sock, m);
+               nlmsg_free(m);
+               if (err < 0)
+                       nl_cli_fatal(err, "%s", nl_geterror(err));
+
+               nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
+
+               if (nl_recvmsgs_default(sock) < 0)
+                       nl_cli_fatal(err, "%s", nl_geterror(err));
+       }
+
+       //nl_cache_dump(route_cache, &params);
+
+       return 0;
+}
diff --git a/src/nl-route-list.c b/src/nl-route-list.c
new file mode 100644 (file)
index 0000000..e0e57be
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * src/nl-route-list.c     List route attributes
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/route.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-route-list [OPTION]... [ROUTE]\n"
+       "\n"
+       "Options\n"
+       " -c, --cache           List the contents of the route cache\n"
+       " -f, --format=TYPE     Output format { brief | details | stats }\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Route Options\n"
+       " -d, --dst=ADDR        destination prefix, e.g. 10.10.0.0/16\n"
+       " -n, --nexthop=NH      nexthop configuration:\n"
+       "                         dev=DEV         route via device\n"
+       "                         weight=WEIGHT   weight of nexthop\n"
+       "                         flags=FLAGS\n"
+       "                         via=GATEWAY     route via other node\n"
+       "                         realms=REALMS\n"
+       "                         e.g. dev=eth0,via=192.168.1.12\n"
+       " -t, --table=TABLE     Routing table\n"
+       "     --family=FAMILY   Address family\n"
+       "     --src=ADDR        Source prefix\n"
+       "     --iif=DEV         Incomming interface\n"
+       "     --pref-src=ADDR   Preferred source address\n"
+       "     --metrics=OPTS    Metrics configurations\n"
+       "     --priority=NUM    Priotity\n"
+       "     --scope=SCOPE     Scope\n"
+       "     --protocol=PROTO  Protocol\n"
+       "     --type=TYPE       { unicast | local | broadcast | multicast }\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_cache *link_cache, *route_cache;
+       struct rtnl_route *route;
+       struct nl_dump_params params = {
+               .dp_fd = stdout,
+               .dp_type = NL_DUMP_LINE,
+       };
+       int print_cache = 0;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       route = nl_cli_route_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+                       ARG_SRC = 258,
+                       ARG_IIF,
+                       ARG_PREF_SRC,
+                       ARG_METRICS,
+                       ARG_PRIORITY,
+                       ARG_SCOPE,
+                       ARG_PROTOCOL,
+                       ARG_TYPE,
+               };
+               static struct option long_opts[] = {
+                       { "cache", 0, 0, 'c' },
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "dst", 1, 0, 'd' },
+                       { "nexthop", 1, 0, 'n' },
+                       { "table", 1, 0, 't' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { "src", 1, 0, ARG_SRC },
+                       { "iif", 1, 0, ARG_IIF },
+                       { "pref-src", 1, 0, ARG_PREF_SRC },
+                       { "metrics", 1, 0, ARG_METRICS },
+                       { "priority", 1, 0, ARG_PRIORITY },
+                       { "scope", 1, 0, ARG_SCOPE },
+                       { "protocol", 1, 0, ARG_PROTOCOL },
+                       { "type", 1, 0, ARG_TYPE },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "cf:hvd:n:t:", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'c': print_cache = 1; break;
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case 'd': nl_cli_route_parse_dst(route, optarg); break;
+               case 'n': nl_cli_route_parse_nexthop(route, optarg, link_cache); break;
+               case 't': nl_cli_route_parse_table(route, optarg); break;
+               case ARG_FAMILY: nl_cli_route_parse_family(route, optarg); break;
+               case ARG_SRC: nl_cli_route_parse_src(route, optarg); break;
+               case ARG_IIF: nl_cli_route_parse_iif(route, optarg, link_cache); break;
+               case ARG_PREF_SRC: nl_cli_route_parse_pref_src(route, optarg); break;
+               case ARG_METRICS: nl_cli_route_parse_metric(route, optarg); break;
+               case ARG_PRIORITY: nl_cli_route_parse_prio(route, optarg); break;
+               case ARG_SCOPE: nl_cli_route_parse_scope(route, optarg); break;
+               case ARG_PROTOCOL: nl_cli_route_parse_protocol(route, optarg); break;
+               case ARG_TYPE: nl_cli_route_parse_type(route, optarg); break;
+               }
+       }
+
+       route_cache = nl_cli_route_alloc_cache(sock,
+                               print_cache ? ROUTE_CACHE_CONTENT : 0);
+
+       nl_cache_dump_filter(route_cache, &params, OBJ_CAST(route));
+
+       return 0;
+}
diff --git a/src/nl-rule-list.c b/src/nl-rule-list.c
new file mode 100644 (file)
index 0000000..8b474fa
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * src/nl-rule-dump.c     Dump rule attributes
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/rule.h>
+#include <netlink/cli/link.h>
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-rule-list [OPTION]... [ROUTE]\n"
+       "\n"
+       "Options\n"
+       " -c, --cache           List the contents of the route cache\n"
+       " -f, --format=TYPE     Output format { brief | details | stats }\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       "\n"
+       "Rule Options\n"
+       "     --family          Address family\n"
+       );
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct rtnl_rule *rule;
+       struct nl_cache *link_cache, *rule_cache;
+       struct nl_dump_params params = {
+               .dp_fd = stdout,
+               .dp_type = NL_DUMP_LINE,
+       };
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       rule_cache = nl_cli_rule_alloc_cache(sock);
+       rule = nl_cli_rule_alloc();
+
+       for (;;) {
+               int c, optidx = 0;
+               enum {
+                       ARG_FAMILY = 257,
+               };
+               static struct option long_opts[] = {
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { "family", 1, 0, ARG_FAMILY },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               case ARG_FAMILY: nl_cli_rule_parse_family(rule, optarg); break;
+               }
+       }
+
+       nl_cache_dump_filter(rule_cache, &params, OBJ_CAST(rule));
+
+       return 0;
+}
diff --git a/src/nl-tctree-list.c b/src/nl-tctree-list.c
new file mode 100644 (file)
index 0000000..d90cb28
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * src/nl-tctree-list.c                List Traffic Control Tree
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <netlink/cli/qdisc.h>
+#include <netlink/cli/class.h>
+#include <linux/pkt_sched.h>
+
+static struct nl_sock *sock;
+static struct nl_cache *qdisc_cache, *class_cache;
+static struct nl_dump_params params = {
+       .dp_type = NL_DUMP_DETAILS,
+};
+
+static int ifindex;
+static void print_qdisc(struct nl_object *, void *);
+static void print_tc_childs(struct rtnl_tc *, void *);
+
+static void print_usage(void)
+{
+       printf(
+       "Usage: nl-tctree-list [OPTION]...\n"
+       "\n"
+       "Options\n"
+       " -f, --format=TYPE     Output format { brief | details | stats }\n"
+       " -h, --help            Show this help\n"
+       " -v, --version         Show versioning information\n"
+       );
+       exit(0);
+}
+
+static void print_class(struct nl_object *obj, void *arg)
+{
+       struct rtnl_qdisc *leaf;
+       struct rtnl_class *class = (struct rtnl_class *) obj;
+       struct nl_cache *cls_cache;
+       uint32_t parent = rtnl_tc_get_handle((struct rtnl_tc *) class);
+
+       params.dp_prefix = (int)(long) arg;
+       nl_object_dump(obj, &params);
+
+       leaf = rtnl_class_leaf_qdisc(class, qdisc_cache);
+       if (leaf)
+               print_qdisc((struct nl_object *) leaf, arg + 2);
+
+       print_tc_childs(TC_CAST(class), arg + 2);
+
+       if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
+               return;
+
+       params.dp_prefix = (int)(long) arg + 2;
+       nl_cache_dump(cls_cache, &params);
+       nl_cache_free(cls_cache);
+}
+
+static void print_tc_childs(struct rtnl_tc *tc, void *arg)
+{
+       struct rtnl_class *filter;
+
+       filter = nl_cli_class_alloc();
+
+       rtnl_tc_set_parent(TC_CAST(filter), rtnl_tc_get_handle(tc));
+       rtnl_tc_set_ifindex(TC_CAST(filter), rtnl_tc_get_ifindex(tc));
+
+       nl_cache_foreach_filter(class_cache, OBJ_CAST(filter), &print_class, arg);
+
+       rtnl_class_put(filter);
+}
+
+static void print_qdisc(struct nl_object *obj, void *arg)
+{
+       struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj;
+       struct nl_cache *cls_cache;
+       uint32_t parent = rtnl_tc_get_handle((struct rtnl_tc *) qdisc);
+
+       params.dp_prefix = (int)(long) arg;
+       nl_object_dump(obj, &params);
+
+       print_tc_childs(TC_CAST(qdisc), arg + 2);
+
+       if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
+               return;
+
+       params.dp_prefix = (int)(long) arg + 2;
+       nl_cache_dump(cls_cache, &params);
+       nl_cache_free(cls_cache);
+}
+
+static void print_link(struct nl_object *obj, void *arg)
+{
+       struct rtnl_link *link = (struct rtnl_link *) obj;
+       struct rtnl_qdisc *qdisc;
+
+       ifindex = rtnl_link_get_ifindex(link);
+       params.dp_prefix = 0;
+       nl_object_dump(obj, &params);
+
+       if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0)
+               return;
+
+       qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT);
+       if (qdisc) {
+               print_qdisc((struct nl_object *) qdisc, (void *) 2);
+               rtnl_qdisc_put(qdisc);
+       }
+
+       qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0);
+       if (qdisc) {
+               print_qdisc((struct nl_object *) qdisc, (void *) 2);
+               rtnl_qdisc_put(qdisc);
+       }
+
+       qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS);
+       if (qdisc) {
+               print_qdisc((struct nl_object *) qdisc, (void *) 2);
+               rtnl_qdisc_put(qdisc);
+       }
+
+       nl_cache_free(class_cache);
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_cache *link_cache;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_ROUTE);
+       link_cache = nl_cli_link_alloc_cache(sock);
+       qdisc_cache = nl_cli_qdisc_alloc_cache(sock);
+
+       params.dp_fd = stdout;
+
+       for (;;) {
+               int c, optidx = 0;
+               static struct option long_opts[] = {
+                       { "format", 1, 0, 'f' },
+                       { "help", 0, 0, 'h' },
+                       { "version", 0, 0, 'v' },
+                       { 0, 0, 0, 0 }
+               };
+
+               c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'f': params.dp_type = nl_cli_parse_dumptype(optarg); break;
+               case 'h': print_usage(); break;
+               case 'v': nl_cli_print_version(); break;
+               }
+       }
+
+       nl_cache_foreach(link_cache, &print_link, NULL);
+
+       return 0;
+}
diff --git a/src/nl-util-addr.c b/src/nl-util-addr.c
new file mode 100644 (file)
index 0000000..5f0738d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * src/nl-util-addr.c     Address Helper
+ *
+ *     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) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+
+int main(int argc, char *argv[])
+{
+       int err;
+       char host[256];
+       struct nl_addr *a;
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage: nl-util-addr <address>\n");
+               return -1;
+       }
+
+       a = nl_cli_addr_parse(argv[1], AF_UNSPEC);
+       err = nl_addr_resolve(a, host, sizeof(host));
+       if (err != 0)
+               nl_cli_fatal(err, "Unable to resolve address \"%s\": %s",
+                     argv[1], nl_geterror(err));
+
+       printf("%s\n", host);
+
+       return 0;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644 (file)
index 0000000..7953176
--- /dev/null
@@ -0,0 +1,54 @@
+# -*- Makefile -*-
+
+EXTRA_DIST = \
+       util.h
+
+if ENABLE_UNIT_TESTS
+
+AM_CPPFLAGS  = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
+
+LDADD = \
+       ${top_builddir}/lib/libnl-3.la \
+       ${top_builddir}/lib/libnl-nf-3.la \
+       ${top_builddir}/lib/libnl-genl-3.la \
+       ${top_builddir}/lib/libnl-route-3.la \
+       @CHECK_LIBS@
+
+CFLAGS += @CHECK_CFLAGS@
+
+UNIT_TESTS = check-all
+
+check_PROGRAMS = \
+       test-create-bond \
+       test-create-vlan \
+       test-delete-link \
+       test-socket-creation \
+       test-complex-HTB-with-hash-filters \
+       ${UNIT_TESTS}
+
+TESTS = \
+       ${UNIT_TESTS}
+
+if ENABLE_CLI
+LDADD += ${top_builddir}/src/lib/libnl-cli-3.la
+check_PROGRAMS += \
+       test-cache-mngr \
+       test-genl \
+       test-nf-cache-mngr
+endif
+
+test_cache_mngr_SOURCES = test-cache-mngr.c
+test_create_bond_SOURCES = test-create-bond.c
+test_create_vlan_SOURCES = test-create-vlan.c
+test_delete_link_SOURCES = test-delete-link.c
+test_genl_SOURCES = test-genl.c
+test_nf_cache_mngr_SOURCES = test-nf-cache-mngr.c
+test_socket_creation_SOURCES = test-socket-creation.c
+test_complex_HTB_with_hash_filters_SOURCES = test-complex-HTB-with-hash-filters.c
+
+# Unit tests
+check_all_SOURCES = \
+       check-all.c \
+       check-addr.c \
+       check-attr.c
+endif
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644 (file)
index 0000000..85d4fd8
--- /dev/null
@@ -0,0 +1,814 @@
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# -*- Makefile -*-
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@ENABLE_UNIT_TESTS_TRUE@am__append_1 = @CHECK_CFLAGS@
+@ENABLE_UNIT_TESTS_TRUE@check_PROGRAMS = test-create-bond$(EXEEXT) \
+@ENABLE_UNIT_TESTS_TRUE@       test-create-vlan$(EXEEXT) \
+@ENABLE_UNIT_TESTS_TRUE@       test-delete-link$(EXEEXT) \
+@ENABLE_UNIT_TESTS_TRUE@       test-socket-creation$(EXEEXT) \
+@ENABLE_UNIT_TESTS_TRUE@       test-complex-HTB-with-hash-filters$(EXEEXT) \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__EXEEXT_1) $(am__EXEEXT_2)
+@ENABLE_UNIT_TESTS_TRUE@TESTS = $(am__EXEEXT_1)
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@am__append_2 = ${top_builddir}/src/lib/libnl-cli-3.la
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@am__append_3 = \
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@      test-cache-mngr \
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@      test-genl \
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@      test-nf-cache-mngr
+
+subdir = tests
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/defs.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@ENABLE_UNIT_TESTS_TRUE@am__EXEEXT_1 = check-all$(EXEEXT)
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@am__EXEEXT_2 = test-cache-mngr$(EXEEXT) \
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@      test-genl$(EXEEXT) \
+@ENABLE_CLI_TRUE@@ENABLE_UNIT_TESTS_TRUE@      test-nf-cache-mngr$(EXEEXT)
+am__check_all_SOURCES_DIST = check-all.c check-addr.c check-attr.c
+@ENABLE_UNIT_TESTS_TRUE@am_check_all_OBJECTS = check-all.$(OBJEXT) \
+@ENABLE_UNIT_TESTS_TRUE@       check-addr.$(OBJEXT) \
+@ENABLE_UNIT_TESTS_TRUE@       check-attr.$(OBJEXT)
+check_all_OBJECTS = $(am_check_all_OBJECTS)
+check_all_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@check_all_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__test_cache_mngr_SOURCES_DIST = test-cache-mngr.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_cache_mngr_OBJECTS =  \
+@ENABLE_UNIT_TESTS_TRUE@       test-cache-mngr.$(OBJEXT)
+test_cache_mngr_OBJECTS = $(am_test_cache_mngr_OBJECTS)
+test_cache_mngr_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_cache_mngr_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+am__test_complex_HTB_with_hash_filters_SOURCES_DIST =  \
+       test-complex-HTB-with-hash-filters.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_complex_HTB_with_hash_filters_OBJECTS = test-complex-HTB-with-hash-filters.$(OBJEXT)
+test_complex_HTB_with_hash_filters_OBJECTS =  \
+       $(am_test_complex_HTB_with_hash_filters_OBJECTS)
+test_complex_HTB_with_hash_filters_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_complex_HTB_with_hash_filters_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+am__test_create_bond_SOURCES_DIST = test-create-bond.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_create_bond_OBJECTS =  \
+@ENABLE_UNIT_TESTS_TRUE@       test-create-bond.$(OBJEXT)
+test_create_bond_OBJECTS = $(am_test_create_bond_OBJECTS)
+test_create_bond_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_create_bond_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+am__test_create_vlan_SOURCES_DIST = test-create-vlan.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_create_vlan_OBJECTS =  \
+@ENABLE_UNIT_TESTS_TRUE@       test-create-vlan.$(OBJEXT)
+test_create_vlan_OBJECTS = $(am_test_create_vlan_OBJECTS)
+test_create_vlan_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_create_vlan_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+am__test_delete_link_SOURCES_DIST = test-delete-link.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_delete_link_OBJECTS =  \
+@ENABLE_UNIT_TESTS_TRUE@       test-delete-link.$(OBJEXT)
+test_delete_link_OBJECTS = $(am_test_delete_link_OBJECTS)
+test_delete_link_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_delete_link_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+am__test_genl_SOURCES_DIST = test-genl.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_genl_OBJECTS = test-genl.$(OBJEXT)
+test_genl_OBJECTS = $(am_test_genl_OBJECTS)
+test_genl_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_genl_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+am__test_nf_cache_mngr_SOURCES_DIST = test-nf-cache-mngr.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_nf_cache_mngr_OBJECTS =  \
+@ENABLE_UNIT_TESTS_TRUE@       test-nf-cache-mngr.$(OBJEXT)
+test_nf_cache_mngr_OBJECTS = $(am_test_nf_cache_mngr_OBJECTS)
+test_nf_cache_mngr_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_nf_cache_mngr_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+am__test_socket_creation_SOURCES_DIST = test-socket-creation.c
+@ENABLE_UNIT_TESTS_TRUE@am_test_socket_creation_OBJECTS =  \
+@ENABLE_UNIT_TESTS_TRUE@       test-socket-creation.$(OBJEXT)
+test_socket_creation_OBJECTS = $(am_test_socket_creation_OBJECTS)
+test_socket_creation_LDADD = $(LDADD)
+@ENABLE_UNIT_TESTS_TRUE@test_socket_creation_DEPENDENCIES =  \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       $(am__append_2)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(check_all_SOURCES) $(test_cache_mngr_SOURCES) \
+       $(test_complex_HTB_with_hash_filters_SOURCES) \
+       $(test_create_bond_SOURCES) $(test_create_vlan_SOURCES) \
+       $(test_delete_link_SOURCES) $(test_genl_SOURCES) \
+       $(test_nf_cache_mngr_SOURCES) $(test_socket_creation_SOURCES)
+DIST_SOURCES = $(am__check_all_SOURCES_DIST) \
+       $(am__test_cache_mngr_SOURCES_DIST) \
+       $(am__test_complex_HTB_with_hash_filters_SOURCES_DIST) \
+       $(am__test_create_bond_SOURCES_DIST) \
+       $(am__test_create_vlan_SOURCES_DIST) \
+       $(am__test_delete_link_SOURCES_DIST) \
+       $(am__test_genl_SOURCES_DIST) \
+       $(am__test_nf_cache_mngr_SOURCES_DIST) \
+       $(am__test_socket_creation_SOURCES_DIST)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ $(am__append_1)
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBNL_VERSION = @LIBNL_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_REVISION = @LT_REVISION@
+MAJ_VERSION = @MAJ_VERSION@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIC_VERSION = @MIC_VERSION@
+MIN_VERSION = @MIN_VERSION@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+YACC = @YACC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgconfigdir = @pkgconfigdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+       util.h
+
+@ENABLE_UNIT_TESTS_TRUE@AM_CPPFLAGS = -Wall -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
+@ENABLE_UNIT_TESTS_TRUE@LDADD = ${top_builddir}/lib/libnl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-nf-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-genl-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       ${top_builddir}/lib/libnl-route-3.la \
+@ENABLE_UNIT_TESTS_TRUE@       @CHECK_LIBS@ $(am__append_2)
+@ENABLE_UNIT_TESTS_TRUE@UNIT_TESTS = check-all
+@ENABLE_UNIT_TESTS_TRUE@test_cache_mngr_SOURCES = test-cache-mngr.c
+@ENABLE_UNIT_TESTS_TRUE@test_create_bond_SOURCES = test-create-bond.c
+@ENABLE_UNIT_TESTS_TRUE@test_create_vlan_SOURCES = test-create-vlan.c
+@ENABLE_UNIT_TESTS_TRUE@test_delete_link_SOURCES = test-delete-link.c
+@ENABLE_UNIT_TESTS_TRUE@test_genl_SOURCES = test-genl.c
+@ENABLE_UNIT_TESTS_TRUE@test_nf_cache_mngr_SOURCES = test-nf-cache-mngr.c
+@ENABLE_UNIT_TESTS_TRUE@test_socket_creation_SOURCES = test-socket-creation.c
+@ENABLE_UNIT_TESTS_TRUE@test_complex_HTB_with_hash_filters_SOURCES = test-complex-HTB-with-hash-filters.c
+
+# Unit tests
+@ENABLE_UNIT_TESTS_TRUE@check_all_SOURCES = \
+@ENABLE_UNIT_TESTS_TRUE@       check-all.c \
+@ENABLE_UNIT_TESTS_TRUE@       check-addr.c \
+@ENABLE_UNIT_TESTS_TRUE@       check-attr.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+       @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+check-all$(EXEEXT): $(check_all_OBJECTS) $(check_all_DEPENDENCIES) $(EXTRA_check_all_DEPENDENCIES) 
+       @rm -f check-all$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(check_all_OBJECTS) $(check_all_LDADD) $(LIBS)
+test-cache-mngr$(EXEEXT): $(test_cache_mngr_OBJECTS) $(test_cache_mngr_DEPENDENCIES) $(EXTRA_test_cache_mngr_DEPENDENCIES) 
+       @rm -f test-cache-mngr$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_cache_mngr_OBJECTS) $(test_cache_mngr_LDADD) $(LIBS)
+test-complex-HTB-with-hash-filters$(EXEEXT): $(test_complex_HTB_with_hash_filters_OBJECTS) $(test_complex_HTB_with_hash_filters_DEPENDENCIES) $(EXTRA_test_complex_HTB_with_hash_filters_DEPENDENCIES) 
+       @rm -f test-complex-HTB-with-hash-filters$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_complex_HTB_with_hash_filters_OBJECTS) $(test_complex_HTB_with_hash_filters_LDADD) $(LIBS)
+test-create-bond$(EXEEXT): $(test_create_bond_OBJECTS) $(test_create_bond_DEPENDENCIES) $(EXTRA_test_create_bond_DEPENDENCIES) 
+       @rm -f test-create-bond$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_create_bond_OBJECTS) $(test_create_bond_LDADD) $(LIBS)
+test-create-vlan$(EXEEXT): $(test_create_vlan_OBJECTS) $(test_create_vlan_DEPENDENCIES) $(EXTRA_test_create_vlan_DEPENDENCIES) 
+       @rm -f test-create-vlan$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_create_vlan_OBJECTS) $(test_create_vlan_LDADD) $(LIBS)
+test-delete-link$(EXEEXT): $(test_delete_link_OBJECTS) $(test_delete_link_DEPENDENCIES) $(EXTRA_test_delete_link_DEPENDENCIES) 
+       @rm -f test-delete-link$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_delete_link_OBJECTS) $(test_delete_link_LDADD) $(LIBS)
+test-genl$(EXEEXT): $(test_genl_OBJECTS) $(test_genl_DEPENDENCIES) $(EXTRA_test_genl_DEPENDENCIES) 
+       @rm -f test-genl$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_genl_OBJECTS) $(test_genl_LDADD) $(LIBS)
+test-nf-cache-mngr$(EXEEXT): $(test_nf_cache_mngr_OBJECTS) $(test_nf_cache_mngr_DEPENDENCIES) $(EXTRA_test_nf_cache_mngr_DEPENDENCIES) 
+       @rm -f test-nf-cache-mngr$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_nf_cache_mngr_OBJECTS) $(test_nf_cache_mngr_LDADD) $(LIBS)
+test-socket-creation$(EXEEXT): $(test_socket_creation_OBJECTS) $(test_socket_creation_DEPENDENCIES) $(EXTRA_test_socket_creation_DEPENDENCIES) 
+       @rm -f test-socket-creation$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(test_socket_creation_OBJECTS) $(test_socket_creation_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-addr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-all.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check-attr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-cache-mngr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-complex-HTB-with-hash-filters.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-create-bond.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-create-vlan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-delete-link.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-genl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nf-cache-mngr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-socket-creation.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+       @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+       srcdir=$(srcdir); export srcdir; \
+       list=' $(TESTS) '; \
+       $(am__tty_colors); \
+       if test -n "$$list"; then \
+         for tst in $$list; do \
+           if test -f ./$$tst; then dir=./; \
+           elif test -f $$tst; then dir=; \
+           else dir="$(srcdir)/"; fi; \
+           if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *[\ \     ]$$tst[\ \      ]*) \
+               xpass=`expr $$xpass + 1`; \
+               failed=`expr $$failed + 1`; \
+               col=$$red; res=XPASS; \
+             ;; \
+             *) \
+               col=$$grn; res=PASS; \
+             ;; \
+             esac; \
+           elif test $$? -ne 77; then \
+             all=`expr $$all + 1`; \
+             case " $(XFAIL_TESTS) " in \
+             *[\ \     ]$$tst[\ \      ]*) \
+               xfail=`expr $$xfail + 1`; \
+               col=$$lgn; res=XFAIL; \
+             ;; \
+             *) \
+               failed=`expr $$failed + 1`; \
+               col=$$red; res=FAIL; \
+             ;; \
+             esac; \
+           else \
+             skip=`expr $$skip + 1`; \
+             col=$$blu; res=SKIP; \
+           fi; \
+           echo "$${col}$$res$${std}: $$tst"; \
+         done; \
+         if test "$$all" -eq 1; then \
+           tests="test"; \
+           All=""; \
+         else \
+           tests="tests"; \
+           All="All "; \
+         fi; \
+         if test "$$failed" -eq 0; then \
+           if test "$$xfail" -eq 0; then \
+             banner="$$All$$all $$tests passed"; \
+           else \
+             if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+             banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+           fi; \
+         else \
+           if test "$$xpass" -eq 0; then \
+             banner="$$failed of $$all $$tests failed"; \
+           else \
+             if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+             banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+           fi; \
+         fi; \
+         dashes="$$banner"; \
+         skipped=""; \
+         if test "$$skip" -ne 0; then \
+           if test "$$skip" -eq 1; then \
+             skipped="($$skip test was not run)"; \
+           else \
+             skipped="($$skip tests were not run)"; \
+           fi; \
+           test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$skipped"; \
+         fi; \
+         report=""; \
+         if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+           report="Please report to $(PACKAGE_BUGREPORT)"; \
+           test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+             dashes="$$report"; \
+         fi; \
+         dashes=`echo "$$dashes" | sed s/./=/g`; \
+         if test "$$failed" -eq 0; then \
+           col="$$grn"; \
+         else \
+           col="$$red"; \
+         fi; \
+         echo "$${col}$$dashes$${std}"; \
+         echo "$${col}$$banner$${std}"; \
+         test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+         test -z "$$report" || echo "$${col}$$report$${std}"; \
+         echo "$${col}$$dashes$${std}"; \
+         test "$$failed" -eq 0; \
+       else :; fi
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+       $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+       $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+       clean-checkPROGRAMS clean-generic clean-libtool ctags \
+       distclean distclean-compile distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+       tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/check-addr.c b/tests/check-addr.c
new file mode 100644 (file)
index 0000000..39f3ede
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * tests/check-addr.c          nl_addr unit tests
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <check.h>
+#include <netlink/addr.h>
+
+START_TEST(addr_alloc)
+{
+       struct nl_addr *addr;
+
+       addr = nl_addr_alloc(16);
+       fail_if(addr == NULL,
+               "Allocation should not return NULL");
+
+       fail_if(nl_addr_iszero(addr) == 0,
+               "New empty address should be all zeros");
+
+       fail_if(nl_addr_get_family(addr) != AF_UNSPEC,
+               "New empty address should have family AF_UNSPEC");
+
+       fail_if(nl_addr_get_prefixlen(addr) != 0,
+               "New empty address should have prefix length 0");
+
+       fail_if(nl_addr_shared(addr),
+               "New empty address should not be shared");
+
+       fail_if(nl_addr_get(addr) != addr,
+               "nl_addr_get() should return pointer to address");
+
+       fail_if(nl_addr_shared(addr) == 0,
+               "Address should be shared after call to nl_addr_get()");
+
+       nl_addr_put(addr);
+
+       fail_if(nl_addr_shared(addr),
+               "Address should not be shared after call to nl_addr_put()");
+
+       fail_if(nl_addr_fill_sockaddr(addr, NULL, 0) == 0,
+               "Socket address filling should fail for empty address");
+
+       nl_addr_put(addr);
+}
+END_TEST
+
+START_TEST(addr_binary_addr)
+{
+       struct nl_addr *addr, *addr2;
+       char baddr[4] = { 0x1, 0x2, 0x3, 0x4 };
+       char baddr2[6] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 };
+
+       addr = nl_addr_alloc(4);
+       fail_if(addr == NULL,
+               "Allocation should not return NULL");
+
+       fail_if(nl_addr_set_binary_addr(addr, baddr, 4) < 0,
+               "Valid binary address should be settable");
+
+       fail_if(nl_addr_get_prefixlen(addr) != 0,
+               "Prefix length should be unchanged after nl_addr_set_binary_addr()");
+
+       fail_if(nl_addr_get_len(addr) != 4,
+               "Address length should be 4");
+
+       fail_if(nl_addr_set_binary_addr(addr, baddr2, 6) == 0,
+               "Should not be able to set binary address exceeding maximum length");
+
+       fail_if(nl_addr_get_len(addr) != 4,
+               "Address length should still be 4");
+
+       fail_if(nl_addr_guess_family(addr) != AF_INET,
+               "Binary address of length 4 should be guessed as AF_INET");
+
+       fail_if(memcmp(baddr, nl_addr_get_binary_addr(addr), 4) != 0,
+               "Binary address mismatches");
+
+       addr2 = nl_addr_build(AF_UNSPEC, baddr, 4);
+       fail_if(addr2 == NULL,
+               "Building of address should not fail");
+
+       nl_addr_set_prefixlen(addr, 32);
+       fail_if(nl_addr_get_prefixlen(addr) != 32,
+               "Prefix length should be successful changed after nl_addr_set_prefixlen()");
+
+       fail_if(nl_addr_cmp(addr, addr2),
+               "Addresses built from same binary address should match");
+
+       nl_addr_put(addr);
+       nl_addr_put(addr2);
+}
+END_TEST
+
+START_TEST(addr_parse4)
+{
+       struct nl_addr *addr4, *clone;
+       struct sockaddr_in sin;
+       socklen_t len = sizeof(sin);
+       char *addr_str = "10.0.0.1/16";
+       char buf[128];
+
+       fail_if(nl_addr_parse(addr_str, AF_INET6, &addr4) == 0,
+               "Should not be able to parse IPv4 address in IPv6 mode");
+
+       fail_if(nl_addr_parse(addr_str, AF_UNSPEC, &addr4) != 0,
+               "Should be able to parse \"%s\"", addr_str);
+
+       fail_if(nl_addr_get_family(addr4) != AF_INET,
+               "Address family should be AF_INET");
+
+       fail_if(nl_addr_get_prefixlen(addr4) != 16,
+               "Prefix length should be 16");
+
+       fail_if(nl_addr_iszero(addr4),
+               "Address should not be all zeroes");
+
+       clone = nl_addr_clone(addr4);
+       fail_if(clone == NULL,
+               "Cloned address should not be NULL");
+
+       fail_if(nl_addr_cmp(addr4, clone) != 0,
+               "Cloned address should not mismatch original");
+
+       fail_if(nl_addr_fill_sockaddr(addr4, (struct sockaddr *) &sin, &len) != 0,
+               "Should be able to fill socketaddr");
+
+       fail_if(strcmp(nl_addr2str(addr4, buf, sizeof(buf)), addr_str),
+               "Address translated back to string does not match original");
+
+       nl_addr_put(addr4);
+       nl_addr_put(clone);
+}
+END_TEST
+
+START_TEST(addr_parse6)
+{
+       struct nl_addr *addr6, *clone;
+       struct sockaddr_in6 sin;
+       socklen_t len = sizeof(sin);
+       char *addr_str = "2001:1:2::3/64";
+       char buf[128];
+
+       fail_if(nl_addr_parse(addr_str, AF_INET, &addr6) == 0,
+               "Should not be able to parse IPv6 address in IPv4 mode");
+
+       fail_if(nl_addr_parse(addr_str, AF_UNSPEC, &addr6) != 0,
+               "Should be able to parse \"%s\"", addr_str);
+
+       fail_if(nl_addr_get_family(addr6) != AF_INET6,
+               "Address family should be AF_INET6");
+
+       fail_if(nl_addr_get_prefixlen(addr6) != 64,
+               "Prefix length should be 64");
+
+       fail_if(nl_addr_iszero(addr6),
+               "Address should not be all zeroes");
+
+       clone = nl_addr_clone(addr6);
+       fail_if(clone == NULL,
+               "Cloned address should not be NULL");
+
+       fail_if(nl_addr_cmp(addr6, clone) != 0,
+               "Cloned address should not mismatch original");
+
+       fail_if(nl_addr_fill_sockaddr(addr6, (struct sockaddr *) &sin, &len) != 0,
+               "Should be able to fill socketaddr");
+
+       fail_if(strcmp(nl_addr2str(addr6, buf, sizeof(buf)), addr_str),
+               "Address translated back to string does not match original");
+
+       nl_addr_put(addr6);
+       nl_addr_put(clone);
+}
+END_TEST
+
+START_TEST(addr_info)
+{
+       struct nl_addr *addr;
+       char *addr_str = "127.0.0.1";
+       struct addrinfo *result;
+
+       fail_if(nl_addr_parse(addr_str, AF_UNSPEC, &addr) != 0,
+               "Parsing of valid address should not fail");
+
+       fail_if(nl_addr_info(addr, &result) != 0,
+               "getaddrinfo() on loopback address should work");
+
+       freeaddrinfo(result);
+       nl_addr_put(addr);
+}
+END_TEST
+
+Suite *make_nl_addr_suite(void)
+{
+       Suite *suite = suite_create("Abstract addresses");
+
+       TCase *tc_addr = tcase_create("Core");
+       tcase_add_test(tc_addr, addr_alloc);
+       tcase_add_test(tc_addr, addr_binary_addr);
+       tcase_add_test(tc_addr, addr_parse4);
+       tcase_add_test(tc_addr, addr_parse6);
+       tcase_add_test(tc_addr, addr_info);
+       suite_add_tcase(suite, tc_addr);
+
+       return suite;
+}
diff --git a/tests/check-all.c b/tests/check-all.c
new file mode 100644 (file)
index 0000000..e431802
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * tests/check-all.c           overall unit test program
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <check.h>
+
+extern Suite *make_nl_addr_suite(void);
+extern Suite *make_nl_attr_suite(void);
+
+static Suite *main_suite(void)
+{
+       Suite *suite = suite_create("main");
+
+       return suite;
+}
+
+int main(int argc, char *argv[])
+{
+       SRunner *runner;
+       int nfailed;
+       
+       runner = srunner_create(main_suite());
+
+       /* Add testsuites below */
+
+       srunner_add_suite(runner, make_nl_addr_suite());
+       srunner_add_suite(runner, make_nl_attr_suite());
+
+       /* Do not add testsuites below this line */
+
+       srunner_run_all(runner, CK_ENV);
+
+       nfailed = srunner_ntests_failed(runner);
+       srunner_free(runner);
+
+       return nfailed != 0;
+}
diff --git a/tests/check-attr.c b/tests/check-attr.c
new file mode 100644 (file)
index 0000000..d862230
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * tests/check-attr.c          nla_attr unit tests
+ *
+ *     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) 2013 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include "util.h"
+#include <netlink/attr.h>
+#include <netlink/msg.h>
+
+START_TEST(attr_size)
+{
+       fail_if(nla_attr_size(0) != NLA_HDRLEN,
+               "Length of empty attribute should match header size");
+       fail_if(nla_attr_size(1) != NLA_HDRLEN + 1,
+               "Length of 1 bytes payload should be NLA_HDRLEN + 1");
+       fail_if(nla_attr_size(2) != NLA_HDRLEN + 2,
+               "Length of 2 bytes payload should be NLA_HDRLEN + 2");
+       fail_if(nla_attr_size(3) != NLA_HDRLEN + 3,
+               "Length of 3 bytes payload should be NLA_HDRLEN + 3");
+       fail_if(nla_attr_size(4) != NLA_HDRLEN + 4,
+               "Length of 4 bytes payload should be NLA_HDRLEN + 4");
+
+       fail_if(nla_total_size(1) != NLA_HDRLEN + 4,
+               "Total size of 1 bytes payload should result in 8 bytes");
+       fail_if(nla_total_size(2) != NLA_HDRLEN + 4,
+               "Total size of 2 bytes payload should result in 8 bytes");
+       fail_if(nla_total_size(3) != NLA_HDRLEN + 4,
+               "Total size of 3 bytes payload should result in 8 bytes");
+       fail_if(nla_total_size(4) != NLA_HDRLEN + 4,
+               "Total size of 4 bytes payload should result in 8 bytes");
+
+       fail_if(nla_padlen(1) != 3,
+               "2 bytes of payload should result in 3 padding bytes");
+       fail_if(nla_padlen(2) != 2,
+               "2 bytes of payload should result in 2 padding bytes");
+       fail_if(nla_padlen(3) != 1,
+               "3 bytes of payload should result in 1 padding bytes");
+       fail_if(nla_padlen(4) != 0,
+               "4 bytes of payload should result in 0 padding bytes");
+       fail_if(nla_padlen(5) != 3,
+               "5 bytes of payload should result in 3 padding bytes");
+}
+END_TEST
+
+START_TEST(msg_construct)
+{
+       struct nl_msg *msg;
+       struct nlmsghdr *nlh;
+       struct nlattr *a;
+       int i, rem;
+
+       msg = nlmsg_alloc();
+       fail_if(!msg, "Unable to allocate netlink message");
+
+       for (i = 1; i < 256; i++) {
+               fail_if(nla_put_u32(msg, i, i+1) != 0,
+                       "Unable to add attribute %d", i);
+       }
+
+       nlh = nlmsg_hdr(msg);
+       i = 1;
+       nlmsg_for_each_attr(a, nlh, 0, rem) {
+               fail_if(nla_type(a) != i, "Expected attribute %d", i);
+               i++;
+               fail_if(nla_get_u32(a) != i, "Expected attribute value %d", i);
+       }
+
+       nlmsg_free(msg);
+}
+END_TEST
+
+Suite *make_nl_attr_suite(void)
+{
+       Suite *suite = suite_create("Netlink attributes");
+
+       TCase *nl_attr = tcase_create("Core");
+       tcase_add_test(nl_attr, attr_size);
+       tcase_add_test(nl_attr, msg_construct);
+       suite_add_tcase(suite, nl_attr);
+
+       return suite;
+}
diff --git a/tests/test-cache-mngr.c b/tests/test-cache-mngr.c
new file mode 100644 (file)
index 0000000..8999e58
--- /dev/null
@@ -0,0 +1,66 @@
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/cli/utils.h>
+#include <signal.h>
+
+#include <netlink-private/cache-api.h>
+
+static int quit = 0;
+
+static struct nl_dump_params dp = {
+       .dp_type = NL_DUMP_LINE,
+};
+
+
+static void change_cb(struct nl_cache *cache, struct nl_object *obj,
+                     int action, void *data)
+{
+       if (action == NL_ACT_NEW)
+               printf("NEW ");
+       else if (action == NL_ACT_DEL)
+               printf("DEL ");
+       else if (action == NL_ACT_CHANGE)
+               printf("CHANGE ");
+
+       nl_object_dump(obj, &dp);
+}
+
+static void sigint(int arg)
+{
+       quit = 1;
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_cache_mngr *mngr;
+       struct nl_cache *cache;
+       int err, i;
+
+       dp.dp_fd = stdout;
+
+       signal(SIGINT, sigint);
+
+       err = nl_cache_mngr_alloc(NULL, NETLINK_ROUTE, NL_AUTO_PROVIDE, &mngr);
+       if (err < 0)
+               nl_cli_fatal(err, "Unable to allocate cache manager: %s",
+                            nl_geterror(err));
+
+       for (i = 1; i < argc; i++) {
+               err = nl_cache_mngr_add(mngr, argv[i], &change_cb, NULL, &cache);
+               if (err < 0)
+                       nl_cli_fatal(err, "Unable to add cache %s: %s",
+                                    argv[i], nl_geterror(err));
+       }
+
+       while (!quit) {
+               int err = nl_cache_mngr_poll(mngr, 1000);
+               if (err < 0 && err != -NLE_INTR)
+                       nl_cli_fatal(err, "Polling failed: %s", nl_geterror(err));
+
+               nl_cache_mngr_info(mngr, &dp);
+       }
+
+       nl_cache_mngr_free(mngr);
+
+       return 0;
+}
diff --git a/tests/test-complex-HTB-with-hash-filters.c b/tests/test-complex-HTB-with-hash-filters.c
new file mode 100644 (file)
index 0000000..48cf5e3
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * test/test-complex-HTB-with-hash-filters.c     Add HTB qdisc, HTB classes and creates some hash filters
+ *
+ *      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) 2011 Adrian Ban <adrian.ban@mantech.ro>
+ */
+
+#include <netlink/route/link.h>
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/htb.h>
+#include <netlink/route/qdisc/sfq.h>
+#include <netlink/route/cls/u32.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/class.h>
+#include <linux/if_ether.h>
+
+#include <netlink/attr.h>
+//#include "include/rtnl_u32.h"
+
+#include <stdio.h>
+#include <string.h>
+//#include "include/rtnl_u32_addon.h"
+
+#define        TC_HANDLE(maj, min)   (TC_H_MAJ((maj) << 16) | TC_H_MIN(min))
+
+/* some functions are copied from iproute-tc tool */
+int get_u32(__u32 *val, const char *arg, int base)
+{
+       unsigned long res;
+       char *ptr;
+
+       if (!arg || !*arg)
+               return -1;
+       res = strtoul(arg, &ptr, base);
+       if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
+               return -1;
+       *val = res;
+       return 0;
+}
+
+int get_u32_handle(__u32 *handle, const char *str)
+{
+       __u32 htid=0, hash=0, nodeid=0;
+       char *tmp = strchr(str, ':');
+        
+       if (tmp == NULL) {
+               if (memcmp("0x", str, 2) == 0)
+                       return get_u32(handle, str, 16);
+               return -1;
+       }
+       htid = strtoul(str, &tmp, 16);
+       if (tmp == str && *str != ':' && *str != 0)
+               return -1;
+       if (htid>=0x1000)
+               return -1;
+       if (*tmp) {
+               str = tmp+1;
+               hash = strtoul(str, &tmp, 16);
+               if (tmp == str && *str != ':' && *str != 0)
+                       return -1;
+               if (hash>=0x100)
+                       return -1;
+               if (*tmp) {
+                       str = tmp+1;
+                       nodeid = strtoul(str, &tmp, 16);
+                       if (tmp == str && *str != 0)
+                               return -1;
+                       if (nodeid>=0x1000)
+                               return -1;
+               }
+       }
+       *handle = (htid<<20)|(hash<<12)|nodeid;
+       return 0;
+}
+
+uint32_t get_u32_parse_handle(const char *cHandle)
+{
+       uint32_t handle=0;
+
+       if(get_u32_handle(&handle, cHandle)) {
+               printf ("Illegal \"ht\"\n");
+               return -1;
+       }
+
+       if (handle && TC_U32_NODE(handle)) {
+               printf("\"link\" must be a hash table.\n");
+               return -1;
+       }
+       return handle;
+}
+
+int get_tc_classid(__u32 *h, const char *str)
+{
+       __u32 maj, min;
+       char *p;
+
+       maj = TC_H_ROOT;
+       if (strcmp(str, "root") == 0)
+               goto ok;
+       maj = TC_H_UNSPEC;
+       if (strcmp(str, "none") == 0)
+               goto ok;
+       maj = strtoul(str, &p, 16);
+       if (p == str) {
+               maj = 0;
+               if (*p != ':')
+                       return -1;
+       }
+       if (*p == ':') {
+               if (maj >= (1<<16))
+                       return -1;
+               maj <<= 16;
+               str = p+1;
+               min = strtoul(str, &p, 16);
+               if (*p != 0)
+                       return -1;
+               if (min >= (1<<16))
+                       return -1;
+               maj |= min;
+       } else if (*p != 0)
+               return -1;
+
+ok:
+       *h = maj;
+       return 0;
+}
+
+/* 
+ * Function that adds a new filter and attach it to a hash table
+ *
+ */
+int u32_add_filter_on_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, 
+               uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
+               uint32_t htid, uint32_t classid
+)
+{
+    struct rtnl_cls *cls;
+    int err;
+
+    //printf("Key Val  : 0x%x\n", keyval);
+    //printf("Key Mask : 0x%x\n", keymask);
+
+    cls=rtnl_cls_alloc();
+    if (!(cls)) {
+        printf("Can not allocate classifier\n");
+        nl_socket_free(sock);
+        exit(1);
+    }
+    
+    rtnl_tc_set_link(TC_CAST(cls), rtnlLink);
+
+    if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
+        printf("Can not set classifier as u32\n");
+        return 1;
+    }
+
+    rtnl_cls_set_prio(cls, prio);
+    rtnl_cls_set_protocol(cls, ETH_P_IP);
+
+    rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(1, 0));
+
+    rtnl_u32_set_hashtable(cls, htid);
+
+    rtnl_u32_add_key_uint32(cls, keyval, keymask, keyoff, keyoffmask); /* 10.0.0.0/8 */
+
+    rtnl_u32_set_classid(cls, classid);
+    
+    rtnl_u32_set_cls_terminal(cls);
+
+    if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
+        printf("Can not add classifier: %s\n", nl_geterror(err));
+        return -1;
+    }
+    rtnl_cls_put(cls);
+    return 0;
+
+}
+
+/* 
+ * Function that adds a new filter and attach it to a hash table 
+ * and set next hash table link with hash mask
+ *
+ */
+int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, 
+           uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
+           uint32_t htid, uint32_t htlink, uint32_t hmask, uint32_t hoffset
+)
+{
+    struct rtnl_cls *cls;
+    int err;
+
+    //printf("Key Val  : 0x%x\n", keyval);
+    //printf("Key Mask : 0x%x\n", keymask);
+
+    cls=rtnl_cls_alloc();
+    if (!(cls)) {
+        printf("Can not allocate classifier\n");
+        nl_socket_free(sock);
+        exit(1);
+    }
+    
+    rtnl_tc_set_link(TC_CAST(cls), rtnlLink);
+
+    if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
+        printf("Can not set classifier as u32\n");
+        return 1;
+    }
+
+    rtnl_cls_set_prio(cls, prio);
+    rtnl_cls_set_protocol(cls, ETH_P_IP);
+
+    rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(1, 0));
+    
+    if (htid)
+       rtnl_u32_set_hashtable(cls, htid);
+
+    rtnl_u32_add_key_uint32(cls, keyval, keymask, keyoff, keyoffmask);
+
+    rtnl_u32_set_hashmask(cls, hmask, hoffset);
+
+    rtnl_u32_set_link(cls, htlink);
+
+
+    if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
+        printf("Can not add classifier: %s\n", nl_geterror(err));
+        return -1;
+    }
+    rtnl_cls_put(cls);
+    return 0;
+}
+
+/* 
+ * function that creates a new hash table 
+ */
+int u32_add_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, uint32_t htid, uint32_t divisor)
+{
+
+    int err;
+    struct rtnl_cls *cls;
+
+    cls=rtnl_cls_alloc();
+    if (!(cls)) {
+        printf("Can not allocate classifier\n");
+        nl_socket_free(sock);
+        exit(1);
+    }
+    
+    rtnl_tc_set_link(TC_CAST(cls), rtnlLink);
+
+    if ((err = rtnl_tc_set_kind(TC_CAST(cls), "u32"))) {
+        printf("Can not set classifier as u32\n");
+        return 1;
+    }
+
+    rtnl_cls_set_prio(cls, prio);
+    rtnl_cls_set_protocol(cls, ETH_P_IP);
+    rtnl_tc_set_parent(TC_CAST(cls), TC_HANDLE(1, 0));
+
+    rtnl_u32_set_handle(cls, htid, 0x0, 0x0);
+    //printf("htid: 0x%X\n", htid);
+    rtnl_u32_set_divisor(cls, divisor);
+
+    if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
+        printf("Can not add classifier: %s\n", nl_geterror(err));
+        return -1;
+    }
+    rtnl_cls_put(cls);
+    return 0;
+}
+
+/*
+ * function that adds a new HTB qdisc and set the default class for unclassified traffic
+ */
+int qdisc_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t defaultClass)
+{
+    
+    struct rtnl_qdisc *qdisc;
+    int err;
+    
+    /* Allocation of a qdisc object */
+    if (!(qdisc = rtnl_qdisc_alloc())) {
+        printf("Can not allocate Qdisc\n");
+       return -1;
+    }
+
+    //rtnl_tc_set_ifindex(TC_CAST(qdisc), master_index);
+    rtnl_tc_set_link(TC_CAST(qdisc), rtnlLink);
+    rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT);
+
+    //delete the qdisc
+    //printf("Delete current qdisc\n");
+    rtnl_qdisc_delete(sock, qdisc);
+    //rtnl_qdisc_put(qdisc);
+
+    //add a HTB qdisc
+    //printf("Add a new HTB qdisc\n");
+    rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(1,0));
+
+    if ((err = rtnl_tc_set_kind(TC_CAST(qdisc), "htb"))) {
+        printf("Can not allocate HTB\n");
+       return -1;
+    }
+
+    /* Set default class for unclassified traffic */
+    //printf("Set default class for unclassified traffic\n");
+    rtnl_htb_set_defcls(qdisc, TC_HANDLE(1, defaultClass));
+    rtnl_htb_set_rate2quantum(qdisc, 1);
+
+    /* Submit request to kernel and wait for response */
+    if ((err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE))) {
+        printf("Can not allocate HTB Qdisc\n");
+       return -1;
+    }
+
+    /* Return the qdisc object to free memory resources */
+    rtnl_qdisc_put(qdisc);
+
+    return 0;
+}
+
+/*
+ * function that adds a new HTB class and set its parameters
+ */
+int class_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink, 
+                   uint32_t parentMaj, uint32_t parentMin,
+                   uint32_t childMaj,  uint32_t childMin, 
+                   uint64_t rate, uint64_t ceil,
+                   uint32_t burst, uint32_t cburst, 
+                   uint32_t prio
+)
+{
+    int err;
+    struct rtnl_class *class;
+    //struct rtnl_class *class = (struct rtnl_class *) tc;
+
+    //create a HTB class 
+    //class = (struct rtnl_class *)rtnl_class_alloc();
+    if (!(class = rtnl_class_alloc())) {
+        printf("Can not allocate class object\n");
+        return 1;
+    }
+    //
+    rtnl_tc_set_link(TC_CAST(class), rtnlLink);
+    //add a HTB qdisc
+    //printf("Add a new HTB class with 0x%X:0x%X on parent 0x%X:0x%X\n", childMaj, childMin, parentMaj, parentMin);
+    rtnl_tc_set_parent(TC_CAST(class), TC_HANDLE(parentMaj, parentMin));
+    rtnl_tc_set_handle(TC_CAST(class), TC_HANDLE(childMaj, childMin));
+
+    if ((err = rtnl_tc_set_kind(TC_CAST(class), "htb"))) {
+        printf("Can not set HTB to class\n");
+        return 1;
+    }
+
+    //printf("set HTB class prio to %u\n", prio);
+    rtnl_htb_set_prio((struct rtnl_class *)class, prio);
+
+    if (rate) {
+       //rate=rate/8;
+       rtnl_htb_set_rate(class, rate);
+    }
+    if (ceil) {
+       //ceil=ceil/8;
+       rtnl_htb_set_ceil(class, ceil);
+    }
+    
+    if (burst) {
+       //printf ("Class HTB: set rate burst: %u\n", burst);
+        rtnl_htb_set_rbuffer(class, burst);
+    }
+    if (cburst) {
+       //printf ("Class HTB: set rate cburst: %u\n", cburst);
+        rtnl_htb_set_cbuffer(class, cburst);
+    }
+    /* Submit request to kernel and wait for response */
+    if ((err = rtnl_class_add(sock, class, NLM_F_CREATE))) {
+        printf("Can not allocate HTB Qdisc\n");
+        return 1;
+    }
+    rtnl_class_put(class);
+    return 0;
+}
+
+/*
+ * function that adds a HTB root class and set its parameters
+ */
+int class_add_HTB_root(struct nl_sock *sock, struct rtnl_link *rtnlLink, 
+                       uint64_t rate, uint64_t ceil,
+                       uint32_t burst, uint32_t cburst
+)
+{
+    int err;
+    struct rtnl_class *class;
+
+    //create a HTB class 
+    class = (struct rtnl_class *)rtnl_class_alloc();
+    //class = rtnl_class_alloc();
+    if (!class) {
+        printf("Can not allocate class object\n");
+        return 1;
+    }
+    //
+    rtnl_tc_set_link(TC_CAST(class), rtnlLink);
+    rtnl_tc_set_parent(TC_CAST(class), TC_H_ROOT);
+    //add a HTB class
+    //printf("Add a new HTB ROOT class\n");
+    rtnl_tc_set_handle(TC_CAST(class), 1);
+
+    if ((err = rtnl_tc_set_kind(TC_CAST(class), "htb"))) {
+        printf("Can not set HTB to class\n");
+        return 1;
+    }
+
+    if (rate) {
+       //rate=rate/8;
+       rtnl_htb_set_rate(class, rate);
+    }
+    if (ceil) {
+       //ceil=ceil/8;
+       rtnl_htb_set_ceil(class, ceil);
+    }
+    
+    if (burst) {
+        rtnl_htb_set_rbuffer(class, burst);
+    }
+    if (cburst) {
+        rtnl_htb_set_cbuffer(class, cburst);
+    }
+    
+    /* Submit request to kernel and wait for response */
+    if ((err = rtnl_class_add(sock, class, NLM_F_CREATE))) {
+        printf("Can not allocate HTB Qdisc\n");
+        return 1;
+    }
+    rtnl_class_put(class);
+    return 0;
+}
+
+/*
+ * function that adds a new SFQ qdisc as a leaf for a HTB class
+ */
+int qdisc_add_SFQ_leaf(struct nl_sock *sock, struct rtnl_link *rtnlLink,
+                       uint32_t parentMaj, uint32_t parentMin, 
+                       int quantum, int limit, int perturb
+)
+{
+    int err;
+    struct rtnl_qdisc *qdisc;
+
+    if (!(qdisc = rtnl_qdisc_alloc())) {
+        printf("Can not allocate qdisc object\n");
+        return 1;
+    }
+    rtnl_tc_set_link(TC_CAST(qdisc), rtnlLink);
+    rtnl_tc_set_parent(TC_CAST(qdisc), TC_HANDLE(parentMaj, parentMin));
+
+    rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(parentMin,0));
+
+    if ((err = rtnl_tc_set_kind(TC_CAST(qdisc), "sfq"))) {
+        printf("Can not set SQF class\n");
+        return 1;
+    }
+
+    if(quantum) {
+        rtnl_sfq_set_quantum(qdisc, quantum);
+    } else {
+        rtnl_sfq_set_quantum(qdisc, 16000); // tc default value
+    }
+    if(limit) {
+        rtnl_sfq_set_limit(qdisc, limit); // default is 127
+    }
+    if(perturb) {
+        rtnl_sfq_set_perturb(qdisc, perturb); // default never perturb the hash
+    }
+
+    /* Submit request to kernel and wait for response */
+    if ((err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE))) {
+        printf("Can not allocate SFQ qdisc\n");
+       return -1;
+    }
+
+    /* Return the qdisc object to free memory resources */
+    rtnl_qdisc_put(qdisc);
+    return 0;
+}
+
+
+
+
+int main() {
+    
+    struct nl_sock *sock;
+    struct rtnl_link *link;
+
+    //struct rtnl_qdisc *qdisc;
+    //struct rtnl_class *class;
+    //struct rtnl_cls   *cls;
+
+    uint32_t ht, htlink, htid, direction, classid;
+    //uint32_t hash, hashmask, nodeid, divisor, handle;
+    //struct rtnl_u32 *f_u32;
+    char chashlink[16]="";
+
+    //uint64_t drops, qlen;
+
+    //int master_index;
+    int err;
+    
+    //uint64_t rate=0, ceil=0;
+
+    struct nl_cache *link_cache;
+    
+    if (!(sock = nl_socket_alloc())) {
+        printf("Unable to allocate netlink socket\n");
+        exit(1);
+    }
+
+    if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0 ) {
+        printf("Nu s-a putut conecta la NETLINK!\n");
+        nl_socket_free(sock);
+        exit(1);
+    }
+
+    
+    if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) {
+        printf("Unable to allocate link cache: %s\n",
+                             nl_geterror(err));
+        nl_socket_free(sock);
+        exit(1);
+    }
+    
+    /* lookup interface index of eth0 */
+    if (!(link = rtnl_link_get_by_name(link_cache, "imq0"))) {
+        /* error */
+        printf("Interface not found\n");
+        nl_socket_free(sock);
+        exit(1);
+    }
+    
+    err=qdisc_add_HTB(sock, link, 0xffff);
+    //drops = rtnl_tc_get_stat(TC_CAST(qdisc), RTNL_TC_DROPS);
+    
+    //printf("Add ROOT HTB class\n");
+    err=class_add_HTB_root(sock, link, 12500000, 12500000, 25000, 25000);
+    err=class_add_HTB(sock, link, 1, 0, 1, 0xffff, 1250000, 12500000, 25000, 25000, 5);
+    err=qdisc_add_SFQ_leaf(sock, link, 1, 0xffff, 16000, 0, 10);
+    err=class_add_HTB(sock, link, 1, 1, 1, 0x5, 2000000, 2000000, 25000, 25000, 5);
+    err=qdisc_add_SFQ_leaf(sock, link, 1, 0x5, 16000, 0, 10);
+    err=class_add_HTB(sock, link, 1, 1, 1, 0x6, 1000000, 1000000, 25000, 25000, 5);
+    err=qdisc_add_SFQ_leaf(sock, link, 1, 0x6, 16000, 0, 10);
+    //err=class_add_HTB(sock, link, 1, 0, 1, 0x7, 1024000, 100000000, 5);
+    //err=class_add_HTB(sock, link, 1, 0, 1, 0x8, 2048000, 100000000, 5);
+    //err=class_add_HTB(sock, link, 1, 0, 1, 0x9, 4096000, 100000000, 5);
+    //err=class_add_HTB(sock, link, 1, 0, 1, 0xa, 8192000, 100000000, 5);
+
+    //printf("Add main hash table\n");
+
+    /* create u32 first hash filter table
+     *
+     */
+    /* formula calcul handle:
+    *         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
+    */
+
+    /*
+     * Upper limit of number of hash tables: 4096 (0xFFF)
+     * Number of hashes in a table: 256 values (0xFF)
+     *
+     */
+
+    /* using 256 values for hash table 
+     * each entry in hash table match a byte from IP address specified later by a hash key
+     */
+
+    uint32_t i;
+    for (i = 1; i <= 0xf; i++) 
+       u32_add_ht(sock, link, 1, i, 256);
+
+    /* 
+     * attach a u32 filter to the first hash 
+     * that redirects all traffic and make a hash key
+     * from the fist byte of the IP address
+     *
+     */
+
+    //divisor=0x0;     // unused here
+    //handle = 0x0;    // unused here
+    //hash = 0x0;              // unused here
+    //htid = 0x0;              // unused here
+    //nodeid = 0x0;    // unused here
+
+    // direction = 12 -> source IP
+    // direction = 16 -> destination IP
+    direction = 16;
+
+    /*
+     * which hash table will use
+     * in our case is hash table no 1 defined previous
+     *
+     * There are 2 posibilities to set the the hash table:
+     * 1. Using function get_u32_handle and sent a string in
+     *  format 10: where 10 is number of the hash table
+     * 2. Create your own value in format: 0xa00000
+     *
+     */
+    strcpy(chashlink, "1:");
+    //printf("Hash Link: %s\n", chashlink);
+    //chashlink=malloc(sizeof(char) *
+    htlink = 0x0;              // is used by get_u32_handle to return the correct value of hash table (link)
+    
+    if(get_u32_handle(&htlink, chashlink)) {
+        printf ("Illegal \"link\"");
+        nl_socket_free(sock);
+        exit(1);
+    }
+    //printf ("hash link : 0x%X\n", htlink);
+    //printf ("hash link test : %u\n", (htlink && TC_U32_NODE(htlink)));
+
+    if (htlink && TC_U32_NODE(htlink)) {
+       printf("\"link\" must be a hash table.\n");
+        nl_socket_free(sock);
+        exit(1);
+    }
+    /* the hash mask will hit the hash table (link) no 1: in our case
+     */
+
+    /* set the hash key mask */
+    //hashmask = 0xFF000000UL; // the mask that is used to match the hash in specific table, in our case for example 1:a with mean the first byte which is 10 in hash table 1
+
+    /* Here we add a hash filter which match the first byte (see the hashmask value)
+     * of the source IP (offset 12 in the packet header)
+     * You can use also offset 16 to match the destination IP
+     */
+
+    /*
+     * Also we need a filter to match our rule
+     * This mean that we will put a 0.0.0.0/0 filter in our first rule
+     * that match the offset 12 (source IP)
+     * Also you can put offset 16 to match the destination IP
+     */
+
+    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
+           0x0, 0x0, direction, 0,
+           0, htlink, 0xff000000, direction);
+
+    /*
+     * For each first byte that we need to match we will create a new hash table
+     * For example: you have those clases: 10.0.0.0/24 and 172.16.0.0/23
+     * For byte 10 and byte 172 will create a separate hash table that will match the second
+     * byte from each class.
+     *
+     */
+
+    
+    // Create a new hash table with prio 1, id 2 and 256 entries
+//    u32_CreateNewHashTable(sock, link, 1, 2, 256);
+    // Create a new hash table with prio 1, id 3 and 256 entries
+//    u32_CreateNewHashTable(sock, link, 1, 3, 256);
+//    u32_CreateNewHashTable(sock, link, 1, 4, 256);
+//    u32_CreateNewHashTable(sock, link, 1, 5, 256);
+
+    /*
+     * Now we will create other filter under (ATENTION) our first hash table (link) 1:
+     * Previous rule redirects the trafic according the hash mask to hash table (link) no 1:
+     * Here we will match the hash tables from 1:0 to 1:ff. Under each hash table we will attach 
+     * other rules that matches next byte from IP source/destination IP and we will repeat the 
+     * previous steps.
+     *
+     */
+    
+
+    // /8 check
+
+    // 10.0.0.0/8
+    ht=get_u32_parse_handle("1:a:");
+    htid = (ht&0xFFFFF000);
+    htlink=get_u32_parse_handle("2:");
+
+    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
+           0x0a000000, 0xff000000, direction, 0,
+           htid, htlink, 0x00ff0000, direction);
+
+    // 172.0.0.0/8
+    ht=get_u32_parse_handle("1:ac:");
+    htid = (ht&0xFFFFF000);
+    htlink=get_u32_parse_handle("3:");
+
+    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
+           0xac000000, 0xff000000, direction, 0,
+           htid, htlink, 0x00ff0000, direction);
+
+
+    // /16 check
+    // 10.0.0.0/16
+    ht=get_u32_parse_handle("2:0:");
+    htid = (ht&0xFFFFF000);
+    htlink=get_u32_parse_handle("4:");
+
+    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
+           0x0a000000, 0xffff0000, direction, 0,
+           htid, htlink, 0x0000ff00, direction);
+
+    // 172.17.0.0/16
+    ht=get_u32_parse_handle("3:11:");
+    htid = (ht&0xFFFFF000);
+    htlink=get_u32_parse_handle("5:");
+
+    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
+           0xac110000, 0xffff0000, direction, 0,
+           htid, htlink, 0x0000ff00, direction);
+
+    // /24 check
+    // 10.0.9.0/24
+    ht=get_u32_parse_handle("4:9:");
+    htid = (ht&0xFFFFF000);
+    htlink=get_u32_parse_handle("6:");
+
+    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
+           0x0a000900, 0xffffff00, direction, 0,
+           htid, htlink, 0x000000ff, direction);
+    
+    // 172.17.2.0/16
+    ht=get_u32_parse_handle("5:2:");
+    htid = (ht&0xFFFFF000);
+    htlink=get_u32_parse_handle("7:");
+
+    u32_add_filter_on_ht_with_hashmask(sock, link, 1, 
+           0xac110200, 0xffffff00, direction, 0,
+           htid, htlink, 0x000000ff, direction);
+
+
+    // final filters
+    // 10.0.9.20
+    ht=get_u32_parse_handle("6:14:");
+    htid = (ht&0xFFFFF000);
+
+    err = get_tc_classid(&classid, "1:5");
+
+    u32_add_filter_on_ht(sock, link, 1, 
+           0x0a000914, 0xffffffff, direction, 0,
+           htid, classid);
+
+    // 172.17.2.120
+    ht=get_u32_parse_handle("7:78:");
+    htid = (ht&0xFFFFF000);
+
+    err = get_tc_classid(&classid, "1:6");
+
+    u32_add_filter_on_ht(sock, link, 1, 
+           0xac110278, 0xffffffff, direction, 0,
+           htid, classid);
+
+    
+
+    nl_socket_free(sock);
+    return 0;
+}
diff --git a/tests/test-create-bond.c b/tests/test-create-bond.c
new file mode 100644 (file)
index 0000000..11bc5b0
--- /dev/null
@@ -0,0 +1,29 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/bonding.h>
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_link *link;
+       struct nl_sock *sk;
+       int err;
+
+       sk = nl_socket_alloc();
+       if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+               nl_perror(err, "Unable to connect socket");
+               return err;
+       }
+
+       link = rtnl_link_bond_alloc();
+       rtnl_link_set_name(link, "my_bond");
+
+       if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+               nl_perror(err, "Unable to add link");
+               return err;
+       }
+
+       rtnl_link_put(link);
+       nl_close(sk);
+
+       return 0;
+}
diff --git a/tests/test-create-vlan.c b/tests/test-create-vlan.c
new file mode 100644 (file)
index 0000000..64e478f
--- /dev/null
@@ -0,0 +1,43 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_link *link;
+       struct nl_cache *link_cache;
+       struct nl_sock *sk;
+       int err, master_index;
+
+       sk = nl_socket_alloc();
+       if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+               nl_perror(err, "Unable to connect socket");
+               return err;
+       }
+
+       if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
+               nl_perror(err, "Unable to allocate cache");
+               return err;
+       }
+
+       if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) {
+               fprintf(stderr, "Unable to lookup eth0");
+               return -1;
+       }
+
+       link = rtnl_link_vlan_alloc();
+
+       rtnl_link_set_link(link, master_index);
+
+       rtnl_link_vlan_set_id(link, 10);
+
+       if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+               nl_perror(err, "Unable to add link");
+               return err;
+       }
+
+       rtnl_link_put(link);
+       nl_close(sk);
+
+       return 0;
+}
diff --git a/tests/test-delete-link.c b/tests/test-delete-link.c
new file mode 100644 (file)
index 0000000..9cf1034
--- /dev/null
@@ -0,0 +1,28 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+int main(int argc, char *argv[])
+{
+       struct rtnl_link *link;
+       struct nl_sock *sk;
+       int err;
+
+       sk = nl_socket_alloc();
+       if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+               nl_perror(err, "Unable to connect socket");
+               return err;
+       }
+
+       link = rtnl_link_alloc();
+       rtnl_link_set_name(link, "my_bond");
+
+       if ((err = rtnl_link_delete(sk, link)) < 0) {
+               nl_perror(err, "Unable to delete link");
+               return err;
+       }
+
+       rtnl_link_put(link);
+       nl_close(sk);
+
+       return 0;
+}
diff --git a/tests/test-genl.c b/tests/test-genl.c
new file mode 100644 (file)
index 0000000..74aea10
--- /dev/null
@@ -0,0 +1,118 @@
+#include <netlink/cli/utils.h>
+#include <linux/taskstats.h>
+
+static struct nla_policy attr_policy[TASKSTATS_TYPE_MAX+1] = {
+       [TASKSTATS_TYPE_PID]    = { .type = NLA_U32 },
+       [TASKSTATS_TYPE_TGID]   = { .type = NLA_U32 },
+       [TASKSTATS_TYPE_STATS]  = { .minlen = sizeof(struct taskstats) },
+       [TASKSTATS_TYPE_AGGR_PID] = { .type = NLA_NESTED },
+       [TASKSTATS_TYPE_AGGR_TGID] = { .type = NLA_NESTED },
+};
+
+
+static int parse_cmd_new(struct nl_cache_ops *unused, struct genl_cmd *cmd,
+                        struct genl_info *info, void *arg)
+{
+       struct nlattr *attrs[TASKSTATS_TYPE_MAX+1];
+       struct nlattr *nested;
+       int err;
+
+       if (info->attrs[TASKSTATS_TYPE_AGGR_PID])
+               nested = info->attrs[TASKSTATS_TYPE_AGGR_PID];
+       else if (info->attrs[TASKSTATS_TYPE_AGGR_TGID])
+               nested = info->attrs[TASKSTATS_TYPE_AGGR_TGID];
+       else {
+               fprintf(stderr, "Invalid taskstats message: Unable to find "
+                               "nested attribute/\n");
+               return NL_SKIP;
+       }
+
+       err = nla_parse_nested(attrs, TASKSTATS_TYPE_MAX, nested, attr_policy);
+       if (err < 0) {
+               nl_perror(err, "Error while parsing generic netlink message");
+               return err;
+       }
+
+
+       if (attrs[TASKSTATS_TYPE_STATS]) {
+               struct taskstats *stats = nla_data(attrs[TASKSTATS_TYPE_STATS]);
+
+               printf("%s pid %u uid %u gid %u parent %u\n",
+                      stats->ac_comm, stats->ac_pid, stats->ac_uid,
+                      stats->ac_gid, stats->ac_ppid);
+       }
+
+       return 0;
+}
+
+static int parse_cb(struct nl_msg *msg, void *arg)
+{
+       return genl_handle_msg(msg, NULL);
+}
+
+static struct genl_cmd cmds[] = {
+       {
+               .c_id           = TASKSTATS_CMD_NEW,
+               .c_name         = "taskstats_new()",
+               .c_maxattr      = TASKSTATS_TYPE_MAX,
+               .c_attr_policy  = attr_policy,
+               .c_msg_parser   = &parse_cmd_new,
+       },
+};
+
+#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
+
+static struct genl_ops ops = {
+       .o_name = TASKSTATS_GENL_NAME,
+       .o_cmds = cmds,
+       .o_ncmds = ARRAY_SIZE(cmds),
+};
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *sock;
+       struct nl_msg *msg;
+       void *hdr;
+       int err;
+
+       sock = nl_cli_alloc_socket();
+       nl_cli_connect(sock, NETLINK_GENERIC);
+
+       if ((err = genl_register_family(&ops)) < 0)
+               nl_cli_fatal(err, "Unable to register Generic Netlink family");
+
+       if ((err = genl_ops_resolve(sock, &ops)) < 0)
+               nl_cli_fatal(err, "Unable to resolve family name");
+
+       if (genl_ctrl_resolve(sock, "nlctrl") != GENL_ID_CTRL)
+               nl_cli_fatal(NLE_INVAL, "Resolving of \"nlctrl\" failed");
+
+       msg = nlmsg_alloc();
+       if (msg == NULL)
+               nl_cli_fatal(NLE_NOMEM, "Unable to allocate netlink message");
+
+       hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ops.o_id,
+                         0, 0, TASKSTATS_CMD_GET, TASKSTATS_GENL_VERSION);
+       if (hdr == NULL)
+               nl_cli_fatal(ENOMEM, "Unable to write genl header");
+
+       if ((err = nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, 1)) < 0)
+               nl_cli_fatal(err, "Unable to add attribute: %s", nl_geterror(err));
+
+       if ((err = nl_send_auto_complete(sock, msg)) < 0)
+               nl_cli_fatal(err, "Unable to send message: %s", nl_geterror(err));
+
+       nlmsg_free(msg);
+
+       if ((err = nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM,
+                       parse_cb, NULL)) < 0)
+               nl_cli_fatal(err, "Unable to modify valid message callback");
+
+       if ((err = nl_recvmsgs_default(sock)) < 0)
+               nl_cli_fatal(err, "Unable to receive message: %s", nl_geterror(err));
+
+       nl_close(sock);
+       nl_socket_free(sock);
+
+       return 0;
+}
diff --git a/tests/test-nf-cache-mngr.c b/tests/test-nf-cache-mngr.c
new file mode 100644 (file)
index 0000000..b4f3022
--- /dev/null
@@ -0,0 +1,57 @@
+#include <netlink/cli/utils.h>
+
+static void change_cb(struct nl_cache *cache, struct nl_object *obj,
+                     int action, void *data)
+{
+       struct nfnl_ct *ct = (struct nfnl_ct *) obj;
+       static struct nl_addr *hack = NULL;
+
+       if (!hack)
+               nl_addr_parse("194.88.212.233", AF_INET, &hack);
+
+       if (!nl_addr_cmp(hack, nfnl_ct_get_src(ct, 1)) ||
+           !nl_addr_cmp(hack, nfnl_ct_get_dst(ct, 1))) {
+               struct nl_dump_params dp = {
+                       .dp_type = NL_DUMP_LINE,
+                       .dp_fd = stdout,
+               };
+
+               printf("UPDATE ");
+               nl_object_dump(obj, &dp);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       struct nl_cache_mngr *mngr;
+       struct nl_sock *sock;
+       struct nl_cache *ct;
+       int err;
+
+       sock = nl_cli_alloc_socket();
+
+       err = nl_cache_mngr_alloc(sock, NETLINK_NETFILTER, NL_AUTO_PROVIDE, &mngr);
+       if (err < 0) {
+               nl_perror(err, "nl_cache_mngr_alloc");
+               return -1;
+       }
+
+       err = nl_cache_mngr_add(mngr, "netfilter/ct", &change_cb, NULL, &ct);
+       if (err < 0) {
+               nl_perror(err, "nl_cache_mngr_add(netfilter/ct)");
+               return -1;
+       }
+
+       for (;;) {
+               int err = nl_cache_mngr_poll(mngr, 5000);
+               if (err < 0) {
+                       nl_perror(err, "nl_cache_mngr_poll()");
+                       return -1;
+               }
+
+       }
+
+       nl_cache_mngr_free(mngr);
+
+       return 0;
+}
diff --git a/tests/test-socket-creation.c b/tests/test-socket-creation.c
new file mode 100644 (file)
index 0000000..83f3ad4
--- /dev/null
@@ -0,0 +1,28 @@
+#include <netlink/netlink.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+       struct nl_sock *h[1025];
+       int i;
+
+       h[0] = nl_socket_alloc();
+       printf("Created handle with port 0x%x\n",
+                       nl_socket_get_local_port(h[0]));
+       nl_socket_free(h[0]);
+       h[0] = nl_socket_alloc();
+       printf("Created handle with port 0x%x\n",
+                       nl_socket_get_local_port(h[0]));
+       nl_socket_free(h[0]);
+
+       for (i = 0; i < 1025; i++) {
+               h[i] = nl_socket_alloc();
+               if (h[i] == NULL)
+                       nl_perror(ENOMEM, "Unable to allocate socket");
+               else
+                       printf("Created handle with port 0x%x\n",
+                               nl_socket_get_local_port(h[i]));
+       }
+
+       return 0;
+}
diff --git a/tests/util.h b/tests/util.h
new file mode 100644 (file)
index 0000000..c675383
--- /dev/null
@@ -0,0 +1,5 @@
+#include <check.h>
+
+#define nl_fail_if(condition, error, message) \
+       fail_if((condition), "nlerr=%d (%s): %s", \
+               (error), nl_geterror(error), (message))