aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Ružička <jakub.ruzicka@nic.cz>2022-03-30 17:24:30 +0000
committerJakub Ružička <jakub.ruzicka@nic.cz>2022-03-30 17:24:30 +0000
commit061bbacc77a2f82dd052917f412c30e744d07b9d (patch)
tree30a97e2166c3e8e4251c1d1fa20ec26ffba8465d
parentdf3b50c14ca0bd9f06afa78e559345ab7a195ed0 (diff)
downloadbird-061bbacc77a2f82dd052917f412c30e744d07b9d.tar.gz
New upstream version 2.0.9
-rw-r--r--.gitignore2
-rw-r--r--.gitlab-ci.yml348
-rw-r--r--ChangeLog1278
-rw-r--r--NEWS35
-rw-r--r--conf/cf-lex.l31
-rw-r--r--conf/conf.c3
-rw-r--r--conf/conf.h5
-rw-r--r--conf/confbase.Y2
-rw-r--r--conf/flowspec.Y3
-rwxr-xr-xconfigure4275
-rw-r--r--configure.ac4
-rw-r--r--distro/README.md69
-rw-r--r--distro/config/apkg.toml8
-rw-r--r--distro/pkg/deb/bird.xml286
-rw-r--r--distro/pkg/deb/bird2-doc.docs4
-rw-r--r--distro/pkg/deb/bird2.bird.init136
-rw-r--r--distro/pkg/deb/bird2.bird.service14
-rw-r--r--distro/pkg/deb/bird2.docs2
-rw-r--r--distro/pkg/deb/bird2.install6
-rw-r--r--distro/pkg/deb/bird2.lintian-overrides1
-rw-r--r--distro/pkg/deb/bird2.manpages2
-rw-r--r--distro/pkg/deb/bird2.postinst19
-rw-r--r--distro/pkg/deb/bird2.postrm26
-rw-r--r--distro/pkg/deb/changelog5
-rw-r--r--distro/pkg/deb/compat1
-rw-r--r--distro/pkg/deb/control55
-rw-r--r--distro/pkg/deb/copyright99
-rw-r--r--distro/pkg/deb/envvars3
-rw-r--r--distro/pkg/deb/gbp.conf9
-rwxr-xr-xdistro/pkg/deb/prepare-environment28
-rwxr-xr-xdistro/pkg/deb/rules56
-rw-r--r--distro/pkg/deb/source/format1
-rw-r--r--distro/pkg/deb/watch2
-rw-r--r--distro/pkg/rpm/bird.service13
-rw-r--r--distro/pkg/rpm/bird.spec117
-rw-r--r--distro/pkg/rpm/bird.tmpfilesd1
-rw-r--r--doc/LinuxDocTools.pm637
-rw-r--r--doc/Makefile10
-rw-r--r--doc/bird.sgml235
-rw-r--r--doc/prog-head.sgml2
-rwxr-xr-xdoc/sgml2html53
-rwxr-xr-xdoc/sgml2latex53
-rwxr-xr-xdoc/sgml2txt53
-rw-r--r--filter/config.Y12
-rw-r--r--filter/data.c11
-rw-r--r--filter/data.h88
-rw-r--r--filter/f-inst.c133
-rw-r--r--filter/test.conf83
-rw-r--r--filter/trie.c951
-rw-r--r--filter/trie_test.c862
-rw-r--r--lib/Makefile2
-rw-r--r--lib/birdlib.h8
-rw-r--r--lib/bitops.h1
-rw-r--r--lib/blake2-impl.h153
-rw-r--r--lib/blake2-kat.h4130
-rw-r--r--lib/blake2.h148
-rw-r--r--lib/blake2b.c322
-rw-r--r--lib/blake2s.c313
-rw-r--r--lib/flowspec.c254
-rw-r--r--lib/flowspec.h4
-rw-r--r--lib/flowspec_test.c6
-rw-r--r--lib/ip.h37
-rw-r--r--lib/ip_test.c66
-rw-r--r--lib/lists.h2
-rw-r--r--lib/mac.c28
-rw-r--r--lib/mac.h9
-rw-r--r--lib/mac_test.c91
-rw-r--r--lib/mempool.c12
-rw-r--r--lib/net.h1
-rw-r--r--lib/resource.c47
-rw-r--r--lib/resource.h18
-rw-r--r--lib/slab.c159
-rw-r--r--lib/socket.h1
-rw-r--r--lib/string.h1
-rw-r--r--lib/strtoul.c27
-rw-r--r--lib/timer.c5
-rw-r--r--nest/a-set.c130
-rw-r--r--nest/attrs.h6
-rw-r--r--nest/cmds.c45
-rw-r--r--nest/config.Y119
-rw-r--r--nest/iface.c2
-rw-r--r--nest/password.c26
-rw-r--r--nest/password.h1
-rw-r--r--nest/proto.c11
-rw-r--r--nest/protocol.h2
-rw-r--r--nest/route.h64
-rw-r--r--nest/rt-attr.c31
-rw-r--r--nest/rt-fib.c2
-rw-r--r--nest/rt-show.c84
-rw-r--r--nest/rt-table.c987
-rw-r--r--proto/babel/Makefile2
-rw-r--r--proto/babel/babel.c228
-rw-r--r--proto/babel/babel.h70
-rw-r--r--proto/babel/config.Y40
-rw-r--r--proto/babel/packets.c658
-rw-r--r--proto/bgp/attrs.c45
-rw-r--r--proto/bgp/bgp.c69
-rw-r--r--proto/bgp/bgp.h10
-rw-r--r--proto/bgp/config.Y18
-rw-r--r--proto/bgp/packets.c76
-rw-r--r--proto/mrt/mrt.c9
-rw-r--r--proto/ospf/config.Y5
-rw-r--r--proto/ospf/dbdes.c2
-rw-r--r--proto/ospf/iface.c24
-rw-r--r--proto/ospf/lsack.c16
-rw-r--r--proto/ospf/lsreq.c2
-rw-r--r--proto/ospf/lsupd.c12
-rw-r--r--proto/ospf/ospf.h24
-rw-r--r--proto/ospf/packet.c51
-rw-r--r--proto/ospf/rt.c14
-rw-r--r--proto/pipe/pipe.c3
-rw-r--r--proto/radv/config.Y1
-rw-r--r--proto/radv/radv.c2
-rw-r--r--proto/rip/rip.c2
-rw-r--r--proto/rpki/packets.c27
-rw-r--r--proto/rpki/rpki.c2
-rw-r--r--proto/static/static.c2
-rw-r--r--sysdep/autoconf.h.in21
-rw-r--r--sysdep/bsd/krt-sock.c41
-rw-r--r--sysdep/bsd/sysio.h6
-rw-r--r--sysdep/config.h2
-rw-r--r--sysdep/linux/krt-sys.h1
-rw-r--r--sysdep/linux/netlink.Y4
-rw-r--r--sysdep/linux/netlink.c190
-rw-r--r--sysdep/linux/netlink.c.orig2179
-rw-r--r--sysdep/linux/sysio.h19
-rw-r--r--sysdep/unix/Makefile2
-rw-r--r--sysdep/unix/alloc.c130
-rw-r--r--sysdep/unix/io.c4
-rw-r--r--sysdep/unix/krt.c13
-rw-r--r--sysdep/unix/krt.h2
-rw-r--r--sysdep/unix/main.c19
-rw-r--r--sysdep/unix/random.c74
-rw-r--r--test/birdtest.c15
-rw-r--r--test/birdtest.h3
-rwxr-xr-xtools/gendist3
-rwxr-xr-xtools/linuxdoc80
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools.pm668
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm185
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm176
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/FixRef.pm76
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm583
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm357
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Lang.pm238
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Utils.pm392
-rw-r--r--tools/linuxdoc-tools/LinuxDocTools/Vars.pm22
-rw-r--r--tools/linuxdoc-tools/Text/EntityMap.pm121
-rw-r--r--tools/linuxdoc-tools/copyright85
-rwxr-xr-xtools/make-dev-archive32
-rwxr-xr-xtools/make-obs46
150 files changed, 20988 insertions, 3702 deletions
diff --git a/.gitignore b/.gitignore
index 4dd0a568..a50f1fce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
/autom4te.cache/
/obj/
+/pkg/
/Makefile
/bird
/birdc
@@ -12,3 +13,4 @@
/sysdep/autoconf.h.in
/sysdep/autoconf.h.in~
/cscope.*
+*.tar.gz
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 763e4405..678a08f6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,21 +1,22 @@
variables:
DEBIAN_FRONTEND: noninteractive
- LC_ALL: C
+ LC_ALL: C.UTF-8
GIT_STRATEGY: fetch
DOCKER_CMD: docker --config="$HOME/.docker/$CI_JOB_ID/"
- IMG_BASE: registry.labs.nic.cz/labs/bird
+ IMG_BASE: registry.nic.cz/labs/bird
TOOLS_DIR: /var/lib/gitlab-runner/bird-tools
stages:
- image
- build
+ - pkg
- test
.docker: &docker_build
stage: image
allow_failure: true
script:
- - $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.labs.nic.cz
+ - $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.nic.cz
# Make sure we refresh the base image if it updates (eg. security updates, etc)
# If we do just the build, cache is always reused and the freshness of the
# base image is never checked. However, pull always asks and updates the
@@ -31,16 +32,6 @@ stages:
# That's Docker in Docker
- dind
-docker_debian-7-amd64:
- variables:
- IMG_NAME: "debian-7-amd64"
- <<: *docker_build
-
-docker_debian-7-i386:
- variables:
- IMG_NAME: "debian-7-i386"
- <<: *docker_build
-
docker_debian-8-amd64:
variables:
IMG_NAME: "debian-8-amd64"
@@ -71,16 +62,28 @@ docker_debian-10-i386:
IMG_NAME: "debian-10-i386"
<<: *docker_build
-docker_debian-testing-amd64:
+docker_debian-11-amd64:
variables:
- IMG_NAME: "debian-testing-amd64"
+ IMG_NAME: "debian-11-amd64"
<<: *docker_build
-docker_debian-testing-i386:
+# GPG error
+#docker_debian-11-i386:
+# variables:
+# IMG_NAME: "debian-11-i386"
+# <<: *docker_build
+
+docker_debian-testing-amd64:
variables:
- IMG_NAME: "debian-testing-i386"
+ IMG_NAME: "debian-testing-amd64"
<<: *docker_build
+# GPG error
+#docker_debian-testing-i386:
+# variables:
+# IMG_NAME: "debian-testing-i386"
+# <<: *docker_build
+
docker_fedora-25-amd64:
variables:
IMG_NAME: "fedora-25-amd64"
@@ -116,6 +119,21 @@ docker_fedora-31-amd64:
IMG_NAME: "fedora-31-amd64"
<<: *docker_build
+docker_fedora-32-amd64:
+ variables:
+ IMG_NAME: "fedora-32-amd64"
+ <<: *docker_build
+
+docker_fedora-33-amd64:
+ variables:
+ IMG_NAME: "fedora-33-amd64"
+ <<: *docker_build
+
+docker_fedora-34-amd64:
+ variables:
+ IMG_NAME: "fedora-34-amd64"
+ <<: *docker_build
+
docker_centos-7-amd64:
variables:
IMG_NAME: "centos-7-amd64"
@@ -130,22 +148,33 @@ docker_ubuntu-14_04-amd64:
variables:
IMG_NAME: "ubuntu-14.04-amd64"
<<: *docker_build
-
+
docker_ubuntu-16_04-amd64:
variables:
IMG_NAME: "ubuntu-16.04-amd64"
<<: *docker_build
-
+
docker_ubuntu-18_04-amd64:
variables:
IMG_NAME: "ubuntu-18.04-amd64"
<<: *docker_build
-
-docker_ubuntu-19_10-amd64:
+
+docker_ubuntu-20_04-amd64:
variables:
- IMG_NAME: "ubuntu-19.10-amd64"
+ IMG_NAME: "ubuntu-20.04-amd64"
<<: *docker_build
+docker_ubuntu-21_10-amd64:
+ variables:
+ IMG_NAME: "ubuntu-21.10-amd64"
+ <<: *docker_build
+
+# GPG error
+#docker_ubuntu-21_04-amd64:
+# variables:
+# IMG_NAME: "ubuntu-21.04-amd64"
+# <<: *docker_build
+
docker_opensuse-15.0-amd64:
variables:
IMG_NAME: "opensuse-15.0-amd64"
@@ -156,6 +185,16 @@ docker_opensuse-15.1-amd64:
IMG_NAME: "opensuse-15.1-amd64"
<<: *docker_build
+docker_opensuse-15.2-amd64:
+ variables:
+ IMG_NAME: "opensuse-15.2-amd64"
+ <<: *docker_build
+
+docker_opensuse-15.3-amd64:
+ variables:
+ IMG_NAME: "opensuse-15.3-amd64"
+ <<: *docker_build
+
# TODO We want to copy these BSDs to our own virtual machines, to make sure
# someone doesn't update them by accident.
.freebsd-11-i386: &freebsd-11-i386_env
@@ -172,6 +211,7 @@ docker_opensuse-15.1-amd64:
- freebsd
- amd64
+
.build: &build-base
stage: build
script:
@@ -181,8 +221,9 @@ docker_opensuse-15.1-amd64:
- MAKE=make
- which gmake 2>/dev/null >/dev/null && MAKE=gmake
- $MAKE
- # Run tests if they are available
- $MAKE check
+ # Build docs when tools are available
+ - if which linuxdoc pdflatex >/dev/null ; then $MAKE docs ; fi
.build-linux: &build-linux
<<: *build-base
@@ -191,105 +232,133 @@ docker_opensuse-15.1-amd64:
- linux
- amd64
-build-debian-7-amd64:
- <<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-7-amd64
-
-build-debian-7-i386:
- <<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-7-i386
-
build-debian-8-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-8-amd64
+ image: registry.nic.cz/labs/bird:debian-8-amd64
build-debian-8-i386:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-8-i386
+ image: registry.nic.cz/labs/bird:debian-8-i386
build-debian-9-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-9-amd64
+ image: registry.nic.cz/labs/bird:debian-9-amd64
build-debian-9-i386:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-9-i386
+ image: registry.nic.cz/labs/bird:debian-9-i386
build-debian-10-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-10-amd64
+ image: registry.nic.cz/labs/bird:debian-10-amd64
build-debian-10-i386:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-10-i386
+ image: registry.nic.cz/labs/bird:debian-10-i386
-build-debian-testing-amd64:
+build-debian-11-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-testing-amd64
+ image: registry.nic.cz/labs/bird:debian-11-amd64
-build-debian-testing-i386:
+#build-debian-11-i386:
+# <<: *build-linux
+# image: registry.nic.cz/labs/bird:debian-11-i386
+
+build-debian-testing-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:debian-testing-i386
+ image: registry.nic.cz/labs/bird:debian-testing-amd64
+
+#build-debian-testing-i386:
+# <<: *build-linux
+# image: registry.nic.cz/labs/bird:debian-testing-i386
build-fedora-25-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:fedora-25-amd64
+ image: registry.nic.cz/labs/bird:fedora-25-amd64
build-fedora-26-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:fedora-26-amd64
+ image: registry.nic.cz/labs/bird:fedora-26-amd64
build-fedora-27-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:fedora-27-amd64
+ image: registry.nic.cz/labs/bird:fedora-27-amd64
build-fedora-28-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:fedora-28-amd64
+ image: registry.nic.cz/labs/bird:fedora-28-amd64
build-fedora-29-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:fedora-29-amd64
+ image: registry.nic.cz/labs/bird:fedora-29-amd64
build-fedora-30-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:fedora-30-amd64
+ image: registry.nic.cz/labs/bird:fedora-30-amd64
build-fedora-31-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:fedora-31-amd64
+ image: registry.nic.cz/labs/bird:fedora-31-amd64
+
+build-fedora-32-amd64:
+ <<: *build-linux
+ image: registry.nic.cz/labs/bird:fedora-32-amd64
+
+build-fedora-33-amd64:
+ <<: *build-linux
+ image: registry.nic.cz/labs/bird:fedora-33-amd64
+
+build-fedora-34-amd64:
+ <<: *build-linux
+ image: registry.nic.cz/labs/bird:fedora-33-amd64
build-centos-7-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:centos-7-amd64
+ image: registry.nic.cz/labs/bird:centos-7-amd64
build-centos-8-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:centos-8-amd64
+ image: registry.nic.cz/labs/bird:centos-8-amd64
build-ubuntu-14_04-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:ubuntu-14.04-amd64
+ image: registry.nic.cz/labs/bird:ubuntu-14.04-amd64
build-ubuntu-16_04-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:ubuntu-16.04-amd64
+ image: registry.nic.cz/labs/bird:ubuntu-16.04-amd64
build-ubuntu-18_04-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:ubuntu-18.04-amd64
+ image: registry.nic.cz/labs/bird:ubuntu-18.04-amd64
-build-ubuntu-19_04-amd64:
+build-ubuntu-20_04-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:ubuntu-19.04-amd64
+ image: registry.nic.cz/labs/bird:ubuntu-20.04-amd64
+
+build-ubuntu-21_10-amd64:
+ <<: *build-linux
+ image: registry.nic.cz/labs/bird:ubuntu-21.10-amd64
+
+#build-ubuntu-21_04-amd64:
+# <<: *build-linux
+# image: registry.nic.cz/labs/bird:ubuntu-21.04-amd64
build-opensuse-15.0-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:opensuse-15.0-amd64
+ image: registry.nic.cz/labs/bird:opensuse-15.0-amd64
build-opensuse-15.1-amd64:
<<: *build-linux
- image: registry.labs.nic.cz/labs/bird:opensuse-15.1-amd64
+ image: registry.nic.cz/labs/bird:opensuse-15.1-amd64
+
+build-opensuse-15.2-amd64:
+ <<: *build-linux
+ image: registry.nic.cz/labs/bird:opensuse-15.2-amd64
+
+build-opensuse-15.3-amd64:
+ <<: *build-linux
+ image: registry.nic.cz/labs/bird:opensuse-15.3-amd64
build-freebsd-11-amd64:
<<: *build-base
@@ -303,6 +372,151 @@ build-freebsd-11-i386:
- freebsd
- i386
+
+.pkg-deb: &pkg-deb
+ stage: pkg
+ script:
+ - pip3 install apkg
+ - apkg build
+ #- apkg install -y pkg/pkgs/*/*/*.deb
+ artifacts:
+ paths:
+ - pkg/pkgs/*
+
+.pkg-rpm: &pkg-rpm
+ stage: pkg
+ script:
+ - pip3 install apkg
+ - apkg build
+ #- apkg install -y pkg/pkgs/*/*/*.rpm
+ artifacts:
+ paths:
+ - pkg/pkgs/*
+
+.pkg-rpm-wa: &pkg-rpm-wa
+ stage: pkg
+ script:
+ - sed -i "s/runstatedir/with-runtimedir/" distro/pkg/rpm/bird.spec
+ - pip3 install apkg
+ - apkg build
+ #- apkg install -y pkg/pkgs/*/*/*.rpm
+ artifacts:
+ paths:
+ - pkg/pkgs/*
+
+# Dpkg error: PATH is not set
+#pkg-debian-8-amd64:
+# <<: *pkg-deb
+# needs: [build-debian-8-amd64]
+# image: registry.nic.cz/labs/bird:debian-8-amd64
+
+# Dpkg error: PATH is not set
+#pkg-debian-8-i386:
+# <<: *pkg-deb
+# needs: [build-debian-8-i386]
+# image: registry.nic.cz/labs/bird:debian-8-i386
+
+# Dpkg error: PATH is not set
+pkg-debian-9-amd64:
+ <<: *pkg-deb
+ needs: [build-debian-9-amd64]
+ image: registry.nic.cz/labs/bird:debian-9-amd64
+
+# Dpkg error: PATH is not set
+pkg-debian-9-i386:
+ <<: *pkg-deb
+ needs: [build-debian-9-i386]
+ image: registry.nic.cz/labs/bird:debian-9-i386
+
+pkg-debian-10-amd64:
+ <<: *pkg-deb
+ needs: [build-debian-10-amd64]
+ image: registry.nic.cz/labs/bird:debian-10-amd64
+
+pkg-debian-10-i386:
+ <<: *pkg-deb
+ needs: [build-debian-10-i386]
+ image: registry.nic.cz/labs/bird:debian-10-i386
+
+pkg-debian-11-amd64:
+ <<: *pkg-deb
+ needs: [build-debian-11-amd64]
+ image: registry.nic.cz/labs/bird:debian-11-amd64
+
+pkg-fedora-30-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-fedora-30-amd64]
+ image: registry.nic.cz/labs/bird:fedora-30-amd64
+
+pkg-fedora-31-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-fedora-31-amd64]
+ image: registry.nic.cz/labs/bird:fedora-31-amd64
+
+pkg-fedora-32-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-fedora-32-amd64]
+ image: registry.nic.cz/labs/bird:fedora-32-amd64
+
+pkg-fedora-33-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-fedora-33-amd64]
+ image: registry.nic.cz/labs/bird:fedora-33-amd64
+
+pkg-fedora-34-amd64:
+ <<: *pkg-rpm
+ needs: [build-fedora-34-amd64]
+ image: registry.nic.cz/labs/bird:fedora-34-amd64
+
+pkg-centos-7-amd64:
+ <<: *pkg-rpm-wa
+ variables:
+ LC_ALL: en_US.UTF-8
+ needs: [build-centos-7-amd64]
+ image: registry.nic.cz/labs/bird:centos-7-amd64
+
+pkg-centos-8-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-centos-8-amd64]
+ image: registry.nic.cz/labs/bird:centos-8-amd64
+
+pkg-ubuntu-18.04-amd64:
+ <<: *pkg-deb
+ needs: [build-ubuntu-18_04-amd64]
+ image: registry.nic.cz/labs/bird:ubuntu-18.04-amd64
+
+pkg-ubuntu-20.04-amd64:
+ <<: *pkg-deb
+ needs: [build-ubuntu-20_04-amd64]
+ image: registry.nic.cz/labs/bird:ubuntu-20.04-amd64
+
+
+pkg-ubuntu-21.10-amd64:
+ <<: *pkg-deb
+ needs: [build-ubuntu-21_10-amd64]
+ image: registry.nic.cz/labs/bird:ubuntu-21.10-amd64
+
+#pkg-ubuntu-21.04-amd64:
+# <<: *pkg-deb
+# needs: [build-ubuntu-21_04-amd64]
+# image: registry.nic.cz/labs/bird:ubuntu-21.04-amd64
+
+pkg-opensuse-15.1-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-opensuse-15.1-amd64]
+ image: registry.nic.cz/labs/bird:opensuse-15.1-amd64
+
+pkg-opensuse-15.2-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-opensuse-15.2-amd64]
+ image: registry.nic.cz/labs/bird:opensuse-15.2-amd64
+
+pkg-opensuse-15.3-amd64:
+ <<: *pkg-rpm-wa
+ needs: [build-opensuse-15.3-amd64]
+ image: registry.nic.cz/labs/bird:opensuse-15.3-amd64
+
+
build-birdlab:
stage: build
tags:
@@ -369,6 +583,11 @@ test-ospf-custom:
variables:
TEST_NAME: cf-ospf-custom
+test-ospf-area:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-area
+
test-ospf-vrf:
<<: *test-base
variables:
@@ -413,3 +632,18 @@ test-ibgp-star:
<<: *test-base
variables:
TEST_NAME: cf-ibgp-flat
+
+test-babel-base:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-babel-base
+
+test-babel-auth:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-babel-auth
+
+test-rip-base:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-rip-base
diff --git a/ChangeLog b/ChangeLog
index 02fcdaf2..5efa987f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1281 @@
+commit 34028fc9cfd44d9bfa5d87eadc9d819e7d1fb39b
+Author: Ondrej Filip <feela@network.cz>
+Date: Sun Feb 20 15:47:07 2022 +0100
+
+ Small bugfix in directory existence test
+
+commit eb859a3fb063b261fb76304e5b8eca206e7a162a
+Author: Ondrej Filip <feela@network.cz>
+Date: Sun Feb 20 15:30:47 2022 +0100
+
+ Small change to fix doc building on Debian
+
+commit 9b13fa4d9c3cd8894f61ed84a38ef3c69fe4fe6f
+Author: Ondrej Filip <feela@network.cz>
+Date: Sun Feb 20 14:28:06 2022 +0100
+
+ Small changes related to the new release
+
+commit 64d5d6d2c34fc198753f232959108305b5bd4b4c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Feb 13 16:45:49 2022 +0100
+
+ NEWS: Fix formatting and add some notes
+
+commit 71c9484b00b4428ae6c7d7c8eea6d96073683a54
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Feb 9 03:47:49 2022 +0100
+
+ NEWS and version update
+
+commit 2fc8b4c4bac576427b0054a13cc78e395b93d6c4
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Feb 8 22:42:00 2022 +0100
+
+ Alloc: Use posix_memalign() instead of aligned_alloc()
+
+ For compatibility with older systems use posix_memalign(). We can
+ switch to aligned_alloc() when we commit to C11 for multithreading.
+
+commit ef614f29843ab2bdfb0ff5ed5da0a989eeaa33a6
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Feb 8 22:21:08 2022 +0100
+
+ Netlink: Minor cleanup
+
+commit edc1a2401752c3db30df1b9c6c796c06a8c59cc1
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Feb 7 04:39:49 2022 +0100
+
+ Lib: Update alignment of slabs
+
+ Alignment of slabs should be at least sizeof(ptr) to avoid unaligned
+ pointers in slab structures. Fixme: Use proper way to choose alignment
+ for internal allocators.
+
+commit 53a25406878ed686a58ec3e7379d6cb45b784942
+Merge: 4c6ee53f 24600c64
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Feb 6 23:32:15 2022 +0100
+
+ Merge branch 'oz-trie-table'
+
+commit 24600c642a1f50e2404f4d9dd98bd8a0c9844860
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Feb 6 22:53:55 2022 +0100
+
+ Trie: Fix trie format
+
+ After switching to 16-way tries, trie format ignored unaligned / internal
+ prefixes and only reported the primary prefix of a trie node.
+
+ Fix trie format by showing internal prefixes based on the 'local' bitmask
+ of a node. Also do basic (intra-node) reconstruction of prefix patterns
+ by finding common subtrees in 'local' bitmask.
+
+ In future, we could improve that by doing inter-node reconstruction, so
+ prefixes entered as one pattern for a subtree (e.g. 192.168.0.0/18+)
+ would be reported as such, like with aligned prefixes.
+
+commit 5a89edc6fd0b03716ccb77084e8d1a1910f52ab0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Feb 4 05:34:02 2022 +0100
+
+ Nest: Implement locking of prefix tries during walks
+
+ The prune loop may may rebuild the prefix trie and therefore invalidate
+ walk state for asynchronous walks (used in 'show route in' cmd). Fix it
+ by adding locking that keeps the old trie in memory until current walks
+ are done.
+
+ In future this could be improved by rebuilding trie walk states (by
+ lookup for last found prefix) after the prefix trie rebuild.
+
+commit de6318f70a06854a324b436b3a4cca0b3d60024b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Feb 3 06:08:51 2022 +0100
+
+ Nest: Implement prefix trie pruning
+
+ When rtable is pruned and network fib nodes are removed, we also need to
+ prune prefix trie. Unfortunately, rebuilding prefix trie takes long time
+ (got about 400 ms for 1M networks), so must not be atomic, we have to
+ rebuild a new trie while current one is still active. That may require
+ some considerable amount of temporary memory, so we do that only if
+ we expect significant trie size reduction.
+
+commit ba5aec94cdf643350677f6b0ac4d335039c22396
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Feb 2 05:06:49 2022 +0100
+
+ Trie: Add prefix counter
+
+ Add counter of prefixes stored in trie. Works only for 'restricted' tries
+ composed of explicit prefixes (pxlen == l == h), like ones used in rtables.
+
+commit d0f9a77f641d44472679caf85b7bef6e13ce926a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Dec 31 18:42:50 2021 +0100
+
+ Doc: Describe routing table options
+
+commit 1f2eb2aca8e348fefc1822ec2adcad0cc97768d8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 20 20:25:35 2021 +0100
+
+ BGP: Implement flowspec validation procedure
+
+ Implement flowspec validation procedure as described in RFC 8955 sec. 6
+ and RFC 9117. The Validation procedure enforces that only routers in the
+ forwarding path for a network can originate flowspec rules for that
+ network.
+
+ The patch adds new mechanism for tracking inter-table dependencies, which
+ is necessary as the flowspec validation depends on IP routes, and flowspec
+ rules must be revalidated when best IP routes change.
+
+ The validation procedure is disabled by default and requires that
+ relevant IP table uses trie, as it uses interval queries for subnets.
+
+commit 1ae42e522374ae60c23fe4c419c62b2209fbeea8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Dec 22 04:32:26 2021 +0100
+
+ Nest: Add routing table configuration blocks
+
+ Allow to specify sorted flag, trie fla, and min/max settle time.
+
+ Also do not enable trie by default, it must be explicitly enabled.
+
+commit fde1cff0122ee9d68f141976395e7f89ba28c311
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 20 20:44:36 2021 +0100
+
+ Nest: Add convenience functions to check rtable net type
+
+commit 61375bd0b3803fada0d7bb5b81b5824bab16b7c1
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Dec 2 04:05:17 2021 +0100
+
+ Nest: Avoid unnecessary net_format() in 'show route' command
+
+ When output of 'show route' command was generated, the net_format() was
+ called for each network prematurely, even if the result was not needed.
+
+ Fix the code to call net_format() only when needed. This makes queries
+ that process many networks but show only few (e.g. 'show route where ..',
+ or 'show route count') much faster (like 5x - 10x faster).
+
+commit 9ac16df3d7239bc82d8016591755b41b14285608
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Dec 2 03:30:39 2021 +0100
+
+ Nest: Add trie iteration code to 'show route'
+
+ Add trie iteration code to rt_show_cont() CLI hook and use it to
+ accelerate 'show route in <addr>' commands using interval queries.
+
+commit ea97b8905197180bee5244bce378d03e4b741d88
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Dec 2 02:22:30 2021 +0100
+
+ Nest: Implement 'show route in <addr>' command
+
+ Implement 'show route in <addr>' command, which shows all routes in
+ networks that are subnets of given network. Currently limited to IP
+ network types.
+
+commit 836a87b8acd5da40bde6b89702090c6616e06dfb
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Nov 29 19:23:42 2021 +0100
+
+ Nest: Attach prefix trie to rtable for faster LPM and interval queries
+
+ Attach a prefix trie to IP/VPN/ROA tables. Use it for net_route() and
+ net_roa_check(). This leads to 3-5x speedups for IPv4 and 5-10x
+ speedup for IPv6 of these calls.
+
+ TODO:
+ - Rebuild the trie during rt_prune_table()
+ - Better way to avoid trie_add_prefix() in net_get() for existing tables
+ - Make it configurable (?)
+
+commit 4c6ee53f31a7ac667bc597b0fe19b6365abad415
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jan 28 18:13:18 2022 +0100
+
+ BGP: Make routing loops silent
+
+ One of previous commits added error logging of invalid routes. This
+ also inadvertently caused error logging of route loops, which should
+ be ignored silently. Fix that.
+
+commit 963b2c7ce219df6bf9c179fff2dd2386cf26edf9
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jan 28 05:35:22 2022 +0100
+
+ BGP: Use proper class in attribute error messages
+
+ Most error messages in attribute processing are in rx/decode step and
+ these use L_REMOTE log class. But there are few that are in tx/export
+ step and these should use L_ERR log class.
+
+ Use tx-specific macro (REJECT()) in tx/export code and rename field
+ err_withdraw to err_reject in struct bgp_export_state to ensure that
+ appropriate error reporting macros are called in proper contexts.
+
+commit 75d01ecc2d32f3f673f82d90552f17b753e5e739
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jan 28 05:03:03 2022 +0100
+
+ BGP: Improve 'invalid next hop' error reporting
+
+ Distinguish multiple causes of 'invalid next hop' message and report
+ the relevant next hop address.
+
+ Thanks to Simon Ruderich for the original patch.
+
+commit 9dbb7eb6ebda016cd14ce8fef403c2b3f7bdd504
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Jan 24 03:44:21 2022 +0100
+
+ BGP: Log route updates that were changed to withdraws
+
+ Typical BGP error handling is treat-as-withdraw, where an invalid route
+ is replaced with a withdraw. Log route network when it happens.
+
+commit a9646efd40569f3a1d749bc1bd13219876b33a00
+Author: Matous Holinka <matous.holinka@nic.cz>
+Date: Thu Jan 6 09:53:23 2022 +0100
+
+ .gitlab-ci.yml: minor changes inside the .yml file.
+
+ + ubuntu:21.10 added into the pipeline,
+ - ubuntu:20.10 removed from the pipeline,
+
+ + misc/docker/ubuntu-21.10-amd64/Dockerfile added,
+ - misc/docker/ubuntu-20.10-amd64/Dockerfile removed.
+
+commit 81ee6cda2e60bbd3d97ab63da30657a54b09feda
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Jan 17 05:11:29 2022 +0100
+
+ Netlink: Add option to specify netlink socket receive buffer size
+
+ Add option 'netlink rx buffer' to specify netlink socket receive buffer
+ size. Uses SO_RCVBUFFORCE, so it can override rmem_max limit.
+
+ Thanks to Trisha Biswas and Michal for the original patches.
+
+commit bbc33f6ec310d98b9100fb883a2b8908ede1b5a8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Jan 15 22:39:40 2022 +0100
+
+ Netlink: Add another workaround for older kernel headers
+
+ Unfortunately, SOL_NETLINK is both recently added and arch-dependent,
+ so we cannot just define it.
+
+commit 8988264a64dc9985303332568832b108dba3acd3
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jan 14 23:15:05 2022 +0100
+
+ Netlink: Add workaround for older kernel headers
+
+commit e818f16448e918ed07633480291283f3449dd9e4
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jan 14 21:53:40 2022 +0100
+
+ Netlink: Enable strict checking for KRT dumps
+
+ Add strict checking for netlink KRT dumps to avoid PMTU cache records
+ from FNHE table dump along with KRT.
+
+ Linux Kernel added FNHE table dump to the netlink API in patch:
+
+ https://patchwork.ozlabs.org/project/netdev/patch/8d3b68cd37fb5fddc470904cdd6793fcf480c6c1.1561131177.git.sbrivio@redhat.com/
+
+ Therefore, since Linux 5.3 these route cache entries are dumped together
+ with regular routes during periodic KRT scans, which in some cases may be
+ huge amount of useless data. This can be avoided by using strict checking
+ for netlink dumps:
+
+ https://lore.kernel.org/netdev/20181008031644.15989-1-dsahern@kernel.org/
+
+ The patch mitigates the risk of receiving unknown and potentially large
+ number of FNHE records that would block BIRD I/O in each sync. There is a
+ known issue caused by the GRE tunnels on Linux that seems to be creating
+ one FNHE record for each destination IP address that is routed through
+ the tunnel, even when the PMTU equals to GRE interface MTU.
+
+ Thanks to Tomas Hlavacek for the original patch.
+
+commit d0dd1d20cd40e75e417d58569fac3ff0bf1db41a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jan 14 19:07:57 2022 +0100
+
+ Netlink: Explicitly skip received cloned routes
+
+ Kernel uses cloned routes to keep route cache entries, but reports them
+ together with regular routes. They were skipped implicitly as they
+ do not have rtm_protocol filled. Add explicit check for cloned flag
+ and skip such routes explicitly.
+
+ Also, improve debug logs of skipped routes.
+
+commit 60e9def9ef7b5d16f868b0fb4ab1192d59fd7541
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Jan 9 02:40:58 2022 +0100
+
+ BGP: Add option 'free bind'
+
+ The BGP 'free bind' option applies the IP_FREEBIND/IPV6_FREEBIND
+ socket option for the BGP listening socket.
+
+ Thanks to Alexander Zubkov for the idea.
+
+commit 87a02489f3880689a4e2ad72b0b981649dad2154
+Author: Alexander Zubkov <green@qrator.net>
+Date: Sat Jan 8 18:31:56 2022 +0100
+
+ IO: Support nonlocal bind in socket interface
+
+ Add option to socket interface for nonlocal binding, i.e. binding to an
+ IP address that is not present on interfaces. This behaviour is enabled
+ when SKF_FREEBIND socket flag is set. For Linux systems, it is
+ implemented by IP_FREEBIND socket flag.
+
+ Minor changes done by commiter.
+
+commit bcb25084d31fdb90fcf1666f10e73fe0f863afc0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jan 5 20:07:27 2022 +0100
+
+ Test: Activate some remaining build tests
+
+commit f5c8fb5fba959d356ce1ea0fb5879223f76137f7
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jan 5 19:25:42 2022 +0100
+
+ Netlink: Do not ignore dead routes from BIRD
+
+ Currently, BIRD ignores dead routes to consider them absent. But it also
+ ignores its own routes and thus it can not correctly manage such routes
+ in some cases. This patch makes an exception for routes with proto bird
+ when ignoring dead routes, so they can be properly updated or removed.
+
+ Thanks to Alexander Zubkov for the original patch.
+
+commit 77d032c71f62e44293a10ccc22f8c157442df179
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jan 5 18:46:41 2022 +0100
+
+ Netlink: Improve multipath parsing errors
+
+ Function nl_parse_multipath() should handle errors internally.
+
+commit 29dda184e56ce3a1ec72db4612198f6b3ba84e82
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jan 5 16:38:49 2022 +0100
+
+ Conf: Fix parsing full-length IPv6 addresses
+
+ Lexer expression for bytestring was too loose, accepting also
+ full-length IPv6 addresses. It should be restricted such that
+ colon is used between every byte or never.
+
+ Fix the regex and also add some test cases for it.
+
+ Thanks to Alexander Zubkov for the bugreport
+
+commit 75aceadaf746f8ed0acce0424f89903283dacf16
+Author: Matous <bralor92@email.cz>
+Date: Thu Oct 14 12:16:46 2021 +0200
+
+ gitlab-ci.yml: failing gitlab runner fixed.
+
+ 'registry.labs.nic.cz' -> 'registry.nic.cz' changed
+
+commit 77042292ff1ebeb5451f3a4119c3cbde0629f5b1
+Author: Alexander Zubkov <green@qrator.net>
+Date: Tue Dec 28 04:09:36 2021 +0100
+
+ Doc: Document min/max operators for lists
+
+commit 0e1fd7ea6af8aaeb68a23e320c2a0a0a8480d6de
+Author: Alexander Zubkov <green@qrator.net>
+Date: Tue Dec 28 04:05:05 2021 +0100
+
+ Filter: Add operators to find minimum and maximum element of sets
+
+ Add operators .min and .max to find minumum or maximum element in sets
+ of types: clist, eclist, lclist. Example usage:
+
+ bgp_community.min
+ bgp_ext_community.max
+ filter(bgp_large_community, [(as1, as2, *)]).min
+
+ Signed-off-by: Alexander Zubkov <green@qrator.net>
+
+commit e15e465720c428e765ab88fd587afb4f4f5d70ae
+Author: Alexander Zubkov <green@qrator.net>
+Date: Tue Dec 28 03:48:42 2021 +0100
+
+ Doc: Document community components access operators
+
+commit a2a268da4f0c05012d691b57f9b358e3f35ef121
+Author: Alexander Zubkov <green@qrator.net>
+Date: Tue Dec 28 03:46:13 2021 +0100
+
+ Filter: Add operators to pick community components
+
+ Add operators that can be used to pick components from
+ pair (standard community) or lc (large community) types.
+ For example:
+
+ (10, 20).asn --> 10
+ (10, 20).data --> 20
+
+ (10, 20, 30).asn --> 10
+ (10, 20, 30).data1 --> 20
+ (10, 20, 30).data2 --> 30
+
+ Signed-off-by: Alexander Zubkov <green@qrator.net>
+
+commit a39cd2cc0b0c64235457c07e2b618318bbdfcacd
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 27 19:10:35 2021 +0100
+
+ BSD: Assume onlink flag on ifaces with only host addresses
+
+ The BSD kernel does not support the onlink flag and BIRD does not use
+ direct routes for next hop validation, instead depends on interface
+ address ranges. We would like to handle PtMP cases with only host
+ addresses configured, like:
+
+ ifconfig wg0 192.168.0.10/32
+ route add 192.168.0.4 -iface wg0
+ route add 192.168.0.8 -iface wg0
+
+ To accept BIRD routes with onlink next-hop, like:
+
+ route 192.168.42.0/24 via 192.168.0.4%wg0 onlink
+
+ BIRD would dismiss the route when receiving from the kernel, as the
+ next-hop 192.168.0.4 is not part of any interface subnet and onlink
+ flag is not kept by the BSD kernel.
+
+ The commit fixes this by assuming that for routes received from the
+ kernel, any next-hop is onlink on ifaces with only host addresses.
+
+ Thanks to Stefan Haller for the original patch.
+
+commit b9f38727a7ba7c9c7e383ade80dbf77086dfce05
+Author: Job Snijders <job@fastly.com>
+Date: Sat Dec 18 16:35:28 2021 +0100
+
+ RPKI: Add contextual out-of-bound checks in RTR Prefix PDU handler
+
+ RFC 6810 and RFC 8210 specify that the "Max Length" value MUST NOT be
+ less than the Prefix Length element (underflow). On the other side,
+ overflow of the Max Length element also is possible, it being an 8-bit
+ unsigned integer allows for values larger than 32 or 128. This also
+ implicitly ensures there is no overflow of "Length" value.
+
+ When a PDU is received where the Max Length field is corrputed, the RTR
+ client (BIRD) should immediately terminate the session, flush all data
+ learned from that cache, and log an error for the operator.
+
+ Minor changes done by commiter.
+
+commit 00410fd6c17697a5919cb32a44f7117dd3a0834a
+Author: Simon Ruderich <simon@ruderich.org>
+Date: Sat Dec 18 03:17:48 2021 +0100
+
+ Doc: bgp: remove "advertise ipv4"
+
+ The option was removed in d15b0b0a ("BGP redesign", 2016-12-07)
+ but the documentation wasn't updated.
+
+commit b21104c97e59128973501fc23570e2d929f48923
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Dec 18 00:58:47 2021 +0100
+
+ Nest: Do not ignore secondary flag changes in ifa updates
+
+ Compare all IA_* flags that are set by sysdep iface code.
+
+ The old code ignores IA_SECONDARY flag when comparing whether iface
+ address updates from kernel changed anything. This is usually not an
+ issue as kernel removes all secondary addresses due to removal of the
+ primary one, but it breaks when sysctl 'promote_secondaries' is enabled
+ and kernel promotes secondary addresses to primary ones.
+
+ Thanks to 'Alexander' for the bugreport.
+
+commit 78ddfd2600a31305a78dc205b65deba6fb2e0240
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Nov 29 19:00:24 2021 +0100
+
+ Trie: Clarify handling of less-common net types
+
+ For convenience, Trie functions generally accept as input values not only
+ NET_IPx types of nets, but also NET_VPNx and NET_ROAx types. But returned
+ values are always NET_IPx types.
+
+commit f772afc525156498900770ffe5a98349df89a45c
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Nov 27 00:21:12 2021 +0100
+
+ Memory statistics split into Effective and Overhead
+
+ This feature is intended mostly for checking that BIRD's allocation
+ strategies don't consume much memory space. There are some cases where
+ withdrawing routes in a specific order lead to memory fragmentation and
+ this output should give the user at least a notion of how much memory is
+ actually used for data storage and how much memory is "just allocated"
+ or used for overhead.
+
+ Also raising the "system allocator overhead estimation" from 8 to 16
+ bytes; it is probably even more. I've found 16 as a local minimum in
+ best scenarios among reachable machines. I couldn't find any reasonable
+ method to estimate this value when BIRD starts up.
+
+ This commit also fixes the inaccurate computation of memory overhead for
+ slabs where the "system allocater overhead estimation" was improperly
+ added to the size of mmap-ed memory.
+
+commit 14fc24f3a53ebc5525b854ccdc93274aa74a400f
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Nov 26 03:26:36 2021 +0100
+
+ Trie: Implement longest-prefix-match queries and walks
+
+ The prefix trie now supports longest-prefix-match query by function
+ trie_match_longest_ipX() and it can be extended to iteration over all
+ covering prefixes for a given prefix (from longest to shortest) using
+ TRIE_WALK_TO_ROOT_IPx() macro.
+
+commit 644e9ca94e2d10ba0c2de45f94523da2414328e3
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Nov 24 17:30:13 2021 +0100
+
+ Directly mapped pages are kept for future use if temporarily not needed
+
+commit 062e69bf520e5788913bdd564076ad9892b24a87
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Nov 19 18:04:32 2021 +0100
+
+ Trie: Implement trie walking code
+
+ Trie walking allows enumeration of prefixes in a trie in the usual
+ lexicographic order. Optionally, trie enumeration can be restricted
+ to a chosen subnet (and its descendants).
+
+commit 71c18d9f53ec0ea5eb512fdb6510d0c3350f96b4
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Nov 13 21:11:18 2021 +0100
+
+ Trie: Simplify network matching code
+
+ Introduce ipX_prefix_equal() and use it to simplify network matching code.
+
+commit 9f24fef5e91fb4df301242ede91ee7ac1b46b8a8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Oct 20 01:51:28 2021 +0200
+
+ Conf: Fix crash during shutdown
+
+ BIRD implements shutdown by reconfiguring to fake empty configuration.
+ Such fake config structure is created from the last running config and
+ shares some data, including symbol table. This allows access to (removed)
+ routing tables and causes crash when 'show route' command is used during
+ shutdown.
+
+ Clean up symbol table, table list and links to default tables, so removed
+ routing tables cannot be accessed during shutdown.
+
+commit 067f69a56de0e0e61d423ec5aa68095aa28e3124
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Sep 25 16:00:30 2021 +0200
+
+ Filter: Add prefix trie benchmarks
+
+ Add trie tests intended as benchmarks that use external datasets
+ instead of generated prefixes. As datasets are not included, they
+ are commented out by default.
+
+commit e709dc09e61c4604821d10b81604d38616b81a0b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Apr 21 13:49:29 2020 +0200
+
+ Filter: Improve prefix trie tests
+
+ Add tests explicitly matching insides and outsides of trie and update
+ tests to do testing of both IPv4 and IPv6 tries.
+
+commit dd61278c9db1d4bea29f0a21aa460c7fe931eb32
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Apr 6 14:20:16 2020 +0200
+
+ Filter: Update trie documentation
+
+commit 562a2b8c29a50cca5731b0a19e99a87a261ab4ef
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 5 03:56:07 2020 +0200
+
+ Filter: Fix trie test
+
+ Generated prefixes must be valid.
+
+commit 13225f1dbff54619476f2d8f6bc779dbb4983e3e
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 5 03:24:46 2020 +0200
+
+ Filter: Faster prefix sets
+
+ Use 16-way (4bit) branching in prefix trie instead of basic binary
+ branching. The change makes IPv4 prefix sets almost 3x faster, but
+ with more memory consumption and much more complicated algorithm.
+
+ Together with a previous filter change, it makes IPv4 prefix sets
+ about ~4.3x faster and slightly smaller (on my test data).
+
+commit f761be6b30633054a54369eee7d08b951a366e5e
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Jun 17 16:56:51 2021 +0200
+
+ Nest: Clean up main channel handling
+
+ Remove assumption that main channel is the only channel.
+
+commit 1b9bf4e192a252db861acadc7f800d7046435a3f
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Jun 14 20:02:50 2021 +0200
+
+ Nest: Fix export of tmpattrs through pipes
+
+ Pipes copy the original rte with old values, so they require rte to be
+ exported with stored tmpattrs. Other protocols access stored attributes
+ using eattr list, so they require rte to be exported with expanded
+ tmpattrs. This is temporary hack, we plan to remove whoe tmpattr mechanism.
+
+ Thanks to Paul Donohue for the bugreport.
+
+commit 3ebabab2778d05212cc07ebccf583159d5e0890a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Jun 14 17:58:37 2021 +0200
+
+ Revert "Nest: Fix export of tmpattrs through pipes"
+
+ This reverts commit f8e273b5e7a3c721f4a30cf27a0b4fe54602e83f.
+
+commit f8e273b5e7a3c721f4a30cf27a0b4fe54602e83f
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Jun 14 16:30:59 2021 +0200
+
+ Nest: Fix export of tmpattrs through pipes
+
+ In most cases of export there is no need to store back temporary
+ attributes to rte, as receivers (protocols) access eattr list anyway.
+ But pipe copies the original rte with old values, so we should store
+ tmpattrs also during export.
+
+ Thanks to Paul Donohue for the bugreport.
+
+commit 3f19100f5a47dce96d336d68e0cbe72de5d9ba60
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jun 11 01:31:10 2021 +0200
+
+ CI: Allow Babel tests
+
+commit 596f2e32e38bef076001f4b9a4c75b07fd0264b7
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jun 9 19:54:01 2021 +0200
+
+ Nest: Allow both 'password' and 'key' keywords for authentication keys
+
+commit 6d26f853951675bd188dbf88d539ccb9d02d7eb1
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jun 9 19:31:55 2021 +0200
+
+ Babel: Simplify auth expiration
+
+ Just use hello_expiry for that, keep init_expiry for initial
+ unauthentized neighbors.
+
+commit 8eea396baf2bd73ea846a48e82d5c42fc2aec6d5
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Jun 6 19:10:33 2021 +0200
+
+ Nest: Fix password list parsing code
+
+ One of previous patches broke password list parsing code, fix that.
+
+commit ee9516dbe85b7205c6c8e400780c5a25787d6bff
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Jun 6 17:23:45 2021 +0200
+
+ Lib: Fix static assert macro
+
+commit b174cc0abc0a9d7e84cc6fae46d9e19b714fbcfb
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Jun 6 15:22:59 2021 +0200
+
+ Babel: Add MAC authentication support - update
+
+ Some cleanups and bugfixes to the previous patch, including:
+
+ - Fix rate limiting in index mismatch check
+
+ - Fix missing BABEL_AUTH_INDEX_LEN in auth_tx_overhead computation
+
+ - Fix missing auth_tx_overhead recalculation during reconfiguration
+
+ - Fix pseudoheader construction in babel_auth_sign() (sport vs fport)
+
+ - Fix typecasts for ptrdiffs in log messages
+
+ - Make auth log messages similar to corresponding RIP/OSPF ones
+
+ - Change auth log messages for events that happen during regular
+ operation to debug messages
+
+ - Switch meaning of babel_auth_check*() functions for consistency
+ with corresponding RIP/OSPF ones
+
+ - Remove requirement for min/max key length, only those required by
+ given MAC code are enforced
+
+commit b218a28f61e1e9a93c3a4f2e180590f85df62e79
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Sat Apr 17 15:04:16 2021 +0200
+
+ Babel: Add MAC authentication support
+
+ This implements support for MAC authentication in the Babel protocol, as
+ specified by RFC 8967. The implementation seeks to follow the RFC as close
+ as possible, with the only deliberate deviation being the addition of
+ support for all the HMAC algorithms already supported by Bird, as well as
+ the Blake2b variant of the Blake algorithm.
+
+ For description of applicability, assumptions and security properties,
+ see RFC 8967 sections 1.1 and 1.2.
+
+commit 69d10132a6020e00ea2e8f899fdebf8128329699
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Thu Apr 15 20:15:53 2021 +0200
+
+ Babel: Refactor TLV parsing code for easier reuse
+
+ In preparation for adding authentication checks, refactor the TLV
+ walking code so it can be reused for a separate pass of the packet
+ for authentication checks.
+
+commit 589f7d1e4f3aaca3fec6c38474bb962a9c578ebe
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Thu Apr 15 04:38:49 2021 +0200
+
+ Nest: Allow MAC algorithms to specify min/max key length
+
+ Add min/max key length fields to the MAC algorithm description and
+ validate configured keys before they are used.
+
+commit 35f88b305ab6a0e27b5ff1b445f63f544986e14e
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Wed Apr 14 21:39:43 2021 +0200
+
+ Nest: Allow specifying security keys as hex bytes as well as strings
+
+ Add support for specifying a password in hexadecimal format, The result
+ is the same whether a password is specified as a quoted string or a
+ hex-encoded byte string, this just makes it more convenient to input
+ high-entropy byte strings as MAC keys.
+
+commit f1a824190c22f8159ad0f9378c2dd23e521eaf61
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Wed Apr 14 20:00:03 2021 +0200
+
+ Lib: Add tests for blake2s and blake2b
+
+ Import the blake2-kat.h header with test vector output from the blake
+ reference implementation, and add tests to mac_test.c to compare the
+ output of the Bird MAC algorithm implementations with that reference
+ output.
+
+ Since the reference implementation only has test vectors for the full
+ output size, there are no tests for the smaller-sized output variants.
+
+commit 725d9af94a6eaf3cbce1b107e36c8cf342828ea6
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Sat Apr 10 17:33:28 2021 +0200
+
+ Lib: Add Blake2s and Blake2b hash functions
+
+ The Babel MAC authentication RFC recommends implementing Blake2s as one of
+ the supported algorithms. In order to achieve do this, add the blake2b and
+ blake2s hash functions for MAC authentication. The hashing function
+ implementations are the reference implementations from blake2.net.
+
+ The Blake2 algorithms allow specifying an arbitrary output size, and the
+ Babel MAC spec says to implement Blake2s with 128-bit output. To satisfy
+ this, we add two different variants of each of the algorithms, one using
+ the default size (256 bits for Blake2s, 512 bits for Blake2b), and one
+ using half the default output size.
+
+ Update to BIRD coding style done by committer.
+
+commit e5724f71d2c054bc51d66092beb6af4da21e0c62
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Apr 8 01:15:17 2021 +0200
+
+ sysdep: Add wrapper to get random bytes - update
+
+ Simplify the code and fix an issue with getentropy() return value.
+
+commit c48ebde5ce6db3da8cd571d213d1a1f265de8983
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Thu Apr 1 19:20:13 2021 +0200
+
+ sysdep: Add wrapper to get random bytes
+
+ Add a wrapper function in sysdep to get random bytes, and required checks
+ in configure.ac to select how to do it. The configure script tries, in
+ order, getrandom(), getentropy() and reading from /dev/urandom.
+
+commit 91d04583891f7a6f4aee612cf3f143cc84a73991
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Jun 1 01:59:20 2021 +0200
+
+ BGP: Ensure that freed neighbor entry is not accessed
+
+ Routes from downed protocols stay in rtable (until next rtable prune
+ cycle ends) and may be even exported to another protocol. In BGP case,
+ source BGP protocol is examined, although dynamic parts (including
+ neighbor entries) are already freed. That may lead to crash under some
+ race conditions. Ensure that freed neighbor entry is not accessed to
+ avoid this issue.
+
+commit ebd5751cdeb4c753c6c9df31b82dcd6afee2cd39
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sun May 30 13:07:16 2021 +0200
+
+ Babel: Seqno requests are properly decoupled from neighbors when the underlying interface disappears
+
+ When an interface disappears, all the neighbors are freed as well. Seqno
+ requests were anyway not decoupled from them, leading to strange
+ segfaults. This fix adds a proper seqno request list inside neighbors to
+ make sure that no pointer to neighbor is kept after free.
+
+commit 10498b8e89a4509bdd447bd14f07a3b3e35ae575
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed May 26 18:57:32 2021 +0200
+
+ OSPF: Fix OSPFv3 in IPv4 mode with multiple areas
+
+ Some area handling code got confused by IPv4 setup in OSPFv3 mode.
+
+commit 8650e26dd1566032d587a654376092a9f31a1123
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu May 20 15:02:48 2021 +0200
+
+ CI: Try different locale for Centos 7
+
+commit 0c4dca7ffd2957cca3635d607cb4acc8dfd4af90
+Author: Matous Holinka <bralor92@email.cz>
+Date: Wed May 19 19:10:09 2021 +0200
+
+ CI: Package build for more platforms
+
+ .gitlab-ci.yml:
+ + pkg targets for some distros added
+ + artifacts added
+ - some distros were commented out (due to errors).
+
+ misc/docker/*:
+ + Dockerfiles updated with the necessary packages.
+
+commit 98ef34c0c77d49d766def88f263dab0e91817288
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 25 19:52:19 2021 +0200
+
+ CI: Try utf-8 locale to workaround apkg issue
+
+commit 445d0e699f2b98e5a892c812af9f021671920c1b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 25 11:24:46 2021 +0200
+
+ CI: Build documentation where tools are available
+
+commit 656c744080d308f75cc9707b139e2a3ec31ad5b7
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 25 03:37:54 2021 +0200
+
+ CI: Update docker images for building of documentation
+
+commit 5ea3c5bfee6ed24139bc8e82cc35f08c49d6aaff
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 25 03:07:25 2021 +0200
+
+ Pkg: Enable docs subpackage for Debian
+
+commit 81666d2f126b94e99042ed963e45de5a95f63df5
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Apr 23 00:20:36 2021 +0200
+
+ CI: Test of apkg build
+
+ Also temporarily disable cf-ospf-auth, as there is some problem with it.
+
+commit 312aeda393f9775f603a78c7feb0a11f3c789c02
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Apr 22 19:23:18 2021 +0200
+
+ Tools: Improve make-dev-archive
+
+ Use git-archive to avoid unrelated and temporary files and fix some
+ minor issues (e.g. dependency on bash as system shell).
+
+commit 280d133a9b50dab88d51871927f26cd967211f85
+Author: Jakub Ružička <jakub.ruzicka@nic.cz>
+Date: Tue Apr 13 20:29:11 2021 +0200
+
+ ubuntu: use any init-system-helpers
+
+ init-system-helpers (>= 1.56~) can't be satisfied on:
+
+ * Ubuntu 18.04 (1.51)
+ * Ubuntu 16.04 (1.29)
+ * Debian 9 (1.48)
+
+ Remove the specific version requirement in order to enable build on
+ older platforms.
+
+commit 53cabf94f8de41f740ed08456877f6b8b5889170
+Author: Jakub Ružička <jakub.ruzicka@nic.cz>
+Date: Fri Apr 9 18:36:25 2021 +0200
+
+ suse: fix bird.spec to work on SUSE
+
+ SUSE is more strict about .spec.
+
+ * use SPDX license id
+ * add missing %ghost file directive
+
+commit 60167856af243f5683840d7365493ed0b3fa6cd0
+Author: Jakub Ružička <jakub.ruzicka@nic.cz>
+Date: Fri Apr 9 16:35:10 2021 +0200
+
+ docs: disable docs subpackage to fix FTBFS
+
+ Adressing following FTBFS on all older debian/ubuntu distros:
+
+ Can't locate LinuxDocTools/Data/Latin1ToSgml.pm in @INC (you may need to install the LinuxDocTools::Data::Latin1ToSgml module)
+
+commit 329d6e3fbc5a09a9bc8800bd8a5d239dec1a3d24
+Author: Jakub Ružička <jakub.ruzicka@nic.cz>
+Date: Tue Apr 6 18:13:16 2021 +0200
+
+ add apkg-powered upstream packaging for deb, rpm
+
+ Files in a single new distro/ dir allow apkg to build BIRD packages for
+ various distros directly from upstream sources as well as from upstream
+ archives.
+
+ Please see distro/README.md for more detail as well as apkg docs:
+
+ https://apkg.rtfd.io
+
+ I've used these files to build bird-2.0.8 on all currently supported
+ releases of following distros:
+
+ * Debian
+ * Ubuntu
+ * Fedora
+ * CentOS
+ * openSUSE
+
+ Please note that latest apkg with accumulated fixes for bird is needed:
+ https://gitlab.nic.cz/packaging/apkg/-/merge_requests/35
+
+commit c3c691e95cd40d8654b720be8d9a8ae9fb050951
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 18 20:41:01 2021 +0200
+
+ Flowspec: Documentation update
+
+commit abc9ccc5cb7a3adcbb2090ba7314031b835b0e04
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 18 20:18:06 2021 +0200
+
+ Flowspec: Label field should use numeric operator and not bitmask operator
+
+commit dd8481cc1c92af32ec69cded42b985b7bad40b26
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 18 19:54:18 2021 +0200
+
+ Flowspec: Do not use comma for bitmask operators
+
+ For numeric operators, comma is used for disjunction in expressions like
+ "10, 20, 30..40". But for bitmask operators, comma is used for
+ conjunction in a way that does not really make much sense. Use always
+ explicit logical operators (&& and ||) to connect bitmask operators.
+
+ Thanks to Matt Corallo for the bugreport.
+
+commit e5468d16855600aeb8172e29936789c46ea58da0
+Author: Trisha Biswas <tbiswas@fastly.com>
+Date: Mon May 17 17:50:04 2021 +0200
+
+ Filter: Add MPLS label route attribute
+
+ Add support to set or read outgoing MPLS labels using filters. Currently
+ this supports the addition of one label per route for the first next hop.
+
+ Minor changes by committer.
+
+commit d114959e3aeef872441dccea34552047380af742
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri May 14 18:44:52 2021 +0200
+
+ Flowspec: Fix values for true/false operators
+
+ RFC 8955 is pretty clear that 000 is false and 111 is true.
+
+commit 69a33c92ffce12d173794508cc9d8acfa87d1dc3
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri May 14 18:33:15 2021 +0200
+
+ Flowspec: Add code for conversion of flowspec parts to interval lists
+
+ Implement function flow_explicate_part() to convert flowspec numeric
+ expressions to a simple list of (disjoint, sorted) intervals. That could
+ be used in filters to build f_tree-based int-sets from them.
+
+commit c1511b92cc9c215224314be38c28ed80843f55e4
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon May 10 20:09:31 2021 +0200
+
+ Babel: Log the reason when refusing to run on an interface
+
+ The babel protocol code checks whether iface supports multicast, and
+ whether it has a link-local address assigned. However, it doesn not give
+ any feedback if any of those checks fail, it just silently ignores the
+ interface. Fix this by explicitly logging when multicast check fails.
+
+ Based on patch from Toke Høiland-Jørgensen, thanks!
+
+commit b17adf073594974b05a60ddaaa6e36da4eac4831
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Mon May 10 19:49:43 2021 +0200
+
+ BSD: Propagate OS-level IFF_MULTICAST to internal IF_MULTICAST flag
+
+ The BSD code did not propagate the OS-level IFF_MULTICAST flag to the
+ Bird-internal IF_MULTICAST flag, which causes problems with Wireguard
+ interfaces on FreeBSD. The Linux sysdep code does propagate the flag
+ already, so just copy over the same check and flag update.
+
+commit 2a0af925b83f699d126cf0e733a49c75ffd86033
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon May 10 13:39:55 2021 +0200
+
+ OSPF: Allow ifaces with host address as unnumbered PtP or PtMP ifaces
+
+ Ifaces with host address (/32) were forced to be stubby, but now they
+ can be used as PtP or PtMP. For these ifaces we need to:
+
+ - Do not force stub mode
+ - Accept packets from any IP as local
+ - Accept any configured neighbor as local
+ - Detect ifaces properly as unnumbered
+ - Use ONLINK flag for nexthops
+
+commit bc591061f618cdc35cf21c7973a660f8d7018b43
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun May 9 15:16:13 2021 +0200
+
+ OSPF: Packets on PtP networks should be always sent to AllSPFRouters
+
+ As specified in RFC 2328 8.1: "On physical point-to-point networks,
+ the IP destination is always set to the address AllSPFRouters."
+
+ Note that this likely break setups with multiple neighbors on a network
+ configured as PtP, which worked before. These should be configured as
+ PtMP.
+
+ Thanks to Senthil Kumar Nagappan for the original patch and to Joakim
+ Tjernlund for suggestions.
+
+commit 1647923bd8d2f8e53337365abc5be7e343aa570c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun May 9 14:51:39 2021 +0200
+
+ OSPF: Minor refactoring of packet sending code
+
+ Common behavior for LSupd and delayed LSack moved to ospf_send_to_iface()
+ and other minor changes.
+
+commit 255722e0fcf251c101ff5bec92f1867edf841daa
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 25 02:34:46 2021 +0200
+
+ CI: Fix debian-10-i386 docker file
+
+commit 58510024bead8df9cba6e316f8275423a38fd51b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Apr 25 01:07:14 2021 +0200
+
+ Doc: Include full LinuxDocTools code
+
+ BIRD uses hacked LinuxDocTools for building documentation, keeping some
+ parts locally and using remaining parts from system-installed one. This
+ setup breaks when LinuxDocTools makes some internal changes and is hard
+ to keep consistent.
+
+ Just include full LinuxDocTools code (both hacked and unmodified parts)
+ to avoid consistency issues. Note that we still need some binaries from
+ LinuxDocTools, so it still needs to be installed to build documentation.
+
+commit b646c0098120bbb10ec91fa2fbf1df416c5849bd
+Author: Matous <bralor92@email.cz>
+Date: Wed Apr 21 13:22:23 2021 +0200
+
+ CI/CD: some latest releases added.
+
+ /misc/docker/:
+ + debian 11 (i386+amd64) added,
+ + fedora 32 added,
+ + fedora 33 added,
+ + fedora 34 added,
+ + opensuse 15.2 added,
+ + opensuse 15.3 added,
+ + ubuntu 20.04 added,
+ + ubuntu 20.10 added,
+ + ubuntu 21.04 added,
+ - ubuntu 19.10 removed.
+
+ /.gitlab-ci.yml:
+ + stages 'image' and 'build' updated.
+
+commit 3d90241f62393e6d614c1d20fde4013c9ff24685
+Author: Maria Matejka <mq@ucw.cz>
+Date: Mon Apr 19 15:13:20 2021 +0200
+
+ Internal route tables have a reduced cleanup routine
+
+ This fixes an internal table cleanup bug introduced
+ in ff397df7edcbe7a8abca5b419729b9c64c063847.
+
+commit a7c9515ebc88c42f26ce97255c98b2e61ad52934
+Author: Stefan Haller <stefan.haller@stha.de>
+Date: Mon Apr 19 15:06:42 2021 +0200
+
+ BSD: Fix invalid pointer derefence in logging code
+
+ For logging purposes a stack allocated net_addr struct was passed by
+ value as vararg (instead of the expected pointer). This resulted in
+ a segfault when the specific error condition got logged.
+
+commit 9c41e1ca3e93d4498eaa085139caf1545e08c1d8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Apr 12 17:01:31 2021 +0200
+
+ Lib: Fix handling of buffers in timestamp formatting
+
+ The code in tm_format_real_time() mixed up two buffers and their
+ sizes, which may cause crash in MRT dumping code.
+
+ Thanks to Piotr Wydrych for the bugreport.
+
+commit a2277975d787fb388e753432673acefd69454b1a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Apr 7 16:14:20 2021 +0200
+
+ Unix: Expand accepted ranges of iproute2 constants
+
+ We support 32bit table and realm/flow ids, we should also accept them as
+ constants.
+
+ Thanks to Patrick Hemmer for the bugreport.
+
+commit 5caf32efa209bc3e9d741fe2acfc992d2cfad3e7
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Apr 3 20:09:32 2021 +0200
+
+ Doc: Fix flowspec example
+
+ Thanks to Matt Corallo for the bugreport.
+
+commit 7c8b7649f95c72c207bcf95064d08e831d5738ce
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Mar 30 21:44:35 2021 +0200
+
+ Allocation of ea_list in one contiguous memory block
+
+ This saves some bytes of memory for complex ea's.
+
+commit ff397df7edcbe7a8abca5b419729b9c64c063847
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Mar 30 18:51:31 2021 +0200
+
+ Routing table is now a resource allocated from its own pool
+
+ This also fixes memory leaks from import/export tables being never
+ cleaned up and freed.
+
+commit a9938b179203a4d5c54eae6c814bfa8766f4fde0
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Mar 30 16:03:33 2021 +0200
+
+ Resources: added mb_move() to complement rmove() for memory blocks
+
+commit 4635314cefd55aaa2a0146b6722df55e7efba4b8
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Mar 30 15:09:53 2021 +0200
+
+ Routing tables list iteration should use explicit node struct position
+
+commit 7a74ad5a61c82ab0062a62dbc9ea6ab91d480485
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Mar 30 16:59:11 2021 +0200
+
+ BGP: Do not keep BAF_EXT_LEN flag internally
+
+ The flag makes sense just in external representation. It is reset during
+ BGP export, but keeping it internally broke MRT dumps for short attributes
+ that used it anyways.
+
+ Thanks to Simon Marsh for the bugreport and the patch.
+
+commit a06469d9fc1d3ec4b17b3109627aff7d9877ba0e
+Author: Maria Matejka <mq@ucw.cz>
+Date: Thu Mar 25 20:51:23 2021 +0100
+
+ Dropping automatic tests for Debian 7 Wheezy.
+
+ Debian 7 Wheezy has been superseded by Debian 8 Jessie on Apr 25, 2015,
+ with LTS support ending on May 31, 2018.
+
+ Debian 7 Wheezy's default GCC doesn't fully support C11. It should
+ anyway still be possible to build BIRD for Debian 7 if you backport
+ a C11-capable compiler there.
+
+commit 886dd92eeefa070d8db6aaf0245a67f7a9e9b983
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Jul 22 00:09:15 2020 +0200
+
+ Slab: head now uses bitmask for used/free nodes info instead of lists
+
+ From now, there are no auxiliary pointers stored in the free slab nodes.
+ This led to strange debugging problems if use-after-free happened in
+ slab-allocated structures, especially if the structure's first member is
+ a next pointer.
+
+ This also reduces the memory needed by 1 pointer per allocated object.
+ OTOH, we now rely on pages being aligned to their size's multiple, which
+ is quite common anyway.
+
commit 82f19ba95e421f00a8e99a866a2b8d9bbdba6cdc
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu Mar 18 20:18:38 2021 +0100
diff --git a/NEWS b/NEWS
index 4a85c365..c1e51af2 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,38 @@
+Version 2.0.9 (2022-02-09)
+ o BGP: Flowspec validation procedure
+ o Babel: MAC authentication support
+ o Routing table configuration blocks
+ o Optional prefix trie in routing table for faster LPM/interval queries
+ o CLI: New 'show route in <prefix>' command
+ o Filter: Faster (16-way) prefix sets
+ o Filter: MPLS label route attribute
+ o Filter: Operators to pick community components
+ o Filter: Operators to find minimum and maximum element of lists
+ o BGP: New 'free bind' option
+ o BGP: Log route updates that were changed to withdraws
+ o BGP: Improved 'invalid next hop' error reporting
+ o OSPF: Allow ifaces with host address as unnumbered PtP or PtMP ifaces
+ o OSPF: All packets on PtP networks should be sent to AllSPFRouters address
+ o Scripts for apkg-powered upstream packaging for deb and rpm
+ o Support for Blake2s and Blake2b hash functions
+ o Security keys / passwords can be entered in hexadecimal digits
+ o Memory statistics split into Effective and Overhead
+ o Linux: New option 'netlink rx buffer' to specify netlink socket buffer size
+ o BSD: Assume onlink flag on ifaces with only host addresses
+ o Many bugfixes
+
+ Notes:
+
+ For OSPF on PtP network, BIRD now sends all packets to multicast AllSPFRouters
+ address (as required in RFC 2328 8.1). This likely breaks setups with multiple
+ neighbors on a network configured as PtP, which worked in previous versions.
+ Such links should be configured as PtMP.
+
+ Since Linux 5.3, netlink socket can be flooded by route cache entries during
+ route table scan. This version mitigates that issue by using strict netlink
+ filtering.
+
+
Version 2.0.8 (2021-03-18)
o Automatic channel reloads based on RPKI changes
o Multiple static routes with the same network
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 05288b1a..c9d2f5a5 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -255,6 +255,37 @@ WHITE [ \t]
return IP4;
}
+{XIGIT}{2}((:{XIGIT}{2}){15,}|({XIGIT}{2}){15,}) {
+ char *s = yytext;
+ size_t len = 0, i;
+ struct bytestring *bytes;
+ byte *b;
+
+ while (*s) {
+ len++;
+ s += 2;
+ if (*s == ':')
+ s++;
+ }
+ bytes = cfg_allocz(sizeof(*bytes) + len);
+
+ bytes->length = len;
+ b = &bytes->data[0];
+ s = yytext;
+ errno = 0;
+ for (i = 0; i < len; i++) {
+ *b = bstrtobyte16(s);
+ if (errno == ERANGE)
+ cf_error("Invalid hex string");
+ b++;
+ s += 2;
+ if (*s == ':')
+ s++;
+ }
+ cf_lval.bs = bytes;
+ return BYTESTRING;
+}
+
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
if (!ip6_pton(yytext, &cf_lval.ip6))
cf_error("Invalid IPv6 address %s", yytext);
diff --git a/conf/conf.c b/conf/conf.c
index 58abcde1..a2b01667 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -520,6 +520,9 @@ order_shutdown(int gr)
memcpy(c, config, sizeof(struct config));
init_list(&c->protos);
init_list(&c->tables);
+ init_list(&c->symbols);
+ memset(c->def_tables, 0, sizeof(c->def_tables));
+ HASH_INIT(c->sym_hash, c->pool, 4);
c->shutdown = 1;
c->gr_down = gr;
diff --git a/conf/conf.h b/conf/conf.h
index 860d267a..3bc37959 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -136,6 +136,11 @@ struct sym_scope {
int active; /* Currently entered */
};
+struct bytestring {
+ size_t length;
+ byte data[];
+};
+
#define SYM_MAX_LEN 64
/* Remember to update cf_symbol_class_name() */
diff --git a/conf/confbase.Y b/conf/confbase.Y
index d98f0fee..6985783b 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -92,6 +92,7 @@ CF_DECLS
struct channel_limit cl;
struct timeformat *tf;
mpls_label_stack *mls;
+ struct bytestring *bs;
}
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
@@ -103,6 +104,7 @@ CF_DECLS
%token <i64> VPN_RD
%token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
%token <t> TEXT
+%token <bs> BYTESTRING
%type <iface> ipa_scope
%type <i> expr bool pxlen4
diff --git a/conf/flowspec.Y b/conf/flowspec.Y
index 4d259763..56a7c5dc 100644
--- a/conf/flowspec.Y
+++ b/conf/flowspec.Y
@@ -59,12 +59,12 @@ flow_num_type_:
| ICMP CODE { $$ = FLOW_TYPE_ICMP_CODE; }
| LENGTH { $$ = FLOW_TYPE_PACKET_LENGTH; }
| DSCP { $$ = FLOW_TYPE_DSCP; }
+ | LABEL { $$ = FLOW_TYPE_LABEL; }
;
flow_num_type: flow_num_type_{ flow_builder_set_type(this_flow, $1); };
flow_flag_type: TCP FLAGS { flow_builder_set_type(this_flow, FLOW_TYPE_TCP_FLAGS); };
flow_frag_type: FRAGMENT { flow_builder_set_type(this_flow, FLOW_TYPE_FRAGMENT); };
-flow_label_type: LABEL { flow_builder_set_type(this_flow, FLOW_TYPE_LABEL); };
flow_srcdst:
DST { $$ = FLOW_TYPE_DST_PREFIX; }
@@ -165,7 +165,6 @@ flow6_item:
| flow_num_type flow_num_opts
| flow_flag_type flow_bmk_opts
| flow_frag_type flow_frag_opts
- | flow_label_type flow_bmk_opts
;
flow4_opts:
diff --git a/configure b/configure
index 0c9380bc..6eaaeeb5 100755
--- a/configure
+++ b/configure
@@ -1,9 +1,9 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69e.
+# Generated by GNU Autoconf 2.69.
#
#
-# Copyright (C) 1992-1996, 1998-2017, 2020 Free Software Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
@@ -14,16 +14,14 @@
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
+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 $as_nop
+else
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
@@ -33,46 +31,46 @@ esac
fi
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
+# 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 ${PATH_SEPARATOR+false} :; then
+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 ||
@@ -81,6 +79,13 @@ if ${PATH_SEPARATOR+false} :; then
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 #((
@@ -89,12 +94,8 @@ case $0 in #((
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
done
IFS=$as_save_IFS
@@ -106,10 +107,30 @@ if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ $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
# Use a proper internal environment variable to ensure we don't fall
# into an infinite loop, continuously re-executing ourselves.
@@ -131,22 +152,20 @@ esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
fi
# We don't want this to propagate to other subprocesses.
{ _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
- as_bourne_compatible="as_nop=:
-if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-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 \$as_nop
+else
case \`(set -o) 2>/dev/null\` in #(
*posix*) :
set -o posix ;; #(
@@ -166,52 +185,42 @@ 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 :
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
-else \$as_nop
+else
exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1
-blah=\$(echo \$(echo blah))
-test x\"\$blah\" = xblah || exit 1
test -x / || 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"
- if (eval "$as_required") 2>/dev/null
-then :
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
as_have_required=yes
-else $as_nop
+else
as_have_required=no
fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
-then :
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
-else $as_nop
+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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ 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
+ as_shell=$as_dir/$as_base
if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
+ { $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_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
-then :
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
break 2
fi
fi
@@ -219,21 +228,14 @@ fi
esac
as_found=false
done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else $as_nop
- if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
+$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
-fi
+fi; }
+IFS=$as_save_IFS
- if test "x$CONFIG_SHELL" != x
-then :
+ if test "x$CONFIG_SHELL" != x; then :
export CONFIG_SHELL
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
@@ -251,19 +253,18 @@ esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
exit 255
fi
- if test x$as_have_required = xno
-then :
- printf "%s\n" "$0: This script requires a shell more modern than all"
- printf "%s\n" "$0: the shells that I found on your system."
- if test ${ZSH_VERSION+y} ; then
- printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
+ 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
- printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system,
+ $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."
@@ -290,7 +291,6 @@ as_fn_unset ()
}
as_unset=as_fn_unset
-
# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
@@ -308,14 +308,6 @@ as_fn_exit ()
as_fn_set_status $1
exit $1
} # as_fn_exit
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
# as_fn_mkdir_p
# -------------
@@ -330,7 +322,7 @@ as_fn_mkdir_p ()
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
@@ -339,7 +331,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
+$as_echo X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -378,13 +370,12 @@ as_fn_executable_p ()
# 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 :
+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_nop
+else
as_fn_append ()
{
eval $1=\$$1\$2
@@ -396,27 +387,18 @@ fi # as_fn_append
# 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 :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else $as_nop
+else
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
}
fi # as_fn_arith
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
@@ -428,9 +410,9 @@ 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
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- printf "%s\n" "$as_me: error: $2" >&2
+ $as_echo "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
@@ -457,7 +439,7 @@ as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
+$as_echo X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
@@ -501,7 +483,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
s/-\n.*//
' >$as_me.lineno &&
chmod +x "$as_me.lineno" ||
- { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
# If we had to re-execute with $CONFIG_SHELL, we're ensured to have
# already done that, so ensure we don't try to do so again and fall
@@ -515,10 +497,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
exit
}
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
@@ -532,13 +510,6 @@ case `echo -n x` in #(((((
ECHO_N='-n';;
esac
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-
rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
rm -f conf$$.dir/conf$$.file
@@ -604,26 +575,38 @@ MFLAGS=
MAKEFLAGS=
# Identity of this package.
-PACKAGE_NAME=''
-PACKAGE_TARNAME=''
-PACKAGE_VERSION=''
-PACKAGE_STRING=''
-PACKAGE_BUGREPORT=''
-PACKAGE_URL=''
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
ac_unique_file="conf/confbase.Y"
+ac_header_list=
# Factoring default headers for most tests.
ac_includes_default="\
-#include <stddef.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.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
@@ -637,11 +620,12 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_header_c_list=
ac_subst_vars='LTLIBOBJS
LIBOBJS
CLIENT_LIBS
CLIENT
+EGREP
+GREP
protocols
DAEMON_LIBS
iproutedir
@@ -811,6 +795,8 @@ do
*) ac_optarg=yes ;;
esac
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
case $ac_dashdash$ac_option in
--)
ac_dashdash=yes ;;
@@ -851,9 +837,9 @@ do
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'"
+ as_fn_error $? "invalid feature name: $ac_useropt"
ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
@@ -877,9 +863,9 @@ do
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'"
+ as_fn_error $? "invalid feature name: $ac_useropt"
ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
@@ -1090,9 +1076,9 @@ do
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'"
+ as_fn_error $? "invalid package name: $ac_useropt"
ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
@@ -1106,9 +1092,9 @@ do
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'"
+ as_fn_error $? "invalid package name: $ac_useropt"
ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
@@ -1152,9 +1138,9 @@ Try \`$0 --help' for more information"
*)
# FIXME: should be removed in autoconf 3.0.
- printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
: "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
;;
@@ -1170,7 +1156,7 @@ if test -n "$ac_unrecognized_opts"; then
case $enable_option_checking in
no) ;;
fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
esac
fi
@@ -1234,7 +1220,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_myself" : 'X\(//\)[^/]' \| \
X"$as_myself" : 'X\(//\)$' \| \
X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_myself" |
+$as_echo X"$as_myself" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -1416,9 +1402,9 @@ if test "$ac_init_help" = "recursive"; then
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ 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/ ;;
@@ -1446,8 +1432,7 @@ esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for configure.gnu first; this name is used for a wrapper for
- # Metaconfig's "Configure" on case-insensitive file systems.
+ # Check for guested configure.
if test -f "$ac_srcdir/configure.gnu"; then
echo &&
$SHELL "$ac_srcdir/configure.gnu" --help=recursive
@@ -1455,7 +1440,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
echo &&
$SHELL "$ac_srcdir/configure" --help=recursive
else
- printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
fi || ac_status=$?
cd "$ac_pwd" || { ac_status=$?; break; }
done
@@ -1465,9 +1450,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
configure
-generated by GNU Autoconf 2.69e
+generated by GNU Autoconf 2.69
-Copyright (C) 2020 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@@ -1484,14 +1469,14 @@ fi
ac_fn_c_try_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam
+ 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\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1499,15 +1484,14 @@ printf "%s\n" "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ $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 :
+ } && test -s conftest.$ac_objext; then :
ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
+else
+ $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1523,14 +1507,14 @@ fi
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.beam conftest$ac_exeext
+ 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\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_link") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1538,18 +1522,17 @@ printf "%s\n" "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ $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 ||
test -x conftest$ac_exeext
- }
-then :
+ }; then :
ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
+else
+ $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1576,7 +1559,7 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1584,15 +1567,14 @@ printf "%s\n" "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ $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 :
+ }; then :
ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
+else
+ $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1609,32 +1591,159 @@ fi
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $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 :
+if ac_fn_c_try_compile "$LINENO"; then :
eval "$3=yes"
-else $as_nop
+else
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
+ { $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_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_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $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
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $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
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
# ----------------------------------------------------
# Tries to find if the field MEMBER exists in type AGGR, after including
@@ -1642,17 +1751,16 @@ printf "%s\n" "$ac_res" >&6; }
ac_fn_c_check_member ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
-printf %s "checking for $2.$3... " >&6; }
-if eval test \${$4+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval \${$4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$5
int
-main (void)
+main ()
{
static $2 ac_aggr;
if (ac_aggr.$3)
@@ -1661,15 +1769,14 @@ return 0;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
eval "$4=yes"
-else $as_nop
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$5
int
-main (void)
+main ()
{
static $2 ac_aggr;
if (sizeof ac_aggr.$3)
@@ -1678,93 +1785,96 @@ return 0;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
eval "$4=yes"
-else $as_nop
+else
eval "$4=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
eval ac_res=\$$4
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
+ { $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_member
-# ac_fn_c_try_run LINENO
-# ----------------------
-# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
-# executables *can* be run.
-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
- 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\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$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\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: program exited with status $ac_status" >&5
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+ { $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
- 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
+/* 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. */
-} # ac_fn_c_try_run
-ac_configure_args_raw=
-for ac_arg
-do
- case $ac_arg in
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- as_fn_append ac_configure_args_raw " '$ac_arg'"
-done
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
-case $ac_configure_args_raw in
- *$as_nl*)
- ac_safe_unquote= ;;
- *)
- ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
- ac_unsafe_a="$ac_unsafe_z#~"
- ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
- ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
-esac
+#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 $as_me, which was
-generated by GNU Autoconf 2.69e. Invocation command line was
+generated by GNU Autoconf 2.69. Invocation command line was
- $ $0$ac_configure_args_raw
+ $ $0 $@
_ACEOF
exec 5>>config.log
@@ -1797,12 +1907,8 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- printf "%s\n" "PATH: $as_dir"
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
done
IFS=$as_save_IFS
@@ -1837,7 +1943,7 @@ do
| -silent | --silent | --silen | --sile | --sil)
continue ;;
*\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
case $ac_pass in
1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
@@ -1872,13 +1978,11 @@ done
# 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=$?
- # Sanitize IFS.
- IFS=" "" $as_nl"
# Save into config.log some information that might help in debugging.
{
echo
- printf "%s\n" "## ---------------- ##
+ $as_echo "## ---------------- ##
## Cache variables. ##
## ---------------- ##"
echo
@@ -1889,8 +1993,8 @@ trap 'exit_status=$?
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_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) ;; #(
@@ -1914,7 +2018,7 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;}
)
echo
- printf "%s\n" "## ----------------- ##
+ $as_echo "## ----------------- ##
## Output variables. ##
## ----------------- ##"
echo
@@ -1922,14 +2026,14 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;}
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
+ $as_echo "$ac_var='\''$ac_val'\''"
done | sort
echo
if test -n "$ac_subst_files"; then
- printf "%s\n" "## ------------------- ##
+ $as_echo "## ------------------- ##
## File substitutions. ##
## ------------------- ##"
echo
@@ -1937,15 +2041,15 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;}
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
+ $as_echo "$ac_var='\''$ac_val'\''"
done | sort
echo
fi
if test -s confdefs.h; then
- printf "%s\n" "## ----------- ##
+ $as_echo "## ----------- ##
## confdefs.h. ##
## ----------- ##"
echo
@@ -1953,8 +2057,8 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;}
echo
fi
test "$ac_signal" != 0 &&
- printf "%s\n" "$as_me: caught signal $ac_signal"
- printf "%s\n" "$as_me: exit $exit_status"
+ $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 &&
@@ -1968,48 +2072,63 @@ ac_signal=0
# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -f -r conftest* confdefs.h
-printf "%s\n" "/* confdefs.h */" > confdefs.h
+$as_echo "/* confdefs.h */" > confdefs.h
# Predefined preprocessor variables.
-printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
-printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
-printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
-printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
-printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
-printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
+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
- ac_site_files="$CONFIG_SITE"
+ # 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_files="$prefix/share/config.site $prefix/etc/config.site"
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
else
- ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ 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_files
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
do
- case $ac_site_file in #(
- */*) :
- ;; #(
- *) :
- ac_site_file=./$ac_site_file ;;
-esac
- if test -f "$ac_site_file" && test -r "$ac_site_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
+ 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" \
- || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+ || { { $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
@@ -2019,125 +2138,21 @@ 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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
+ { $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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
>$cache_file
fi
-as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
-as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
-as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
-as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
-as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
-as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
-as_fn_append ac_header_c_list " alloca.h alloca_h HAVE_ALLOCA_H"
-as_fn_append ac_header_c_list " syslog.h syslog_h HAVE_SYSLOG_H"
-
-# Auxiliary files required by this configure script.
-ac_aux_files="install-sh config.guess config.sub"
-
-# Locations in which to look for auxiliary files.
-ac_aux_dir_candidates="${srcdir}/tools"
-
-# Search for a directory containing all of the required auxiliary files,
-# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.
-# If we don't find one directory that contains all the files we need,
-# we report the set of missing files from the *first* directory in
-# $ac_aux_dir_candidates and give up.
-ac_missing_aux_files=""
-ac_first_candidate=:
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in $ac_aux_dir_candidates
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- as_found=:
-
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5
- ac_aux_dir_found=yes
- ac_install_sh=
- for ac_aux in $ac_aux_files
- do
- # As a special case, if "install-sh" is required, that requirement
- # can be satisfied by any of "install-sh", "install.sh", or "shtool",
- # and $ac_install_sh is set appropriately for whichever one is found.
- if test x"$ac_aux" = x"install-sh"
- then
- if test -f "${as_dir}install-sh"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5
- ac_install_sh="${as_dir}install-sh -c"
- elif test -f "${as_dir}install.sh"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5
- ac_install_sh="${as_dir}install.sh -c"
- elif test -f "${as_dir}shtool"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5
- ac_install_sh="${as_dir}shtool install -c"
- else
- ac_aux_dir_found=no
- if $ac_first_candidate; then
- ac_missing_aux_files="${ac_missing_aux_files} install-sh"
- else
- break
- fi
- fi
- else
- if test -f "${as_dir}${ac_aux}"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5
- else
- ac_aux_dir_found=no
- if $ac_first_candidate; then
- ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}"
- else
- break
- fi
- fi
- fi
- done
- if test "$ac_aux_dir_found" = yes; then
- ac_aux_dir="$as_dir"
- break
- fi
- ac_first_candidate=false
-
- as_found=false
-done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else $as_nop
- as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$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.
-if test -f "${ac_aux_dir}config.guess"; then
- ac_config_guess="$SHELL ${ac_aux_dir}config.guess"
-fi
-if test -f "${ac_aux_dir}config.sub"; then
- ac_config_sub="$SHELL ${ac_aux_dir}config.sub"
-fi
-if test -f "$ac_aux_dir/configure"; then
- ac_configure="$SHELL ${ac_aux_dir}configure"
-fi
-
+as_fn_append ac_header_list " alloca.h"
+as_fn_append ac_header_list " syslog.h"
# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
@@ -2148,12 +2163,12 @@ for ac_var in $ac_precious_vars; do
eval ac_new_val=\$ac_env_${ac_var}_value
case $ac_old_set,$ac_new_set in
set,)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ { $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)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ { $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=: ;;
,);;
*)
@@ -2162,24 +2177,24 @@ printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { $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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ { $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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
-printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
-printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;}
+ { $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=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) 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
@@ -2189,12 +2204,11 @@ printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;}
fi
done
if $ac_cache_corrupted; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file'
- and start over" "$LINENO" 5
+ { $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. ##
@@ -2208,83 +2222,103 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_aux_dir=
+for ac_dir in tools "$srcdir"/tools; 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 tools \"$srcdir\"/tools" "$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.
+
# Check whether --enable-client was given.
-if test ${enable_client+y}
-then :
+if test "${enable_client+set}" = set; then :
enableval=$enable_client;
-else $as_nop
+else
enable_client=yes
fi
# Check whether --enable-debug was given.
-if test ${enable_debug+y}
-then :
+if test "${enable_debug+set}" = set; then :
enableval=$enable_debug;
-else $as_nop
+else
enable_debug=no
fi
# Check whether --enable-debug-generated was given.
-if test ${enable_debug_generated+y}
-then :
+if test "${enable_debug_generated+set}" = set; then :
enableval=$enable_debug_generated;
-else $as_nop
+else
enable_debug_generated=no
fi
# Check whether --enable-debug-expensive was given.
-if test ${enable_debug_expensive+y}
-then :
+if test "${enable_debug_expensive+set}" = set; then :
enableval=$enable_debug_expensive;
-else $as_nop
+else
enable_debug_expensive=no
fi
# Check whether --enable-memcheck was given.
-if test ${enable_memcheck+y}
-then :
+if test "${enable_memcheck+set}" = set; then :
enableval=$enable_memcheck;
-else $as_nop
+else
enable_memcheck=yes
fi
# Check whether --enable-pthreads was given.
-if test ${enable_pthreads+y}
-then :
+if test "${enable_pthreads+set}" = set; then :
enableval=$enable_pthreads;
-else $as_nop
+else
enable_pthreads=try
fi
# Check whether --enable-libssh was given.
-if test ${enable_libssh+y}
-then :
+if test "${enable_libssh+set}" = set; then :
enableval=$enable_libssh;
-else $as_nop
+else
enable_libssh=try
fi
# Check whether --enable-mpls-kernel was given.
-if test ${enable_mpls_kernel+y}
-then :
+if test "${enable_mpls_kernel+set}" = set; then :
enableval=$enable_mpls_kernel;
-else $as_nop
+else
enable_mpls_kernel=try
fi
@@ -2292,10 +2326,9 @@ fi
# Check whether --with-protocols was given.
-if test ${with_protocols+y}
-then :
+if test "${with_protocols+set}" = set; then :
withval=$with_protocols;
-else $as_nop
+else
with_protocols="all"
fi
@@ -2303,16 +2336,14 @@ fi
# Check whether --with-sysconfig was given.
-if test ${with_sysconfig+y}
-then :
+if test "${with_sysconfig+set}" = set; then :
withval=$with_sysconfig;
fi
# Check whether --with-runtimedir was given.
-if test ${with_runtimedir+y}
-then :
+if test "${with_runtimedir+set}" = set; then :
withval=$with_runtimedir; runstatedir="$with_runtimedir"
fi
@@ -2320,8 +2351,7 @@ fi
# Check whether --with-iproutedir was given.
-if test ${with_iproutedir+y}
-then :
+if test "${with_iproutedir+set}" = set; then :
withval=$with_iproutedir; given_iproutedir="yes"
fi
@@ -2350,8 +2380,7 @@ exedir=.
# Workaround for older Autoconfs that do not define runstatedir
-if test -z "${runstatedir}"
-then :
+if test -z "${runstatedir}"; then :
runstatedir='${localstatedir}/run'
fi
@@ -2370,12 +2399,11 @@ 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -2383,15 +2411,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2402,11 +2426,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -2415,12 +2439,11 @@ 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -2428,15 +2451,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="gcc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2447,11 +2466,11 @@ fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
if test "x$ac_ct_CC" = x; then
@@ -2459,8 +2478,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ $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
@@ -2473,12 +2492,11 @@ 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -2486,15 +2504,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2505,11 +2519,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -2518,12 +2532,11 @@ 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -2532,19 +2545,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ if as_fn_executable_p "$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"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2560,18 +2569,18 @@ if test $ac_prog_rejected = yes; then
# 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+' '}$@"
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
fi
fi
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -2582,12 +2591,11 @@ if test -z "$CC"; then
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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -2595,15 +2603,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2614,11 +2618,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -2631,12 +2635,11 @@ if test -z "$CC"; then
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -2644,15 +2647,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2663,11 +2662,11 @@ fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -2679,138 +2678,34 @@ done
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
-set dummy ${ac_tool_prefix}clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}clang"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "clang", so it can be a program name with args.
-set dummy clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="clang"
- printf "%s\n" "$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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ $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
fi
-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+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.
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+$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 -version; do
+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\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_compiler $ac_option >&5") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -2820,7 +2715,7 @@ printf "%s\n" "$ac_try_echo"; } >&5
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
@@ -2828,7 +2723,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
@@ -2840,9 +2735,9 @@ 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.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-printf %s "checking whether the C compiler works... " >&6; }
-ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+{ $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.*"
@@ -2863,12 +2758,11 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_link_default") 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
+ $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,
@@ -2885,7 +2779,7 @@ do
# certainly right.
break;;
*.* )
- if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
then :; else
ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
fi
@@ -2901,46 +2795,44 @@ do
done
test "$ac_cv_exeext" = no && ac_cv_exeext=
-else $as_nop
+else
ac_file=''
fi
-if test -z "$ac_file"
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-printf "%s\n" "$as_me: failed program was:" >&5
+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
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $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_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-printf %s "checking for C compiler default output file name... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-printf "%s\n" "$ac_file" >&6; }
+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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-printf %s "checking for suffix of executables... " >&6; }
+{ $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\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
+ $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
@@ -2954,15 +2846,15 @@ for ac_file in conftest.exe conftest conftest.*; do
* ) break;;
esac
done
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-printf "%s\n" "$ac_cv_exeext" >&6; }
+{ $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
@@ -2971,7 +2863,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main (void)
+main ()
{
FILE *f = fopen ("conftest.out", "w");
return ferror (f) || fclose (f) != 0;
@@ -2983,8 +2875,8 @@ _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.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-printf %s "checking whether we are cross compiling... " >&6; }
+{ $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
@@ -2992,10 +2884,10 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ $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
@@ -3003,40 +2895,39 @@ printf "%s\n" "$ac_try_echo"; } >&5
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ $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
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot run C compiled programs.
+ { { $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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-printf "%s\n" "$cross_compiling" >&6; }
+{ $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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-printf %s "checking for suffix of object files... " >&6; }
-if test ${ac_cv_objext+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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 (void)
+main ()
{
;
@@ -3050,12 +2941,11 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
+$as_echo "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>&5
ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
+ $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
@@ -3064,32 +2954,31 @@ then :
break;;
esac
done
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
+else
+ $as_echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-printf "%s\n" "$ac_cv_objext" >&6; }
+{ $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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
-printf %s "checking whether the compiler supports GNU C... " >&6; }
-if test ${ac_cv_c_compiler_gnu+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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 (void)
+main ()
{
#ifndef __GNUC__
choke me
@@ -3099,33 +2988,29 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
ac_compiler_gnu=yes
-else $as_nop
+else
ac_compiler_gnu=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
+{ $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+y}
+ac_test_CFLAGS=${CFLAGS+set}
ac_save_CFLAGS=$CFLAGS
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-printf %s "checking whether $CC accepts -g... " >&6; }
-if test ${ac_cv_prog_cc_g+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -3134,60 +3019,57 @@ else $as_nop
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_prog_cc_g=yes
-else $as_nop
+else
CFLAGS=""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
-else $as_nop
+else
ac_c_werror_flag=$ac_save_c_werror_flag
CFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_prog_cc_g=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_c_werror_flag=$ac_save_c_werror_flag
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
-if test $ac_test_CFLAGS; then
+{ $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
@@ -3202,254 +3084,790 @@ else
CFLAGS=
fi
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
-printf %s "checking for $CC option to enable C11 features... " >&6; }
-if test ${ac_cv_prog_cc_c11+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c11=no
+{ $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 <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <wchar.h>
#include <stdio.h>
-
-// Check varargs macros. These examples are taken from C99 6.10.3.5.
-#define debug(...) fprintf (stderr, __VA_ARGS__)
-#define showlist(...) puts (#__VA_ARGS__)
-#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
-static void
-test_varargs_macros (void)
+struct stat;
+/* 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;
{
- int x = 1234;
- int y = 5678;
- debug ("Flag");
- debug ("X = %d\n", x);
- showlist (The first, second, and third items.);
- report (x>y, "x is %d but y is %d", x, y);
+ 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;
}
-// Check long long types.
-#define BIG64 18446744073709551615ull
-#define BIG32 4294967295ul
-#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
-#if !BIG_OK
- your preprocessor is broken;
-#endif
-#if BIG_OK
-#else
- your preprocessor is broken;
-#endif
-static long long int bignum = -9223372036854775807LL;
-static unsigned long long int ubignum = BIG64;
+/* 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];
-struct incomplete_array
+/* 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 ()
{
- int datasize;
- double data[];
-};
+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
-struct named_init {
- int number;
- const wchar_t *name;
- double average;
-};
+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 :
-typedef const char *ccp;
+fi
-static inline int
-test_restrict (ccp restrict text)
+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 library containing clock_gettime" >&5
+$as_echo_n "checking for library containing clock_gettime... " >&6; }
+if ${ac_cv_search_clock_gettime+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$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 clock_gettime ();
+int
+main ()
{
- // See if C++-style comments work.
- // Iterate through items via the restricted pointer.
- // Also check for declarations in for loops.
- for (unsigned int i = 0; *(text+i) != '\0'; ++i)
- continue;
+return clock_gettime ();
+ ;
return 0;
}
+_ACEOF
+for ac_lib in '' rt posix4; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_clock_gettime=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_clock_gettime+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_clock_gettime+:} false; then :
-// Check varargs and va_copy.
-static bool
-test_varargs (const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- va_list args_copy;
- va_copy (args_copy, args);
+else
+ ac_cv_search_clock_gettime=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+$as_echo "$ac_cv_search_clock_gettime" >&6; }
+ac_res=$ac_cv_search_clock_gettime
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
- const char *str = "";
- int number = 0;
- float fnumber = 0;
+else
+ as_fn_error $? "Function clock_gettime not available." "$LINENO" 5
- while (*format)
- {
- switch (*format++)
- {
- case 's': // string
- str = va_arg (args_copy, const char *);
- break;
- case 'd': // int
- number = va_arg (args_copy, int);
- break;
- case 'f': // float
- fnumber = va_arg (args_copy, double);
- break;
- default:
- break;
- }
- }
- va_end (args_copy);
- va_end (args);
+fi
- return *str && number && fnumber;
-}
-// Check _Alignas.
-char _Alignas (double) aligned_as_double;
-char _Alignas (0) no_special_alignment;
-extern char aligned_as_int;
-char _Alignas (0) _Alignas (int) aligned_as_int;
-
-// Check _Alignof.
-enum
-{
- int_alignment = _Alignof (int),
- int_array_alignment = _Alignof (int[100]),
- char_alignment = _Alignof (char)
-};
-_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
-// Check _Noreturn.
-int _Noreturn does_not_return (void) { for (;;) continue; }
+# 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
-// Check _Static_assert.
-struct test_static_assert
-{
- int x;
- _Static_assert (sizeof (int) <= sizeof (long int),
- "_Static_assert does not work in struct");
- long int y;
-};
+{ $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
-// Check UTF-8 literals.
-#define u8 syntax error!
-char const utf8_literal[] = u8"happens to be ASCII" "another string";
+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
-// Check duplicate typedefs.
-typedef long *long_ptr;
-typedef long int *long_ptr;
-typedef long_ptr long_ptr;
-// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
-struct anonymous
-{
- union {
- struct { int i; int j; };
- struct { int k; long int l; } w;
- };
- int m;
-} v1;
+{ $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
+
+
+
+# Store this value because ac_test_CFLAGS is overwritten by AC_PROG_CC
+if test "$ac_test_CFLAGS" != set ; then
+ bird_cflags_default=yes
+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 as_fn_executable_p "$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 as_fn_executable_p "$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 as_fn_executable_p "$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 as_fn_executable_p "$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 as_fn_executable_p "$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 as_fn_executable_p "$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 (void)
+main ()
{
+#ifndef __GNUC__
+ choke me
+#endif
- // Check bool.
- _Bool success = false;
+ ;
+ 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
- // Check restrict.
- if (test_restrict ("String literal") == 0)
- success = true;
- char *restrict newvar = "Another string";
+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. */
- // Check varargs.
- success &= test_varargs ("s, d' f .", "string", 65, 34.234);
- test_varargs_macros ();
+int
+main ()
+{
- // Check flexible array members.
- struct incomplete_array *ia =
- malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
- ia->datasize = 10;
- for (int i = 0; i < ia->datasize; ++i)
- ia->data[i] = i * 1.234;
+ ;
+ 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. */
- // Check named initializers.
- struct named_init ni = {
- .number = 34,
- .name = L"Test wide string",
- .average = 543.34343,
- };
+int
+main ()
+{
- ni.number = 58;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
- int dynamic_array[ni.number];
- dynamic_array[ni.number - 1] = 543;
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
- // work around unused variable warnings
- return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
- || dynamic_array[ni.number - 1] != 543);
+int
+main ()
+{
- v1.i = 2;
- v1.w.k = 5;
- _Static_assert ((offsetof (struct anonymous, i)
- == offsetof (struct anonymous, w.k)),
- "Anonymous union alignment botch");
+ ;
+ 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>
+struct stat;
+/* 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 '' -std=gnu11
+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_c11=$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 conftest.beam
- test "x$ac_cv_prog_cc_c11" != "xno" && break
+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
-ac_prog_cc_stdc_options=
-case "x$ac_cv_prog_cc_c11" in
+case "x$ac_cv_prog_cc_c89" in
x)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; } ;;
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
xno)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; } ;;
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
*)
- ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c11"
- CC=$CC$ac_prog_cc_stdc_options
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&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_c11" != xno
-then :
- ac_prog_cc_stdc=c11
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
-printf %s "checking for $CC option to enable C99 features... " >&6; }
-if test ${ac_cv_prog_cc_c99+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+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
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_cv_prog_cc_c99=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdbool.h>
-#include <stddef.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdio.h>
@@ -3509,7 +3927,7 @@ test_restrict (ccp restrict text)
}
// Check varargs and va_copy.
-static bool
+static void
test_varargs (const char *format, ...)
{
va_list args;
@@ -3517,9 +3935,9 @@ test_varargs (const char *format, ...)
va_list args_copy;
va_copy (args_copy, args);
- const char *str = "";
- int number = 0;
- float fnumber = 0;
+ const char *str;
+ int number;
+ float fnumber;
while (*format)
{
@@ -3540,11 +3958,10 @@ test_varargs (const char *format, ...)
}
va_end (args_copy);
va_end (args);
-
- return *str && number && fnumber;
}
+
int
-main (void)
+main ()
{
// Check bool.
@@ -3556,7 +3973,7 @@ main (void)
char *restrict newvar = "Another string";
// Check varargs.
- success &= test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs ("s, d' f .", "string", 65, 34.234);
test_varargs_macros ();
// Check flexible array members.
@@ -3586,14 +4003,13 @@ main (void)
return 0;
}
_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc1x -qlanglvl=extc99
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
do
CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
+ if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_prog_cc_c99=$ac_arg
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
+rm -f core conftest.err conftest.$ac_objext
test "x$ac_cv_prog_cc_c99" != "xno" && break
done
rm -f conftest.$ac_ext
@@ -3601,293 +4017,33 @@ CC=$ac_save_CC
fi
# AC_CACHE_VAL
-ac_prog_cc_stdc_options=
case "x$ac_cv_prog_cc_c99" in
x)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; } ;;
- xno)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; } ;;
- *)
- ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c99"
- CC=$CC$ac_prog_cc_stdc_options
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c99" != xno
-then :
- ac_prog_cc_stdc=c99
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
-printf %s "checking for $CC option to enable C89 features... " >&6; }
-if test ${ac_cv_prog_cc_c89+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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>
-struct stat;
-/* 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 (void)
-{
-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 conftest.beam
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-ac_prog_cc_stdc_options=
-case "x$ac_cv_prog_cc_c89" in
- x)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; } ;;
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
xno)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; } ;;
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
*)
- ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c89"
- CC=$CC$ac_prog_cc_stdc_options
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } ;;
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
esac
-if test "x$ac_cv_prog_cc_c89" != xno
-then :
- ac_prog_cc_stdc=c89
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
-else $as_nop
- ac_prog_cc_stdc=no
- ac_cv_prog_cc_stdc=no
-fi
-
-fi
+if test "x$ac_cv_prog_cc_c99" != 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
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
-printf %s "checking for library containing clock_gettime... " >&6; }
-if test ${ac_cv_search_clock_gettime+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$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. */
-char clock_gettime ();
-int
-main (void)
-{
-return clock_gettime ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' rt posix4
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_clock_gettime=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_clock_gettime+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_clock_gettime+y}
-then :
-
-else $as_nop
- ac_cv_search_clock_gettime=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
-printf "%s\n" "$ac_cv_search_clock_gettime" >&6; }
-ac_res=$ac_cv_search_clock_gettime
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-else $as_nop
- as_fn_error $? "Function clock_gettime not available." "$LINENO" 5
-
-fi
-
-
-
-
-
- # 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
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-printf %s "checking build system type... " >&6; }
-if test ${ac_cv_build+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-printf "%s\n" "$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
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-printf %s "checking host system type... " >&6; }
-if test ${ac_cv_host+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-printf "%s\n" "$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
-
-
-
-# Store this value because ac_test_CFLAGS is overwritten by AC_PROG_CC
-if test "$ac_test_CFLAGS" != set ; then
- bird_cflags_default=yes
-fi
-
-
if test -z "$GCC" ; then
as_fn_error $? "This program requires the GNU C Compiler." "$LINENO" 5
fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _Thread_local is known" >&5
-printf %s "checking whether _Thread_local is known... " >&6; }
-if test ${bird_cv_thread_local+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether _Thread_local is known" >&5
+$as_echo_n "checking whether _Thread_local is known... " >&6; }
+if ${bird_cv_thread_local+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -3895,7 +4051,7 @@ else $as_nop
_Thread_local static int x = 42;
int
-main (void)
+main ()
{
@@ -3904,22 +4060,21 @@ main (void)
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
bird_cv_thread_local=yes
-else $as_nop
+else
bird_cv_thread_local=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_thread_local" >&5
-printf "%s\n" "$bird_cv_thread_local" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_thread_local" >&5
+$as_echo "$bird_cv_thread_local" >&6; }
if test "$bird_cv_thread_local" = yes ; then
-printf "%s\n" "#define HAVE_THREAD_LOCAL 1" >>confdefs.h
+$as_echo "#define HAVE_THREAD_LOCAL 1" >>confdefs.h
fi
@@ -3928,19 +4083,18 @@ if test "$enable_pthreads" != no ; then
bird_tmp_cflags="$CFLAGS"
CFLAGS="$CFLAGS -pthread"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads are available" >&5
-printf %s "checking whether POSIX threads are available... " >&6; }
-if test ${bird_cv_lib_pthreads+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads are available" >&5
+$as_echo_n "checking whether POSIX threads are available... " >&6; }
+if ${bird_cv_lib_pthreads+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <pthread.h>
int
-main (void)
+main ()
{
pthread_t pt;
@@ -3954,27 +4108,26 @@ main (void)
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
bird_cv_lib_pthreads=yes
-else $as_nop
+else
bird_cv_lib_pthreads=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_pthreads" >&5
-printf "%s\n" "$bird_cv_lib_pthreads" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_pthreads" >&5
+$as_echo "$bird_cv_lib_pthreads" >&6; }
CFLAGS="$bird_tmp_cflags"
if test "$bird_cv_lib_pthreads" = yes ; then
-printf "%s\n" "#define USE_PTHREADS 1" >>confdefs.h
+$as_echo "#define USE_PTHREADS 1" >>confdefs.h
CFLAGS="$CFLAGS -pthread"
LDFLAGS="$LDFLAGS -pthread"
@@ -3996,37 +4149,35 @@ if test "$bird_cflags_default" = yes ; then
bird_tmp_cflags="$CFLAGS"
CFLAGS="-Wall -Wno-pointer-sign"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-pointer-sign" >&5
-printf %s "checking whether CC supports -Wno-pointer-sign... " >&6; }
-if test ${bird_cv_c_option_wno_pointer_sign+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-pointer-sign" >&5
+$as_echo_n "checking whether CC supports -Wno-pointer-sign... " >&6; }
+if ${bird_cv_c_option_wno_pointer_sign+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
bird_cv_c_option_wno_pointer_sign=yes
-else $as_nop
+else
bird_cv_c_option_wno_pointer_sign=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_pointer_sign" >&5
-printf "%s\n" "$bird_cv_c_option_wno_pointer_sign" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_pointer_sign" >&5
+$as_echo "$bird_cv_c_option_wno_pointer_sign" >&6; }
CFLAGS="$bird_tmp_cflags"
@@ -4034,37 +4185,35 @@ printf "%s\n" "$bird_cv_c_option_wno_pointer_sign" >&6; }
bird_tmp_cflags="$CFLAGS"
CFLAGS="-Wall -Wextra -Wno-missing-field-initializers"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-missing-field-initializers" >&5
-printf %s "checking whether CC supports -Wno-missing-field-initializers... " >&6; }
-if test ${bird_cv_c_option_wno_missing_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-missing-field-initializers" >&5
+$as_echo_n "checking whether CC supports -Wno-missing-field-initializers... " >&6; }
+if ${bird_cv_c_option_wno_missing_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
bird_cv_c_option_wno_missing_init=yes
-else $as_nop
+else
bird_cv_c_option_wno_missing_init=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_missing_init" >&5
-printf "%s\n" "$bird_cv_c_option_wno_missing_init" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_missing_init" >&5
+$as_echo "$bird_cv_c_option_wno_missing_init" >&6; }
CFLAGS="$bird_tmp_cflags"
@@ -4076,38 +4225,36 @@ printf "%s\n" "$bird_cv_c_option_wno_missing_init" >&6; }
CFLAGS="-flto"
LDFLAGS="-flto=4"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether link time optimizer is available" >&5
-printf %s "checking whether link time optimizer is available... " >&6; }
-if test ${bird_cv_c_lto+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether link time optimizer is available" >&5
+$as_echo_n "checking whether link time optimizer is available... " >&6; }
+if ${bird_cv_c_lto+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
bird_cv_c_lto=yes
-else $as_nop
+else
bird_cv_c_lto=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_lto" >&5
-printf "%s\n" "$bird_cv_c_lto" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_lto" >&5
+$as_echo "$bird_cv_c_lto" >&6; }
CFLAGS="$bird_tmp_cflags"
LDFLAGS="$bird_tmp_ldflags"
@@ -4135,51 +4282,55 @@ printf "%s\n" "$bird_cv_c_lto" >&6; }
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CFLAGS" >&5
-printf %s "checking CFLAGS... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CFLAGS" >&5
-printf "%s\n" "$CFLAGS" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking CFLAGS" >&5
+$as_echo_n "checking CFLAGS... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CFLAGS" >&5
+$as_echo "$CFLAGS" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDFLAGS" >&5
-printf %s "checking LDFLAGS... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDFLAGS" >&5
-printf "%s\n" "$LDFLAGS" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LDFLAGS" >&5
+$as_echo_n "checking LDFLAGS... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDFLAGS" >&5
+$as_echo "$LDFLAGS" >&6; }
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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-printf %s "checking how to run the C preprocessor... " >&6; }
+{ $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 test ${ac_cv_prog_CPP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- # Double quotes because $CC needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp
+ 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. */
-#include <limits.h>
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
Syntax error
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
+if ac_fn_c_try_cpp "$LINENO"; then :
-else $as_nop
+else
# Broken: fails on valid input.
continue
fi
@@ -4191,11 +4342,10 @@ rm -f conftest.err conftest.i conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
+if ac_fn_c_try_cpp "$LINENO"; then :
# Broken: success on invalid input.
continue
-else $as_nop
+else
# Passes both tests.
ac_preproc_ok=:
break
@@ -4205,8 +4355,7 @@ 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 :
+if $ac_preproc_ok; then :
break
fi
@@ -4218,24 +4367,29 @@ fi
else
ac_cv_prog_CPP=$CPP
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-printf "%s\n" "$CPP" >&6; }
+{ $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. */
-#include <limits.h>
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
Syntax error
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
+if ac_fn_c_try_cpp "$LINENO"; then :
-else $as_nop
+else
# Broken: fails on valid input.
continue
fi
@@ -4247,11 +4401,10 @@ rm -f conftest.err conftest.i conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"
-then :
+if ac_fn_c_try_cpp "$LINENO"; then :
# Broken: success on invalid input.
continue
-else $as_nop
+else
# Passes both tests.
ac_preproc_ok=:
break
@@ -4261,12 +4414,11 @@ 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 :
+if $ac_preproc_ok; then :
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+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
@@ -4277,8 +4429,7 @@ 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
-
- # Find a good install program. We prefer a C program (faster),
+# 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
@@ -4292,25 +4443,20 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# 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.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-printf %s "checking for a BSD-compatible install... " >&6; }
+{ $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 test ${ac_cv_path_install+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+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
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- # Account for fact that we put trailing slashes in our PATH walk.
-case $as_dir in #((
- ./ | /[cC]/* | \
+ 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/* ) ;;
@@ -4320,13 +4466,13 @@ case $as_dir in #((
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then
+ if as_fn_executable_p "$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
+ 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
+ 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
@@ -4334,12 +4480,12 @@ case $as_dir in #((
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/" &&
+ 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"
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
break 3
fi
fi
@@ -4355,7 +4501,7 @@ IFS=$as_save_IFS
rm -rf conftest.one conftest.two conftest.dir
fi
- if test ${ac_cv_path_install+y}; then
+ 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
@@ -4365,8 +4511,8 @@ fi
INSTALL=$ac_install_sh
fi
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-printf "%s\n" "$INSTALL" >&6; }
+{ $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.
@@ -4379,12 +4525,11 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -4392,15 +4537,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4411,11 +4552,11 @@ fi
fi
RANLIB=$ac_cv_prog_RANLIB
if test -n "$RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-printf "%s\n" "$RANLIB" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -4424,12 +4565,11 @@ 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
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -4437,15 +4577,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4456,11 +4592,11 @@ fi
fi
ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
if test -n "$ac_ct_RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-printf "%s\n" "$ac_ct_RANLIB" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
if test "x$ac_ct_RANLIB" = x; then
@@ -4468,8 +4604,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ $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
@@ -4480,12 +4616,11 @@ fi
# Extract the first word of "flex", so it can be a program name with args.
set dummy flex; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_FLEX+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $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
@@ -4493,15 +4628,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_FLEX="flex"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4512,22 +4643,21 @@ fi
fi
FLEX=$ac_cv_prog_FLEX
if test -n "$FLEX"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5
-printf "%s\n" "$FLEX" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5
+$as_echo "$FLEX" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
# Extract the first word of "bison", so it can be a program name with args.
set dummy bison; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_BISON+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_BISON+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
if test -n "$BISON"; then
ac_cv_prog_BISON="$BISON" # Let the user override the test.
else
@@ -4535,15 +4665,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_BISON="bison"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4554,11 +4680,11 @@ fi
fi
BISON=$ac_cv_prog_BISON
if test -n "$BISON"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5
-printf "%s\n" "$BISON" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5
+$as_echo "$BISON" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -4566,12 +4692,11 @@ for ac_prog in gm4 m4
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_M4+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_M4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
if test -n "$M4"; then
ac_cv_prog_M4="$M4" # Let the user override the test.
else
@@ -4579,15 +4704,11 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
+ test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_prog_M4="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4598,11 +4719,11 @@ fi
fi
M4=$ac_cv_prog_M4
if test -n "$M4"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
-printf "%s\n" "$M4" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
+$as_echo "$M4" >&6; }
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
@@ -4614,8 +4735,8 @@ test -z "$FLEX" && as_fn_error $? "Flex is missing." "$LINENO" 5
test -z "$BISON" && as_fn_error $? "Bison is missing." "$LINENO" 5
test -z "$M4" && as_fn_error $? "M4 is missing." "$LINENO" 5
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking bison version" >&5
-printf %s "checking bison version... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking bison version" >&5
+$as_echo_n "checking bison version... " >&6; }
BISON_VERSION=`bison --version | ( read line; echo ${line##* } )`
case "$BISON_VERSION" in
@@ -4635,8 +4756,8 @@ printf %s "checking bison version... " >&6; }
;;
esac
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON_VERSION" >&5
-printf "%s\n" "$BISON_VERSION" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON_VERSION" >&5
+$as_echo "$BISON_VERSION" >&6; }
if test "$bird_bison_synclines" = yes && test "$enable_debug_generated" = no; then
M4FLAGS="$M4FLAGS -s"
fi
@@ -4705,23 +4826,25 @@ else
esac
sysdesc=$srcdir/sysdep/cf/$sysdesc.h
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which OS configuration should we use" >&5
-printf %s "checking which OS configuration should we use... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $sysdesc" >&5
-printf "%s\n" "$sysdesc" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which OS configuration should we use" >&5
+$as_echo_n "checking which OS configuration should we use... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sysdesc" >&5
+$as_echo "$sysdesc" >&6; }
if ! test -f $sysdesc ; then
as_fn_error $? "The system configuration file is missing." "$LINENO" 5
fi
sysname=`echo $sysdesc | sed 's/\.h$//'`
-printf "%s\n" "#define SYSCONF_INCLUDE \"$sysdesc\"" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define SYSCONF_INCLUDE "$sysdesc"
+_ACEOF
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking system-dependent directories" >&5
-printf %s "checking system-dependent directories... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking system-dependent directories" >&5
+$as_echo_n "checking system-dependent directories... " >&6; }
sysdep_dirs="`sed <$sysdesc '/^Link: /!d;s/^Link: \(.*\)$/\1/' | tr '\012' ' '`"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $sysdep_dirs" >&5
-printf "%s\n" "$sysdep_dirs" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sysdep_dirs" >&5
+$as_echo "$sysdep_dirs" >&6; }
if test "$with_iproutedir" = no ; then with_iproutedir= ; fi
@@ -4739,19 +4862,18 @@ DAEMON_LIBS=
if test "$enable_libssh" != no ; then
ac_fn_c_check_header_compile "$LINENO" "libssh/libssh.h" "ac_cv_header_libssh_libssh_h" "
"
-if test "x$ac_cv_header_libssh_libssh_h" = xyes
-then :
+if test "x$ac_cv_header_libssh_libssh_h" = xyes; then :
true
-else $as_nop
+else
fail=yes
fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ssh_connect in -lssh" >&5
-printf %s "checking for ssh_connect in -lssh... " >&6; }
-if test ${ac_cv_lib_ssh_ssh_connect+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ssh_connect in -lssh" >&5
+$as_echo_n "checking for ssh_connect in -lssh... " >&6; }
+if ${ac_cv_lib_ssh_ssh_connect+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lssh $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4760,38 +4882,39 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 ssh_connect ();
int
-main (void)
+main ()
{
return ssh_connect ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_ssh_ssh_connect=yes
-else $as_nop
+else
ac_cv_lib_ssh_ssh_connect=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssh_ssh_connect" >&5
-printf "%s\n" "$ac_cv_lib_ssh_ssh_connect" >&6; }
-if test "x$ac_cv_lib_ssh_ssh_connect" = xyes
-then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssh_ssh_connect" >&5
+$as_echo "$ac_cv_lib_ssh_ssh_connect" >&6; }
+if test "x$ac_cv_lib_ssh_ssh_connect" = xyes; then :
true
-else $as_nop
+else
fail=yes
fi
if test "$fail" != yes ; then
-printf "%s\n" "#define HAVE_LIBSSH 1" >>confdefs.h
+$as_echo "#define HAVE_LIBSSH 1" >>confdefs.h
DAEMON_LIBS="-lssh $DAEMON_LIBS"
enable_libssh=yes
@@ -4806,12 +4929,11 @@ fi
if test "$enable_mpls_kernel" != no ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Linux MPLS headers" >&5
-printf %s "checking for Linux MPLS headers... " >&6; }
-if test ${bird_cv_mpls_kernel+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux MPLS headers" >&5
+$as_echo_n "checking for Linux MPLS headers... " >&6; }
+if ${bird_cv_mpls_kernel+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -4824,7 +4946,7 @@ else $as_nop
void t(int arg);
int
-main (void)
+main ()
{
t(AF_MPLS);
@@ -4841,24 +4963,23 @@ main (void)
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
bird_cv_mpls_kernel=yes
-else $as_nop
+else
bird_cv_mpls_kernel=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_mpls_kernel" >&5
-printf "%s\n" "$bird_cv_mpls_kernel" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_mpls_kernel" >&5
+$as_echo "$bird_cv_mpls_kernel" >&6; }
if test "$bird_cv_mpls_kernel" = yes ; then
-printf "%s\n" "#define HAVE_MPLS_KERNEL 1" >>confdefs.h
+$as_echo "#define HAVE_MPLS_KERNEL 1" >>confdefs.h
elif test "$enable_mpls_kernel" = yes ; then
as_fn_error $? "Kernel MPLS support not found." "$LINENO" 5
@@ -4888,14 +5009,14 @@ fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking protocols" >&5
-printf %s "checking protocols... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking protocols" >&5
+$as_echo_n "checking protocols... " >&6; }
protocols=`echo "$with_protocols" | sed 's/,/ /g'`
if test "$protocols" = no ; then protocols= ; fi
for a in $protocols ; do
if ! test -f $srcdir/proto/$a/Makefile ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5
-printf "%s\n" "failed" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
as_fn_error $? "Requested protocol $a not found" "$LINENO" 5
fi
cat >>confdefs.h <<_ACEOF
@@ -4903,8 +5024,8 @@ printf "%s\n" "failed" >&6; }
_ACEOF
done
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5
-printf "%s\n" "ok" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
case $sysdesc in
@@ -4915,63 +5036,323 @@ case $sysdesc in
"
-if test "x$ac_cv_header_linux_rtnetlink_h" = xyes
-then :
+if test "x$ac_cv_header_linux_rtnetlink_h" = xyes; then :
-else $as_nop
+else
as_fn_error $? "Appropriate version of Linux kernel headers not found." "$LINENO" 5
fi
+
;;
esac
-ac_header= ac_cache=
-for ac_item in $ac_header_c_list
+
+{ $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"
+ as_fn_executable_p "$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
- if test $ac_cache; then
- ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
- if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
- printf "%s\n" "#define $ac_item 1" >> confdefs.h
+ 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"
+ as_fn_executable_p "$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
- ac_header= ac_cache=
- elif test $ac_header; then
- ac_cache=$ac_item
- else
- ac_header=$ac_item
+ # 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 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 $ac_header_list
+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
+
+
+
-printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h
-printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h
-printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
+ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mman_h" = xyes; then :
+$as_echo "#define HAVE_MMAP 1" >>confdefs.h
+fi
ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes
-then :
+if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then :
-printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_SA_LEN 1" >>confdefs.h
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_SA_LEN 1
+_ACEOF
fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
-printf %s "checking whether byte ordering is bigendian... " >&6; }
-if test ${ac_cv_c_bigendian+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_cv_c_bigendian=unknown
# See if we're dealing with a universal compiler.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4982,8 +5363,7 @@ else $as_nop
typedef int dummy;
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
# Check for potential -arch flags. It is not universal unless
# there are at least two -arch flags with different values.
@@ -5007,7 +5387,7 @@ then :
fi
done
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
if test $ac_cv_c_bigendian = unknown; then
# See if sys/param.h defines the BYTE_ORDER macro.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5016,7 +5396,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
#include <sys/param.h>
int
-main (void)
+main ()
{
#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
&& defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
@@ -5028,8 +5408,7 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
# It does; now see whether it defined to BIG_ENDIAN or not.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5037,7 +5416,7 @@ then :
#include <sys/param.h>
int
-main (void)
+main ()
{
#if BYTE_ORDER != BIG_ENDIAN
not big endian
@@ -5047,15 +5426,14 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_c_bigendian=yes
-else $as_nop
+else
ac_cv_c_bigendian=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
if test $ac_cv_c_bigendian = unknown; then
# See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
@@ -5064,7 +5442,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
#include <limits.h>
int
-main (void)
+main ()
{
#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
bogus endian macros
@@ -5074,15 +5452,14 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
# It does; now see whether it defined to _BIG_ENDIAN or not.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <limits.h>
int
-main (void)
+main ()
{
#ifndef _BIG_ENDIAN
not big endian
@@ -5092,33 +5469,31 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_c_bigendian=yes
-else $as_nop
+else
ac_cv_c_bigendian=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
if test $ac_cv_c_bigendian = unknown; then
# Compile a test program.
- if test "$cross_compiling" = yes
-then :
+ if test "$cross_compiling" = yes; then :
# Try to guess by grepping values from an object file.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-unsigned short int ascii_mm[] =
+short int ascii_mm[] =
{ 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
- unsigned short int ascii_ii[] =
+ short int ascii_ii[] =
{ 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
int use_ascii (int i) {
return ascii_mm[i] + ascii_ii[i];
}
- unsigned short int ebcdic_ii[] =
+ short int ebcdic_ii[] =
{ 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
- unsigned short int ebcdic_mm[] =
+ short int ebcdic_mm[] =
{ 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
int use_ebcdic (int i) {
return ebcdic_mm[i] + ebcdic_ii[i];
@@ -5126,15 +5501,14 @@ unsigned short int ascii_mm[] =
extern int foo;
int
-main (void)
+main ()
{
return use_ascii (foo) == use_ebcdic (foo);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
ac_cv_c_bigendian=yes
fi
@@ -5147,13 +5521,13 @@ then :
fi
fi
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-else $as_nop
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
int
-main (void)
+main ()
{
/* Are we little or big endian? From Harbison&Steele. */
@@ -5169,10 +5543,9 @@ main (void)
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"
-then :
+if ac_fn_c_try_run "$LINENO"; then :
ac_cv_c_bigendian=no
-else $as_nop
+else
ac_cv_c_bigendian=yes
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
@@ -5181,20 +5554,20 @@ fi
fi
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
-printf "%s\n" "$ac_cv_c_bigendian" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
case $ac_cv_c_bigendian in #(
yes)
-printf "%s\n" "#define CPU_BIG_ENDIAN 1" >>confdefs.h
+$as_echo "#define CPU_BIG_ENDIAN 1" >>confdefs.h
;; #(
no)
-printf "%s\n" "#define CPU_LITTLE_ENDIAN 1" >>confdefs.h
+$as_echo "#define CPU_LITTLE_ENDIAN 1" >>confdefs.h
;; #(
universal)
-printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
;; #(
*)
@@ -5204,12 +5577,11 @@ printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glob.h" >&5
-printf %s "checking for glob.h... " >&6; }
-if test ${bird_cv_lib_glob+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for glob.h" >&5
+$as_echo_n "checking for glob.h... " >&6; }
+if ${bird_cv_lib_glob+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5218,7 +5590,7 @@ else $as_nop
#include <stdlib.h>
int
-main (void)
+main ()
{
glob(NULL, 0, NULL, NULL);
@@ -5227,10 +5599,9 @@ main (void)
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
bird_cv_lib_glob=yes
-else $as_nop
+else
bird_tmp_libs="$LIBS"
LIBS="$LIBS -landroid-glob"
@@ -5242,7 +5613,7 @@ else $as_nop
#include <stdlib.h>
int
-main (void)
+main ()
{
glob(NULL, 0, NULL, NULL);
@@ -5251,25 +5622,24 @@ main (void)
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
bird_cv_lib_glob=-landroid-glob
-else $as_nop
+else
bird_cv_lib_glob=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS="$bird_tmp_libs"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_glob" >&5
-printf "%s\n" "$bird_cv_lib_glob" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_glob" >&5
+$as_echo "$bird_cv_lib_glob" >&6; }
if test "$bird_cv_lib_glob" = no ; then
as_fn_error $? "glob.h not found." "$LINENO" 5
@@ -5278,18 +5648,17 @@ elif test "$bird_cv_lib_glob" != yes ; then
fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for syslog lib flags" >&5
-printf %s "checking for syslog lib flags... " >&6; }
-if test ${bird_cv_lib_log+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syslog lib flags" >&5
+$as_echo_n "checking for syslog lib flags... " >&6; }
+if ${bird_cv_lib_log+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/syslog.h>
int
-main (void)
+main ()
{
syslog(0, "");
@@ -5298,10 +5667,9 @@ main (void)
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
bird_cv_lib_log=yes
-else $as_nop
+else
bird_tmp_libs="$LIBS"
LIBS="$LIBS -llog"
@@ -5310,7 +5678,7 @@ else $as_nop
#include <sys/syslog.h>
int
-main (void)
+main ()
{
syslog(0, "");
@@ -5319,25 +5687,24 @@ main (void)
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
bird_cv_lib_log=-llog
-else $as_nop
+else
bird_cv_lib_log=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS="$bird_tmp_libs"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_log" >&5
-printf "%s\n" "$bird_cv_lib_log" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_log" >&5
+$as_echo "$bird_cv_lib_log" >&6; }
if test "$bird_cv_lib_log" = no ; then
as_fn_error $? "don't know how to link syslog." "$LINENO" 5
@@ -5345,9 +5712,32 @@ elif test "$bird_cv_lib_log" != yes ; then
LIBS="$LIBS $bird_cv_lib_log"
fi
+for ac_func in getrandom
+do :
+ ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom"
+if test "x$ac_cv_func_getrandom" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETRANDOM 1
+_ACEOF
+
+fi
+done
+
+for ac_func in getentropy
+do :
+ ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
+if test "x$ac_cv_func_getentropy" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETENTROPY 1
+_ACEOF
+
+fi
+done
+
+
if test "$enable_debug" = yes ; then
-printf "%s\n" "#define DEBUGGING 1" >>confdefs.h
+$as_echo "#define DEBUGGING 1" >>confdefs.h
LDFLAGS="$LDFLAGS -rdynamic"
CFLAGS="$CFLAGS -O0 -ggdb -g3"
@@ -5356,37 +5746,35 @@ printf "%s\n" "#define DEBUGGING 1" >>confdefs.h
bird_tmp_cflags="$CFLAGS"
CFLAGS=" -gdwarf-4"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CC supports -gdwarf-4" >&5
-printf %s "checking whether CC supports -gdwarf-4... " >&6; }
-if test ${bird_cv_c_option_dwarf4+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -gdwarf-4" >&5
+$as_echo_n "checking whether CC supports -gdwarf-4... " >&6; }
+if ${bird_cv_c_option_dwarf4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main (void)
+main ()
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
+if ac_fn_c_try_compile "$LINENO"; then :
bird_cv_c_option_dwarf4=yes
-else $as_nop
+else
bird_cv_c_option_dwarf4=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_dwarf4" >&5
-printf "%s\n" "$bird_cv_c_option_dwarf4" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_dwarf4" >&5
+$as_echo "$bird_cv_c_option_dwarf4" >&6; }
CFLAGS="$bird_tmp_cflags"
@@ -5396,19 +5784,17 @@ printf "%s\n" "$bird_cv_c_option_dwarf4" >&6; }
fi
- ac_fn_c_check_header_compile "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
-if test "x$ac_cv_header_execinfo_h" = xyes
-then :
+ ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
+if test "x$ac_cv_header_execinfo_h" = xyes; then :
-printf "%s\n" "#define HAVE_EXECINFO_H 1" >>confdefs.h
+$as_echo "#define HAVE_EXECINFO_H 1" >>confdefs.h
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5
-printf %s "checking for library containing backtrace... " >&6; }
-if test ${ac_cv_search_backtrace+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5
+$as_echo_n "checking for library containing backtrace... " >&6; }
+if ${ac_cv_search_backtrace+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5416,51 +5802,49 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 backtrace ();
int
-main (void)
+main ()
{
return backtrace ();
;
return 0;
}
_ACEOF
-for ac_lib in '' execinfo
-do
+for ac_lib in '' execinfo; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"
-then :
+ if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_backtrace=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if test ${ac_cv_search_backtrace+y}
-then :
+ if ${ac_cv_search_backtrace+:} false; then :
break
fi
done
-if test ${ac_cv_search_backtrace+y}
-then :
+if ${ac_cv_search_backtrace+:} false; then :
-else $as_nop
+else
ac_cv_search_backtrace=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5
-printf "%s\n" "$ac_cv_search_backtrace" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5
+$as_echo "$ac_cv_search_backtrace" >&6; }
ac_res=$ac_cv_search_backtrace
-if test "$ac_res" != no
-then :
+if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-else $as_nop
+else
as_fn_error $? "Function backtrace not available." "$LINENO" 5
fi
@@ -5470,13 +5854,13 @@ fi
fi
+
if test "$enable_memcheck" = yes ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dmalloc_debug in -ldmalloc" >&5
-printf %s "checking for dmalloc_debug in -ldmalloc... " >&6; }
-if test ${ac_cv_lib_dmalloc_dmalloc_debug+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dmalloc_debug in -ldmalloc" >&5
+$as_echo_n "checking for dmalloc_debug in -ldmalloc... " >&6; }
+if ${ac_cv_lib_dmalloc_dmalloc_debug+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_check_lib_save_LIBS=$LIBS
LIBS="-ldmalloc $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5485,42 +5869,44 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 dmalloc_debug ();
int
-main (void)
+main ()
{
return dmalloc_debug ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_dmalloc_dmalloc_debug=yes
-else $as_nop
+else
ac_cv_lib_dmalloc_dmalloc_debug=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dmalloc_dmalloc_debug" >&5
-printf "%s\n" "$ac_cv_lib_dmalloc_dmalloc_debug" >&6; }
-if test "x$ac_cv_lib_dmalloc_dmalloc_debug" = xyes
-then :
- printf "%s\n" "#define HAVE_LIBDMALLOC 1" >>confdefs.h
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dmalloc_dmalloc_debug" >&5
+$as_echo "$ac_cv_lib_dmalloc_dmalloc_debug" >&6; }
+if test "x$ac_cv_lib_dmalloc_dmalloc_debug" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDMALLOC 1
+_ACEOF
LIBS="-ldmalloc $LIBS"
fi
if test $ac_cv_lib_dmalloc_dmalloc_debug != yes ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for malloc in -lefence" >&5
-printf %s "checking for malloc in -lefence... " >&6; }
-if test ${ac_cv_lib_efence_malloc+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for malloc in -lefence" >&5
+$as_echo_n "checking for malloc in -lefence... " >&6; }
+if ${ac_cv_lib_efence_malloc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lefence $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5529,30 +5915,33 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 malloc ();
int
-main (void)
+main ()
{
return malloc ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_efence_malloc=yes
-else $as_nop
+else
ac_cv_lib_efence_malloc=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_efence_malloc" >&5
-printf "%s\n" "$ac_cv_lib_efence_malloc" >&6; }
-if test "x$ac_cv_lib_efence_malloc" = xyes
-then :
- printf "%s\n" "#define HAVE_LIBEFENCE 1" >>confdefs.h
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_efence_malloc" >&5
+$as_echo "$ac_cv_lib_efence_malloc" >&6; }
+if test "x$ac_cv_lib_efence_malloc" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBEFENCE 1
+_ACEOF
LIBS="-lefence $LIBS"
@@ -5563,7 +5952,7 @@ fi
if test "enable_debug_expensive" = yes ; then
-printf "%s\n" "#define ENABLE_EXPENSIVE_CHECKS 1" >>confdefs.h
+$as_echo "#define ENABLE_EXPENSIVE_CHECKS 1" >>confdefs.h
fi
fi
@@ -5575,27 +5964,28 @@ if test "$enable_client" = yes ; then
BASE_LIBS="$LIBS"
LIBS=""
- for ac_header in curses.h
+ for ac_header in curses.h
do :
ac_fn_c_check_header_compile "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default
"
-if test "x$ac_cv_header_curses_h" = xyes
-then :
- printf "%s\n" "#define HAVE_CURSES_H 1" >>confdefs.h
+if test "x$ac_cv_header_curses_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_CURSES_H 1
+_ACEOF
-else $as_nop
+else
as_fn_error $? "The client requires ncurses library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
done
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
-printf %s "checking for library containing tgetent... " >&6; }
-if test ${ac_cv_search_tgetent+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
+$as_echo_n "checking for library containing tgetent... " >&6; }
+if ${ac_cv_search_tgetent+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5603,79 +5993,76 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 tgetent ();
int
-main (void)
+main ()
{
return tgetent ();
;
return 0;
}
_ACEOF
-for ac_lib in '' tinfo tinfow ncurses curses termcap
-do
+for ac_lib in '' tinfo tinfow ncurses curses termcap; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"
-then :
+ if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_tgetent=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if test ${ac_cv_search_tgetent+y}
-then :
+ if ${ac_cv_search_tgetent+:} false; then :
break
fi
done
-if test ${ac_cv_search_tgetent+y}
-then :
+if ${ac_cv_search_tgetent+:} false; then :
-else $as_nop
+else
ac_cv_search_tgetent=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
-printf "%s\n" "$ac_cv_search_tgetent" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
+$as_echo "$ac_cv_search_tgetent" >&6; }
ac_res=$ac_cv_search_tgetent
-if test "$ac_res" != no
-then :
+if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
TINFO_LIBS="$LIBS"; LIBS=""
-else $as_nop
+else
as_fn_error $? "The client requires ncurses library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
- for ac_header in readline/readline.h readline/history.h
+ for ac_header in readline/readline.h readline/history.h
do :
- as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh`
+ 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 :
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
-#define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
-else $as_nop
+else
as_fn_error $? "The client requires GNU Readline library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
done
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing rl_callback_read_char" >&5
-printf %s "checking for library containing rl_callback_read_char... " >&6; }
-if test ${ac_cv_search_rl_callback_read_char+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing rl_callback_read_char" >&5
+$as_echo_n "checking for library containing rl_callback_read_char... " >&6; }
+if ${ac_cv_search_rl_callback_read_char+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5683,17 +6070,19 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 rl_callback_read_char ();
int
-main (void)
+main ()
{
return rl_callback_read_char ();
;
return 0;
}
_ACEOF
-for ac_lib in '' readline
-do
+for ac_lib in '' readline; do
if test -z "$ac_lib"; then
ac_res="none required"
else
@@ -5701,44 +6090,39 @@ do
LIBS="-l$ac_lib $TINFO_LIBS
$ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"
-then :
+ if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_rl_callback_read_char=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
- if test ${ac_cv_search_rl_callback_read_char+y}
-then :
+ if ${ac_cv_search_rl_callback_read_char+:} false; then :
break
fi
done
-if test ${ac_cv_search_rl_callback_read_char+y}
-then :
+if ${ac_cv_search_rl_callback_read_char+:} false; then :
-else $as_nop
+else
ac_cv_search_rl_callback_read_char=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rl_callback_read_char" >&5
-printf "%s\n" "$ac_cv_search_rl_callback_read_char" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rl_callback_read_char" >&5
+$as_echo "$ac_cv_search_rl_callback_read_char" >&6; }
ac_res=$ac_cv_search_rl_callback_read_char
-if test "$ac_res" != no
-then :
+if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
READLINE_LIBS="$LIBS"; LIBS=""
-else $as_nop
+else
as_fn_error $? "The client requires GNU Readline library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_crlf in -lreadline" >&5
-printf %s "checking for rl_crlf in -lreadline... " >&6; }
-if test ${ac_cv_lib_readline_rl_crlf+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_crlf in -lreadline" >&5
+$as_echo_n "checking for rl_crlf in -lreadline... " >&6; }
+if ${ac_cv_lib_readline_rl_crlf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lreadline $TINFO_LIBS
$LIBS"
@@ -5748,41 +6132,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 rl_crlf ();
int
-main (void)
+main ()
{
return rl_crlf ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_readline_rl_crlf=yes
-else $as_nop
+else
ac_cv_lib_readline_rl_crlf=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_crlf" >&5
-printf "%s\n" "$ac_cv_lib_readline_rl_crlf" >&6; }
-if test "x$ac_cv_lib_readline_rl_crlf" = xyes
-then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_crlf" >&5
+$as_echo "$ac_cv_lib_readline_rl_crlf" >&6; }
+if test "x$ac_cv_lib_readline_rl_crlf" = xyes; then :
-printf "%s\n" "#define HAVE_RL_CRLF 1" >>confdefs.h
+$as_echo "#define HAVE_RL_CRLF 1" >>confdefs.h
fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_ding in -lreadline" >&5
-printf %s "checking for rl_ding in -lreadline... " >&6; }
-if test ${ac_cv_lib_readline_rl_ding+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_ding in -lreadline" >&5
+$as_echo_n "checking for rl_ding in -lreadline... " >&6; }
+if ${ac_cv_lib_readline_rl_ding+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lreadline $TINFO_LIBS
$LIBS"
@@ -5792,31 +6176,32 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* 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 rl_ding ();
int
-main (void)
+main ()
{
return rl_ding ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
+if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_readline_rl_ding=yes
-else $as_nop
+else
ac_cv_lib_readline_rl_ding=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
+rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_ding" >&5
-printf "%s\n" "$ac_cv_lib_readline_rl_ding" >&6; }
-if test "x$ac_cv_lib_readline_rl_ding" = xyes
-then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_ding" >&5
+$as_echo "$ac_cv_lib_readline_rl_ding" >&6; }
+if test "x$ac_cv_lib_readline_rl_ding" = xyes; then :
-printf "%s\n" "#define HAVE_RL_DING 1" >>confdefs.h
+$as_echo "#define HAVE_RL_DING 1" >>confdefs.h
fi
@@ -5859,8 +6244,8 @@ _ACEOF
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_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) ;; #(
@@ -5890,15 +6275,15 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;}
/^ac_cv_env_/b end
t clear
:clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
+ 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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
+ { $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
@@ -5912,8 +6297,8 @@ printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
fi
fi
else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
+ { $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
@@ -5930,7 +6315,7 @@ 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=`printf "%s\n" "$ac_i" | sed "$ac_script"`
+ 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"
@@ -5947,8 +6332,8 @@ LTLIBOBJS=$ac_ltlibobjs
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
+{ $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
@@ -5971,16 +6356,14 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
+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 $as_nop
+else
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
@@ -5990,46 +6373,46 @@ esac
fi
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
-if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
+# 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 ${PATH_SEPARATOR+false} :; then
+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 ||
@@ -6038,6 +6421,13 @@ if ${PATH_SEPARATOR+false} :; then
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 #((
@@ -6046,12 +6436,8 @@ case $0 in #((
for as_dir in $PATH
do
IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
done
IFS=$as_save_IFS
@@ -6063,10 +6449,30 @@ if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ $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]
@@ -6079,14 +6485,13 @@ 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
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- printf "%s\n" "$as_me: error: $2" >&2
+ $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.
@@ -6113,20 +6518,18 @@ 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 :
+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_nop
+else
as_fn_append ()
{
eval $1=\$$1\$2
@@ -6138,13 +6541,12 @@ fi # as_fn_append
# 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 :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else $as_nop
+else
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
@@ -6175,7 +6577,7 @@ as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
+$as_echo X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
@@ -6197,10 +6599,6 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
@@ -6214,12 +6612,6 @@ case `echo -n x` in #(((((
ECHO_N='-n';;
esac
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
rm -f conf$$.dir/conf$$.file
@@ -6261,7 +6653,7 @@ as_fn_mkdir_p ()
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
@@ -6270,7 +6662,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
+$as_echo X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -6333,7 +6725,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# values after options handling.
ac_log="
This file was extended by $as_me, which was
-generated by GNU Autoconf 2.69e. Invocation command line was
+generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -6391,16 +6783,14 @@ $config_headers
Report bugs to the package provider."
_ACEOF
-ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
-ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config='$ac_cs_config_escaped'
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
config.status
-configured by $0, generated by GNU Autoconf 2.69e,
+configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2020 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@@ -6438,15 +6828,15 @@ do
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
ac_cs_recheck=: ;;
--version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- printf "%s\n" "$ac_cs_version"; exit ;;
+ $as_echo "$ac_cs_version"; exit ;;
--config | --confi | --conf | --con | --co | --c )
- printf "%s\n" "$ac_cs_config"; exit ;;
+ $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=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
'') as_fn_error $? "missing file argument" ;;
esac
as_fn_append CONFIG_FILES " '$ac_optarg'"
@@ -6454,7 +6844,7 @@ do
--header | --heade | --head | --hea )
$ac_shift
case $ac_optarg in
- *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
as_fn_append CONFIG_HEADERS " '$ac_optarg'"
ac_need_defaults=false;;
@@ -6463,7 +6853,7 @@ do
as_fn_error $? "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
--help | --hel | -h )
- printf "%s\n" "$ac_cs_usage"; exit ;;
+ $as_echo "$ac_cs_usage"; exit ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil | --si | --s)
ac_cs_silent=: ;;
@@ -6491,7 +6881,7 @@ 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
- \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
export CONFIG_SHELL
exec "\$@"
@@ -6505,7 +6895,7 @@ exec 5>>config.log
sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
## Running $as_me. ##
_ASBOX
- printf "%s\n" "$ac_log"
+ $as_echo "$ac_log"
} >&5
_ACEOF
@@ -6531,8 +6921,8 @@ done
# 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+y} || CONFIG_FILES=$config_files
- test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
fi
# Have a temporary directory for convenience. Make it in the build tree
@@ -6868,7 +7258,7 @@ do
esac ||
as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
esac
- case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
as_fn_append ac_file_inputs " '$ac_f'"
done
@@ -6876,17 +7266,17 @@ do
# use $as_me), people would be surprised to read:
# /* config.h. Generated by config.status. */
configure_input='Generated from '`
- printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
`' by configure.'
if test x"$ac_file" != x-; then
configure_input="$ac_file. $configure_input"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-printf "%s\n" "$as_me: creating $ac_file" >&6;}
+ { $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=`printf "%s\n" "$configure_input" |
+ ac_sed_conf_input=`$as_echo "$configure_input" |
sed 's/[\\\\&|]/\\\\&/g'`;; #(
*) ac_sed_conf_input=$configure_input;;
esac
@@ -6903,7 +7293,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$ac_file" : 'X\(//\)[^/]' \| \
X"$ac_file" : 'X\(//\)$' \| \
X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$ac_file" |
+$as_echo X"$ac_file" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -6927,9 +7317,9 @@ printf "%s\n" X"$ac_file" |
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ 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/ ;;
@@ -6986,8 +7376,8 @@ ac_sed_dataroot='
case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
*datarootdir*) ac_datarootdir_seen=yes;;
*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ { $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='
@@ -7030,9 +7420,9 @@ 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"; } &&
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+ { $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
-printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+$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"
@@ -7048,20 +7438,20 @@ which seems to be undefined. Please make sure it is defined" >&2;}
#
if test x"$ac_file" != x-; then
{
- printf "%s\n" "/* $configure_input */" >&1 \
+ $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
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
-printf "%s\n" "$as_me: $ac_file is unchanged" >&6;}
+ { $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
- printf "%s\n" "/* $configure_input */" >&1 \
+ $as_echo "/* $configure_input */" \
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
|| as_fn_error $? "could not create -" "$LINENO" 5
fi
@@ -7102,35 +7492,34 @@ if test "$no_create" != yes; then
$ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: " >&5
-printf "%s\n" "" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: BIRD was configured with the following options:" >&5
-printf "%s\n" "BIRD was configured with the following options:" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Source directory: $srcdir" >&5
-printf "%s\n" " Source directory: $srcdir" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Object directory: $objdir" >&5
-printf "%s\n" " Object directory: $objdir" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Iproute2 directory: $iproutedir" >&5
-printf "%s\n" " Iproute2 directory: $iproutedir" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: System configuration: $sysdesc" >&5
-printf "%s\n" " System configuration: $sysdesc" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Debugging: $enable_debug" >&5
-printf "%s\n" " Debugging: $enable_debug" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: POSIX threads: $enable_pthreads" >&5
-printf "%s\n" " POSIX threads: $enable_pthreads" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Routing protocols: $protocols" >&5
-printf "%s\n" " Routing protocols: $protocols" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: LibSSH support in RPKI: $enable_libssh" >&5
-printf "%s\n" " LibSSH support in RPKI: $enable_libssh" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Kernel MPLS support: $enable_mpls_kernel" >&5
-printf "%s\n" " Kernel MPLS support: $enable_mpls_kernel" >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Client: $enable_client" >&5
-printf "%s\n" " Client: $enable_client" >&6; }
+ { $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
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5
+$as_echo "" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: BIRD was configured with the following options:" >&5
+$as_echo "BIRD was configured with the following options:" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Source directory: $srcdir" >&5
+$as_echo " Source directory: $srcdir" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Object directory: $objdir" >&5
+$as_echo " Object directory: $objdir" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Iproute2 directory: $iproutedir" >&5
+$as_echo " Iproute2 directory: $iproutedir" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: System configuration: $sysdesc" >&5
+$as_echo " System configuration: $sysdesc" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Debugging: $enable_debug" >&5
+$as_echo " Debugging: $enable_debug" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: POSIX threads: $enable_pthreads" >&5
+$as_echo " POSIX threads: $enable_pthreads" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Routing protocols: $protocols" >&5
+$as_echo " Routing protocols: $protocols" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: LibSSH support in RPKI: $enable_libssh" >&5
+$as_echo " LibSSH support in RPKI: $enable_libssh" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Kernel MPLS support: $enable_mpls_kernel" >&5
+$as_echo " Kernel MPLS support: $enable_mpls_kernel" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Client: $enable_client" >&5
+$as_echo " Client: $enable_client" >&6; }
rm -f $objdir/.*-stamp
-
diff --git a/configure.ac b/configure.ac
index eabb3d56..64181d29 100644
--- a/configure.ac
+++ b/configure.ac
@@ -351,6 +351,7 @@ case $sysdesc in
esac
AC_CHECK_HEADERS_ONCE([alloca.h syslog.h])
+AC_CHECK_HEADER([sys/mman.h], [AC_DEFINE([HAVE_MMAP], [1], [Define to 1 if mmap() is available.])])
AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#include <sys/socket.h>])
AC_C_BIGENDIAN(
@@ -373,6 +374,9 @@ elif test "$bird_cv_lib_log" != yes ; then
LIBS="$LIBS $bird_cv_lib_log"
fi
+AC_CHECK_FUNCS(getrandom)
+AC_CHECK_FUNCS(getentropy)
+
if test "$enable_debug" = yes ; then
AC_DEFINE([DEBUGGING], [1], [Define to 1 if debugging is enabled])
LDFLAGS="$LDFLAGS -rdynamic"
diff --git a/distro/README.md b/distro/README.md
new file mode 100644
index 00000000..ac1a75b0
--- /dev/null
+++ b/distro/README.md
@@ -0,0 +1,69 @@
+# BIRD upstream packaging sources
+
+This distro/ directory contains packaging sources initially copied from Debian
+and Fedora downstream repos.
+
+Files in this directory follow [apkg] conventions and apkg can be used to
+create BIRD packages for various distros directly from upstream sources as
+well as from upstream archives.
+
+[apkg]: https://apkg.rtfd.io
+
+
+## Create (source) package from current repo commit
+
+Following command should build source package for current distro directly
+from current repo state - run at top bird directory:
+
+ apkg srcpkg
+
+or build native packages directly:
+
+ apkg build
+
+or in case of disposable VM/container you can use faster direct host build
+
+ apkg build -Hi
+
+tools/make-dev-archive script is in charge of creating archive from source.
+
+
+## Create (source) package from upstream release
+
+Following commands can be used to clone upstream repo, download current upstream
+archive (tarball), and build Debian, Ubuntu, Fedora, CentOS, or OpenSUSE
+source package (depending on host system) using files in bird/distro:
+
+ git clone https://gitlab.nic.cz/labs/bird
+ cd bird
+ apkg get-archive
+ apkg srcpkg -a pkg/archives/upstream/bird-2.0.8.tar.gz
+
+To create native packages instead use `build`:
+
+ apkg build -a pkg/archives/upstream/bird-2.0.8.tar.gz
+
+Or to build packages directly in case of a disposable VM/container (faster, modifies system):
+
+ apkg build -Hi -a pkg/archives/upstream/bird-2.0.8.tar.gz
+
+
+## Build packages in openSUSE Build Service (OBS)
+
+tools/make-obs script can be used on Debian-based system to create OBS
+source package in pkg/obs directory ready to be uploaded:
+
+ cd bird
+ apkg get-archive
+ ./tools/make-obs
+ # result in pkg/obs
+
+You can also supply (upstream) archive to build from:
+
+ # or to use specified archive
+ ./tools/make-obs pkg/archives/upstream/bird-2.0.8.tar.gz
+
+
+## More Info
+
+Please see [apkg docs][apkg].
diff --git a/distro/config/apkg.toml b/distro/config/apkg.toml
new file mode 100644
index 00000000..c70306d6
--- /dev/null
+++ b/distro/config/apkg.toml
@@ -0,0 +1,8 @@
+[project]
+name = "bird"
+# needed for make-archive
+make_archive_script = "tools/make-dev-archive"
+
+[upstream]
+# needed for get-archive
+archive_url = "https://bird.network.cz/download/bird-{{ version }}.tar.gz"
diff --git a/distro/pkg/deb/bird.xml b/distro/pkg/deb/bird.xml
new file mode 100644
index 00000000..4ba3868f
--- /dev/null
+++ b/distro/pkg/deb/bird.xml
@@ -0,0 +1,286 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+
+<!--
+
+`xsltproc -''-nonet \
+ -''-param man.charmap.use.subset "0" \
+ -''-param make.year.ranges "1" \
+ -''-param make.single.year.ranges "1" \
+ /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl \
+ manpage.xml'
+
+A manual page <package>.<section> will be generated. You may view the
+manual page with: nroff -man <package>.<section> | less'. A typical entry
+in a Makefile or Makefile.am is:
+
+DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl
+XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0"
+
+manpage.1: manpage.xml
+ $(XP) $(DB2MAN) $<
+
+The xsltproc binary is found in the xsltproc package. The XSL files are in
+docbook-xsl. A description of the parameters you can use can be found in the
+docbook-xsl-doc-* packages. Please remember that if you create the nroff
+version in one of the debian/rules file targets (such as build), you will need
+to include xsltproc and docbook-xsl in your Build-Depends control field.
+Alternatively use the xmlto command/package. That will also automatically
+pull in xsltproc and docbook-xsl.
+
+Notes for using docbook2x: docbook2x-man does not automatically create the
+AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as
+<refsect1> ... </refsect1>.
+
+To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections
+read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be
+found in the docbook-xsl-doc-html package.
+
+Validation can be done using: `xmllint -''-noout -''-valid manpage.xml`
+
+General documentation about man-pages and man-page-formatting:
+man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
+
+-->
+
+ <!ENTITY dhfirstname "Giovanni">
+ <!ENTITY dhsurname "Mascellani">
+ <!ENTITY dhusername "&dhfirstname; &dhsurname;">
+ <!ENTITY dhemail "mascellani@poisson.phc.unipi.it">
+ <!ENTITY dhsection "8">
+ <!ENTITY dhtitle "BIRD User Manual">
+]>
+
+<refentry>
+ <refentryinfo>
+ <title>&dhtitle;</title>
+ <productname>bird</productname>
+ <authorgroup>
+ <author>
+ <firstname>&dhfirstname;</firstname>
+ <surname>&dhsurname;</surname>
+ <contrib>Wrote this manpage for the Debian system.</contrib>
+ <address>
+ <email>&dhemail;</email>
+ </address>
+ </author>
+ </authorgroup>
+ <copyright>
+ <year>2010</year>
+ <holder>&dhusername;</holder>
+ </copyright>
+ <legalnotice>
+ <para>This manual page was written for the Debian system
+ (and may be used by others).</para>
+ <para>Permission is granted to copy, distribute and/or modify this
+ document under the terms of the GNU General Public License,
+ Version 2 or (at your option) any later version published by
+ the Free Software Foundation.</para>
+ <para>On Debian systems, the complete text of the GNU General Public
+ License can be found in
+ <filename>/usr/share/common-licenses/GPL</filename>.</para>
+ </legalnotice>
+
+ </refentryinfo>
+ <refmeta>
+ <refentrytitle>bird</refentrytitle>
+ <manvolnum>&dhsection;</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>bird</refname>
+ <refpurpose>BIRD Internet Routing Daemon</refpurpose>
+ </refnamediv>
+ <refnamediv>
+ <refname>birdc</refname>
+ <refpurpose>BIRD Internet Routing Daemon remote control</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>bird</command>
+ <arg choice="opt"><option>-c <replaceable>config-file</replaceable></option></arg>
+ <arg choice="opt"><option>-d</option></arg>
+ <arg choice="opt"><option>-D <replaceable>debug-file</replaceable></option></arg>
+ <arg choice="opt"><option>-f</option></arg>
+ <arg choice="opt"><option>-g <replaceable>group</replaceable></option></arg>
+ <arg choice="opt"><option>-l</option></arg>
+ <arg choice="opt"><option>-p</option></arg>
+ <arg choice="opt"><option>-P <replaceable>pid-file</replaceable></option></arg>
+ <arg choice="opt"><option>-R</option></arg>
+ <arg choice="opt"><option>-s <replaceable>control-socket</replaceable></option></arg>
+ <arg choice="opt"><option>-u <replaceable>user</replaceable></option></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>birdc</command>
+ <arg choice="opt"><option>-l</option></arg>
+ <arg choice="opt"><option>-r</option></arg>
+ <arg choice="opt"><option>-s <replaceable>control-socket</replaceable></option></arg>
+ <arg choice="opt"><option>-v</option></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="description">
+ <title>DESCRIPTION</title>
+ <para><command>bird</command> is an Internet Routing Daemon. That is,
+ it sends and receives messages using different protocols in order to
+ discover and exchange routing information with other routing daemons
+ present on the same network. It is able to talk the most widely
+ known routing protocols (such as BGPv4, RIPv2, OSPFv2 and OSPFv3),
+ both on IPv4 and IPv6 and it features a very powerful language for
+ route filtering.</para>
+ <para><command>birdc</command> is a remote control for <command>bird</command>.
+ While <command>bird</command> is running, the system administrator can
+ connect to it using <command>birdc</command>, to inspect its internal
+ status and reconfigure it. The two processes use a Unix socket to
+ communicate. Once started, <command>bird</command> will give access
+ to an interactive shell: commands can be completed with TAB and help
+ can be requested by pressing the key `?'. More documentation on
+ the available commands can be foung on the website, see below.</para>
+ </refsect1>
+
+ <refsect1 id="options">
+ <title>OPTIONS</title>
+ <para>The <command>bird</command> accepts these options:</para>
+ <variablelist>
+ <varlistentry>
+ <term><option>-c <replaceable>config-file</replaceable></option></term>
+ <listitem>
+ <para>Use given configuration file instead of the default /etc/bird/bird.conf.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-d</option></term>
+ <listitem>
+ <para>Enable debug messages to stderr, and run bird in foreground.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-D <replaceable>debug-file</replaceable></option></term>
+ <listitem>
+ <para>Enable debug messages to given file.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-f</option></term>
+ <listitem>
+ <para>Run bird in foreground.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-g <replaceable>group</replaceable></option></term>
+ <listitem>
+ <para>Run bird with given group ID.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--help</option></term>
+ <listitem>
+ <para>Display command-line options to bird.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-l</option></term>
+ <listitem>
+ <para>Look for a configuration file and a communication socket in the
+ current working directory instead of in default system locations.
+ However, paths specified by options <option>-c</option>,
+ <option>-s</option> have higher priority.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-p</option></term>
+ <listitem>
+ <para>Just parse the config file and exit. Return value is zero if the
+ config file is valid, nonzero if there are some errors.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-P <replaceable>pid-file</replaceable></option></term>
+ <listitem>
+ <para>Create a PID file with given filename.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-R</option></term>
+ <listitem>
+ <para>Apply graceful restart recovery after start.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-s <replaceable>control-socket</replaceable></option></term>
+ <listitem>
+ <para>Use given filename for a socket for communications with the
+ client (remote control), default is /run/bird/bird.ctl.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-u <replaceable>user</replaceable></option></term>
+ <listitem>
+ <para>Drop privileges and run as given user instead of root. The bird
+ would keep CAP_NET_ADMIN and other network-related capabilities
+ necessary for its function.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--version</option></term>
+ <listitem>
+ <para>Display bird version.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>The <command>birdc</command> accepts these options:</para>
+ <variablelist>
+ <varlistentry>
+ <term><option>-l</option></term>
+ <listitem>
+ <para>Look for a communication socket in the current working directory.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-r</option></term>
+ <listitem>
+ <para>Run <command>birdc</command> in restricted mode: only the
+ `show ...' commands are allowed.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-s <replaceable>control-socket</replaceable></option></term>
+ <listitem>
+ <para>Use given filename for a socket for communications with the
+ server, default is /run/bird/bird.ctl.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-v</option></term>
+ <listitem>
+ <para>Numeric return codes are dumped along with messages, making
+ them easily parsable by a program. See the programmer's documentation
+ for information about their meanings.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="files">
+ <title>FILES</title>
+ <variablelist>
+ <varlistentry>
+ <term><filename>/etc/bird/bird.conf</filename></term>
+ <listitem>
+ <para>The system-wide configuration file to control the
+ behaviour of <application>bird</application>. See
+ the website for more documentation.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1 id="see_also">
+ <title>SEE ALSO</title>
+ <para>More documentation con be found on the website:
+ https://bird.network.cz/.</para>
+ </refsect1>
+</refentry>
+
diff --git a/distro/pkg/deb/bird2-doc.docs b/distro/pkg/deb/bird2-doc.docs
new file mode 100644
index 00000000..4c0c6465
--- /dev/null
+++ b/distro/pkg/deb/bird2-doc.docs
@@ -0,0 +1,4 @@
+obj/doc/bird*.html
+obj/doc/bird.pdf
+obj/doc/prog*.html
+obj/doc/prog.pdf
diff --git a/distro/pkg/deb/bird2.bird.init b/distro/pkg/deb/bird2.bird.init
new file mode 100644
index 00000000..ac15e698
--- /dev/null
+++ b/distro/pkg/deb/bird2.bird.init
@@ -0,0 +1,136 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: bird
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+### END INIT INFO
+
+# Author: Ondřej Surý <ondrej@sury.org>
+#
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="BIRD Internet Routing Daemon"
+NAME=bird
+DAEMON=/usr/sbin/$NAME
+BIRD_ARGS=""
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# read the RUN variables
+. /etc/bird/envvars
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+# Create /run/bird with correct permissions
+/usr/lib/bird/prepare-environment
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --start --quiet --name $NAME --exec $DAEMON --test > /dev/null \
+ || return 1
+ start-stop-daemon --start --quiet --name $NAME --exec $DAEMON -- \
+ -u $BIRD_RUN_USER -g $BIRD_RUN_GROUP $BIRD_ARGS \
+ || return 2
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME --exec $DAEMON
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Wait for children to finish too if this is a daemon that forks
+ # and if the daemon is only ever run from this initscript.
+ start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --name $NAME --exec $DAEMON
+ [ "$?" = 2 ] && return 2
+ return "$RETVAL"
+}
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+ #
+ # If the daemon can reload its configuration without
+ # restarting (for example, when it is sent a SIGHUP),
+ # then implement that here.
+ #
+ start-stop-daemon --stop --signal 1 --quiet --name $NAME --exec $DAEMON
+ return 0
+}
+
+case "$1" in
+ start)
+ log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) log_end_msg 0 ;;
+ 2) log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) log_end_msg 0 ;;
+ 2) log_end_msg 1 ;;
+ esac
+ ;;
+ reload|force-reload)
+ #
+ # If do_reload() is not implemented then leave this commented out
+ # and leave 'force-reload' as an alias for 'restart'.
+ #
+ log_daemon_msg "Reloading $DESC" "$NAME"
+ do_reload
+ log_end_msg $?
+ ;;
+ restart)
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+:
diff --git a/distro/pkg/deb/bird2.bird.service b/distro/pkg/deb/bird2.bird.service
new file mode 100644
index 00000000..37e75fb4
--- /dev/null
+++ b/distro/pkg/deb/bird2.bird.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=BIRD Internet Routing Daemon
+After=network.target
+
+[Service]
+EnvironmentFile=/etc/bird/envvars
+ExecStartPre=/usr/lib/bird/prepare-environment
+ExecStartPre=/usr/sbin/bird -p
+ExecReload=/usr/sbin/birdc configure
+ExecStart=/usr/sbin/bird -f -u $BIRD_RUN_USER -g $BIRD_RUN_GROUP $BIRD_ARGS
+Restart=on-abort
+
+[Install]
+WantedBy=multi-user.target
diff --git a/distro/pkg/deb/bird2.docs b/distro/pkg/deb/bird2.docs
new file mode 100644
index 00000000..50bd824b
--- /dev/null
+++ b/distro/pkg/deb/bird2.docs
@@ -0,0 +1,2 @@
+NEWS
+README
diff --git a/distro/pkg/deb/bird2.install b/distro/pkg/deb/bird2.install
new file mode 100644
index 00000000..d0fad47d
--- /dev/null
+++ b/distro/pkg/deb/bird2.install
@@ -0,0 +1,6 @@
+etc/bird/bird.conf /usr/share/bird2/
+debian/envvars /etc/bird/
+debian/prepare-environment /usr/lib/bird/
+usr/sbin/bird
+usr/sbin/birdc
+usr/sbin/birdcl
diff --git a/distro/pkg/deb/bird2.lintian-overrides b/distro/pkg/deb/bird2.lintian-overrides
new file mode 100644
index 00000000..e64c0ef6
--- /dev/null
+++ b/distro/pkg/deb/bird2.lintian-overrides
@@ -0,0 +1 @@
+bird2: binary-without-manpage usr/sbin/birdcl
diff --git a/distro/pkg/deb/bird2.manpages b/distro/pkg/deb/bird2.manpages
new file mode 100644
index 00000000..94898ea1
--- /dev/null
+++ b/distro/pkg/deb/bird2.manpages
@@ -0,0 +1,2 @@
+bird.8
+birdc.8
diff --git a/distro/pkg/deb/bird2.postinst b/distro/pkg/deb/bird2.postinst
new file mode 100644
index 00000000..8f85b15a
--- /dev/null
+++ b/distro/pkg/deb/bird2.postinst
@@ -0,0 +1,19 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = "configure" ]; then
+
+ if ! getent passwd bird > /dev/null; then
+ adduser --quiet --system --group --no-create-home --home /run/bird bird
+ fi
+
+ dpkg-statoverride --list /etc/bird > /dev/null || dpkg-statoverride --update --add bird bird 0750 /etc/bird
+
+ ucf /usr/share/bird2/bird.conf /etc/bird/bird.conf
+ ucfr -f bird2 /etc/bird/bird.conf
+ dpkg-statoverride --list /etc/bird/bird.conf > /dev/null || dpkg-statoverride --update --add bird bird 0640 /etc/bird/bird.conf
+fi
+
+#DEBHELPER#
+
+exit 0
diff --git a/distro/pkg/deb/bird2.postrm b/distro/pkg/deb/bird2.postrm
new file mode 100644
index 00000000..ab03e6e6
--- /dev/null
+++ b/distro/pkg/deb/bird2.postrm
@@ -0,0 +1,26 @@
+#!/bin/sh
+set -e
+
+if test "$1" = "purge"; then
+
+ # Check if there is no collision of ownership of /etc/bird/bird.conf
+ if ! command -v ucf ucfr >/dev/null || ucfr bird2 /etc/bird/bird.conf 2>/dev/null; then
+ dpkg-statoverride --remove /etc/bird >/dev/null 2>/dev/null || true
+ dpkg-statoverride --remove /etc/bird/bird.conf >/dev/null 2>/dev/null || true
+
+ for ext in '~' '%' .bak .ucf-new .ucf-old .ucf-dist; do
+ rm -f /etc/bird/bird.conf$ext
+ done
+ rm -f /etc/bird/bird.conf
+ if command -v ucf ucfr >/dev/null; then
+ ucf --purge /etc/bird/bird.conf
+ ucfr --purge bird2 /etc/bird/bird.conf
+ fi
+
+ deluser --quiet bird > /dev/null || true
+ fi
+fi
+
+#DEBHELPER#
+
+exit 0
diff --git a/distro/pkg/deb/changelog b/distro/pkg/deb/changelog
new file mode 100644
index 00000000..d371bc06
--- /dev/null
+++ b/distro/pkg/deb/changelog
@@ -0,0 +1,5 @@
+bird2 ({{ version }}-cznic.{{ release }}) unstable; urgency=medium
+
+ * upstream package
+
+ -- Jakub Ružička <jakub.ruzicka@nic.cz> Mon, 29 Mar 2021 14:15:50 +0000
diff --git a/distro/pkg/deb/compat b/distro/pkg/deb/compat
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/distro/pkg/deb/compat
@@ -0,0 +1 @@
+9
diff --git a/distro/pkg/deb/control b/distro/pkg/deb/control
new file mode 100644
index 00000000..d431022b
--- /dev/null
+++ b/distro/pkg/deb/control
@@ -0,0 +1,55 @@
+Source: bird2
+Section: net
+Priority: optional
+Build-Depends: bison,
+ debhelper,
+ docbook-xsl,
+ flex,
+ libncurses5-dev,
+ libreadline-dev | libreadline6-dev | libreadline5-dev,
+ libssh-gcrypt-dev,
+ linuxdoc-tools-latex,
+ m4,
+ opensp,
+ quilt,
+ texlive-latex-extra,
+ xsltproc
+Maintainer: Jakub Ružička <jakub.ruzicka@nic.cz>
+Uploaders: Ondřej Surý <ondrej@debian.org>
+Standards-Version: 4.3.0
+Vcs-Browser: https://salsa.debian.org/debian/bird2
+Vcs-Git: https://salsa.debian.org/debian/bird2.git
+Homepage: https://bird.network.cz/
+
+Package: bird2
+Architecture: kfreebsd-any linux-any
+Pre-Depends: init-system-helpers,
+ ${misc:Pre-Depends}
+Depends: adduser,
+ lsb-base,
+ ucf,
+ ${misc:Depends},
+ ${shlibs:Depends}
+Conflicts: bird
+Suggests: bird2-doc
+Description: Internet Routing Daemon
+ BIRD is an Internet routing daemon with full support for all the major
+ routing protocols. It allows redistribution between protocols with a
+ powerful route filtering syntax and an easy-to-use configuration
+ interface.
+ .
+ BIRD supports IPv4 and IPv6 versions of OSPF, RIP, BGP and Babel routing
+ protocols. It also supports supplementary protocols like BFD, RPKI-Router
+ and IPv6 router advertisements.
+
+Package: bird2-doc
+Architecture: all
+Section: doc
+Depends: ${misc:Depends}
+Description: Internet Routing Daemon - documentation
+ BIRD is an Internet routing daemon with full support for all the major
+ routing protocols. It allows redistribution between protocols with a
+ powerful route filtering syntax and an easy-to-use configuration
+ interface.
+ .
+ This package provides the user and developer documentation.
diff --git a/distro/pkg/deb/copyright b/distro/pkg/deb/copyright
new file mode 100644
index 00000000..7d3c391c
--- /dev/null
+++ b/distro/pkg/deb/copyright
@@ -0,0 +1,99 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: bird
+Upstream-Contact: bird-users@network.cz
+Source: https://bird.network.cz
+
+Files: *
+Copyright: 1998-2008 Martin Mareš
+ 1998-2019 Ondřej Filip
+ 1998-2000 Pavel Machek
+ 2008-2019 Ondřej Zajíček
+ 2015-2019 Maria Matějka
+License: GPL-2+
+
+Files: lib/heap.h
+Copyright: 2001 Martin Mareš <mj@ucw.cz>
+ 2005 Tomáš Valla <tom@ucw.cz>
+License: LGPL-2+
+
+Files: lib/md5.c
+Copyright: 1993 Colin Plumb
+License: public-domain
+
+Files: lib/printf.c
+Copyright: 1991-1992 Lars Wirzenius
+ 1991-1992 Linus Torvalds
+ 1998-2000 Martin Mareš
+License: GPL-2
+
+Files: lib/sha*
+Copyright: 1998-2009 Free Software Foundation, Inc.
+ 2015-2016 Pavel Tvrdík
+ 2015-2016 Ondřej Zajíček
+License: GPL-2+
+
+Files: proto/babel/*
+Copyright: 2015-2016 Toke Høiland-Jørgensen
+ 2016-2018 Ondřej Zajíček
+License: GPL-2+
+
+Files: proto/rpki/*
+Copyright: 2015-2016 Pavel Tvrdík
+ 2016-2018 Ondřej Zajíček
+License: GPL-2+
+
+Files: debian/*
+Copyright: 2010-2013 Ondřej Surý <ondrej@debian.org>
+License: GPL-2+
+
+License: GPL-2+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU General Public License
+ version 2 can be found in `/usr/share/common-licenses/GPL-2'.
+
+License: GPL-2
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+ .
+ This package 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 package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU General Public License
+ version 2 can be found in `/usr/share/common-licenses/GPL-2'.
+
+License: LGPL-2+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+ .
+ On Debian systems, the complete text of the GNU Lesser General Public
+ License version 2 can be found in `/usr/share/common-licenses/LGPL-2'.
+
+License: public-domain
+ This code is in the public domain; do with it what you wish.
diff --git a/distro/pkg/deb/envvars b/distro/pkg/deb/envvars
new file mode 100644
index 00000000..9ca9baa0
--- /dev/null
+++ b/distro/pkg/deb/envvars
@@ -0,0 +1,3 @@
+BIRD_RUN_USER=bird
+BIRD_RUN_GROUP=bird
+#BIRD_ARGS=
diff --git a/distro/pkg/deb/gbp.conf b/distro/pkg/deb/gbp.conf
new file mode 100644
index 00000000..f04b9f6e
--- /dev/null
+++ b/distro/pkg/deb/gbp.conf
@@ -0,0 +1,9 @@
+[DEFAULT]
+debian-branch = master
+debian-tag = debian/%(version)s
+upstream-branch = upstream
+upstream-tag = upstream/%(version)s
+pristine-tar = True
+
+[dch]
+meta = 1
diff --git a/distro/pkg/deb/prepare-environment b/distro/pkg/deb/prepare-environment
new file mode 100755
index 00000000..d782c140
--- /dev/null
+++ b/distro/pkg/deb/prepare-environment
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+set -eu
+
+BIRD_RUN_DIR=/run/bird
+. /etc/bird/envvars
+
+
+mkdir --parents "$BIRD_RUN_DIR";
+
+if [ -n "$BIRD_RUN_USER" ]; then
+ if ! getent passwd $BIRD_RUN_USER >/dev/null; then
+ echo "Configured user '$BIRD_RUN_USER' doesn't exist."
+ exit 1
+ fi
+fi
+
+if [ -n "$BIRD_RUN_GROUP" ]; then
+ if ! getent group $BIRD_RUN_GROUP >/dev/null; then
+ echo "Configured group '$BIRD_RUN_GROUP' doesn't exist."
+ exit 1
+ fi
+fi
+
+chown --silent "$BIRD_RUN_USER:$BIRD_RUN_GROUP" "$BIRD_RUN_DIR"
+chmod 775 "$BIRD_RUN_DIR"
+
+:
diff --git a/distro/pkg/deb/rules b/distro/pkg/deb/rules
new file mode 100755
index 00000000..5630ed1c
--- /dev/null
+++ b/distro/pkg/deb/rules
@@ -0,0 +1,56 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+DPKG_EXPORT_BUILDFLAGS = 1
+include /usr/share/dpkg/default.mk
+
+COMMON_FLAGS= --prefix=/usr --sysconfdir=/etc/bird --mandir=\$${prefix}/share/man \
+ --infodir=\$${prefix}/share/info --localstatedir=/var --runstatedir=/run/bird \
+ --docdir=\$${prefix}/share/bird2 \
+ --enable-client
+
+CFLAGS += -g -O2 -fno-strict-aliasing -fno-strict-overflow -fPIC
+LDFLAGS += -g -O2 -fno-strict-aliasing -fno-strict-overflow -fPIC -Wl,-z,defs -Wl,--as-needed
+
+%:
+ dh $@
+
+override_dh_auto_configure:
+ CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" dh_auto_configure -- $(COMMON_FLAGS) --with-protocols=all
+
+override_dh_auto_build:
+ dh_auto_build
+ dh_auto_build -- docs
+
+override_dh_auto_install:
+ dh_auto_install --destdir=debian/tmp
+
+override_dh_installinit:
+ dh_installinit --name=bird --restart-after-upgrade
+
+override_dh_installsystemd:
+ dh_installsystemd --name=bird --restart-after-upgrade
+
+DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl
+XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0"
+
+bird.8: debian/bird.xml
+ $(XP) $(DB2MAN) $<
+
+override_dh_installman: bird.8
+ dh_installman
+
+override_dh_clean:
+ dh_clean
+ -rm -f bird.8 birdc.8
+
+override_dh_missing:
+ dh_missing --fail-missing
+
+override_dh_compress:
+ dh_compress -X.conf
diff --git a/distro/pkg/deb/source/format b/distro/pkg/deb/source/format
new file mode 100644
index 00000000..163aaf8d
--- /dev/null
+++ b/distro/pkg/deb/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/distro/pkg/deb/watch b/distro/pkg/deb/watch
new file mode 100644
index 00000000..1874bfbb
--- /dev/null
+++ b/distro/pkg/deb/watch
@@ -0,0 +1,2 @@
+version=3
+https://bird.network.cz/download/bird-(2\.[\d.]+).tar.gz
diff --git a/distro/pkg/rpm/bird.service b/distro/pkg/rpm/bird.service
new file mode 100644
index 00000000..fa203c78
--- /dev/null
+++ b/distro/pkg/rpm/bird.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=BIRD Internet Routing Daemon
+Wants=network.target
+After=network.target
+
+[Service]
+Type=simple
+ExecStart=/usr/sbin/bird -f -u bird -g bird
+ExecReload=/bin/kill -HUP $MAINPID
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/distro/pkg/rpm/bird.spec b/distro/pkg/rpm/bird.spec
new file mode 100644
index 00000000..cd51ef51
--- /dev/null
+++ b/distro/pkg/rpm/bird.spec
@@ -0,0 +1,117 @@
+%global _hardened_build 1
+%global _without_doc 1
+
+Name: bird
+Version: {{ version }}
+Release: cznic.{{ release }}%{?dist}
+Summary: BIRD Internet Routing Daemon
+
+License: GPL-2.0-or-later
+URL: https://bird.network.cz/
+Source0: https://bird.network.cz/download/bird-%{version}.tar.gz
+Source1: bird.service
+Source2: bird.tmpfilesd
+
+BuildRequires: flex
+BuildRequires: bison
+BuildRequires: ncurses-devel
+BuildRequires: readline-devel
+BuildRequires: sed
+BuildRequires: gcc
+BuildRequires: make
+BuildRequires: libssh-devel
+%if 0%{?fedora} || (0%{?rhel} && 0%{?rhel} > 7)
+BuildRequires: systemd-rpm-macros
+%else
+BuildRequires: systemd
+%endif
+
+Obsoletes: bird6 < 2.0.2-1
+Provides: bird6 = %{version}-%{release}
+
+%description
+BIRD is a dynamic IP routing daemon supporting both, IPv4 and IPv6, Border
+Gateway Protocol (BGPv4), Routing Information Protocol (RIPv2, RIPng), Open
+Shortest Path First protocol (OSPFv2, OSPFv3), Babel Routing Protocol (Babel),
+Bidirectional Forwarding Detection (BFD), IPv6 router advertisements, static
+routes, inter-table protocol, command-line interface allowing on-line control
+and inspection of the status of the daemon, soft reconfiguration as well as a
+powerful language for route filtering.
+
+%if 0%{!?_without_doc:1}
+%package doc
+Summary: Documentation for BIRD Internet Routing Daemon
+BuildRequires: linuxdoc-tools sgml-common perl(FindBin)
+BuildArch: noarch
+
+%description doc
+Documentation for users and programmers of the BIRD Internet Routing Daemon.
+
+BIRD is a dynamic IP routing daemon supporting both, IPv4 and IPv6, Border
+Gateway Protocol (BGPv4), Routing Information Protocol (RIPv2, RIPng), Open
+Shortest Path First protocol (OSPFv2, OSPFv3), Babel Routing Protocol (Babel),
+Bidirectional Forwarding Detection (BFD), IPv6 router advertisements, static
+routes, inter-table protocol, command-line interface allowing on-line control
+and inspection of the status of the daemon, soft reconfiguration as well as a
+powerful language for route filtering.
+%endif
+
+%prep
+%setup -q
+
+%build
+%configure --runstatedir=%{_rundir}/bird
+%make_build all %{!?_without_doc:docs}
+
+%install
+%make_install
+
+{% raw %}
+install -d %{buildroot}{%{_localstatedir}/lib/bird,%{_rundir}/bird}
+install -D -p -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/bird.service
+install -D -p -m 0644 %{SOURCE2} %{buildroot}%{_tmpfilesdir}/bird.conf
+{% endraw %}
+
+%check
+make test
+
+%pre
+getent group bird >/dev/null || groupadd -r bird
+getent passwd bird >/dev/null || \
+ useradd -r -g bird -d %{_localstatedir}/lib/bird -s /sbin/nologin \
+ -c "BIRD daemon user" bird
+exit 0
+
+%post
+%systemd_post bird.service
+
+%preun
+%systemd_preun bird.service
+
+%postun
+%systemd_postun_with_restart bird.service
+
+%files
+%doc NEWS README
+%attr(0640,root,bird) %config(noreplace) %{_sysconfdir}/bird.conf
+%{_unitdir}/bird.service
+%{_tmpfilesdir}/bird.conf
+%{_sbindir}/bird
+%{_sbindir}/birdc
+%{_sbindir}/birdcl
+%dir %attr(0750,bird,bird) %{_localstatedir}/lib/bird
+%dir %attr(0750,bird,bird) %ghost %{_rundir}/bird
+
+%if 0%{!?_without_doc:1}
+%files doc
+%doc NEWS README
+%doc doc/bird.conf.*
+%doc obj/doc/bird*.html
+%doc obj/doc/bird.pdf
+%doc obj/doc/prog*.html
+%doc obj/doc/prog.pdf
+%endif
+
+%changelog
+* Wed Apr 07 2021 Jakub Ružička <jakub.ruzicka@nic.cz> - {{ version }}-cznic.1
+- upstream package
diff --git a/distro/pkg/rpm/bird.tmpfilesd b/distro/pkg/rpm/bird.tmpfilesd
new file mode 100644
index 00000000..a73133ae
--- /dev/null
+++ b/distro/pkg/rpm/bird.tmpfilesd
@@ -0,0 +1 @@
+d /run/bird 750 bird bird
diff --git a/doc/LinuxDocTools.pm b/doc/LinuxDocTools.pm
deleted file mode 100644
index d32f3171..00000000
--- a/doc/LinuxDocTools.pm
+++ /dev/null
@@ -1,637 +0,0 @@
-#! /usr/bin/perl
-#
-# LinuxDocTools.pm
-#
-# $Id$
-#
-# LinuxDoc-Tools driver core. This contains all the basic functionality
-# we need to control all other components.
-#
-# Copyright 1996, Cees de Groot.
-# Copyright 2000, Taketoshi Sano
-#
-# THIS VERSION HAS BEEN HACKED FOR BIRD BY MARTIN MARES
-#
-package LinuxDocTools;
-
-require 5.004;
-use strict;
-
-=head1 NAME
-
-LinuxDocTools - SGML conversion utilities for LinuxDoc DTD.
-
-=head1 SYNOPSIS
-
- use LinuxDocTools;
- LinuxDocTools::init;
- @files = LinuxDocTools::process_options ($0, @ARGV);
- for $curfile (@files) {
- LinuxDocTools::process_file ($curfile);
- }
-
-=head1 DESCRIPTION
-
-The LinuxDocTools package encapsulates all the functionality offered by
-LinuxDoc-Tools. It is used, of course, by LinuxDoc-Tools;
-but the encapsulation should provide for a simple interface for other users as well.
-
-=head1 FUNCTIONS
-
-=over 4
-
-=cut
-
-use DirHandle;
-use File::Basename;
-use File::Find;
-use File::Copy;
-use FileHandle;
-use IPC::Open2;
-use Cwd;
-use LinuxDocTools::Lang;
-use LinuxDocTools::Utils qw(process_options usage cleanup trap_signals remove_tmpfiles create_temp);
-use LinuxDocTools::Vars;
-
-sub BEGIN
-{
- #
- # Make sure we're always looking here. Note that "use lib" adds
- # on the front of the search path, so we first push dist, then
- # site, so that site is searched first.
- #
- use lib "$main::DataDir/dist";
- use lib "$main::DataDir/site";
-}
-
-=item LinuxDocTools::init
-
-Takes care of initialization of package-global variables (which are actually
-defined in L<LinuxDocTools::Vars>). The package-global variables are I<$global>,
-a reference to a hash containing numerous settings, I<%Formats>, a hash
-containing all the formats, and I<%FmtList>, a hash containing the currently
-active formats for help texts.
-
-Apart from this, C<LinuxDocTools::init> also finds all distributed and site-local
-formatting backends and C<require>s them.
-
-=cut
-
-sub init
-{
- trap_signals;
-
- #
- # Register the ``global'' pseudoformat. Apart from the global settings,
- # we also use $global to keep the global variable name space clean;
- # everything that we need to provide to other modules is stuffed
- # into $global.
- #
- $global = {};
- $global->{NAME} = "global";
- $global->{HELP} = "";
- $global->{OPTIONS} = [
- { option => "backend", type => "l",
- 'values' => [ "html", "info", "latex",
- "lyx", "rtf", "txt", "check" ],
- short => "B" },
- { option => "papersize", type => "l",
- 'values' => [ "a4", "letter" ], short => "p" },
- { option => "language", type => "l",
- 'values' => [ @LinuxDocTools::Lang::Languages ], short => "l" },
- { option => "charset", type => "l",
- 'values' => [ "latin", "ascii", "nippon", "euc-kr" ], short => "c" },
- { option => "style", type => "s", short => "S" },
- { option => "tabsize", type => "i", short => "t" },
-# { option => "verbose", type => "f", short => "v" },
- { option => "debug", type => "f", short => "d" },
- { option => "define", type => "s", short => "D" },
- { option => "include", type => "s", short => "i" },
- { option => "pass", type => "s", short => "P" }
- ];
- $global->{backend} = "linuxdoc";
- $global->{papersize} = "a4";
- $global->{language} = "en";
- $global->{charset} = "ascii";
- $global->{style} = "";
- $global->{tabsize} = 8;
- $global->{verbose} = 0;
- $global->{define} = "";
- $global->{debug} = 0;
- $global->{include} = "";
- $global->{pass} = "";
- $global->{InFiles} = [];
- $Formats{$global->{NAME}} = $global; # All formats we know.
- $FmtList{$global->{NAME}} = $global; # List of formats for help msgs.
-
- # automatic language detection: disabled by default
- # {
- # my $lang;
- # foreach $lang (@LinuxDocTools::Lang::Languages)
- # {
- # if (($ENV{"LC_ALL"} =~ /^$lang/i) ||
- # ($ENV{"LC_CTYPE"} =~ /^$lang/i) ||
- # ($ENV{"LANG"} =~ /^$lang/i)) {
- # $global->{language} = Any2ISO($lang);
- # }
- # }
- # }
-
- #
- # Used when the format is "global" (from sgmlcheck).
- #
- $global->{preNSGMLS} = sub {
- $global->{NsgmlsOpts} .= " -s ";
- $global->{NsgmlsPrePipe} = "cat $global->{file}";
- };
-
- #
- # Build up the list of formatters.
- #
- my $savdir = cwd;
- my %Locs;
- chdir "$main::DataDir/dist";
- my $dir = new DirHandle(".");
- die "Unable to read directory $main::DataDir/dist: $!" unless defined($dir);
- foreach my $fmt (grep(/^fmt_.*\.pl$/, $dir->read()))
- {
- $Locs{$fmt} = "dist";
- }
- $dir->close();
- chdir "$main::DataDir/site";
- $dir = new DirHandle(".");
- die "Unable to read directory $main::DataDir/site: $!" unless defined($dir);
- foreach my $fmt (grep(/^fmt_.*\.pl$/, $dir->read()))
- {
- $Locs{$fmt} = "site";
- }
- $dir->close();
- foreach my $fmt (keys %Locs)
- {
- require $fmt;
- }
- chdir $savdir;
-}
-
-=item LinuxDocTools::process_options ($0, @ARGV)
-
-This function contains all initialization that is bound to the current
-invocation of LinuxDocTools. It looks in C<$0> to deduce the backend that
-should be used (ld2txt activates the I<txt> backend) and parses the
-options array. It returns an array of filenames it encountered during
-option processing.
-
-As a side effect, the environment variables I<SGMLDECL> and
-I<SGML_CATALOG_FILES> are modified.
-
-=cut
-
-sub process_options
-{
- my $progname = shift;
- my @args = @_;
-
- #
- # Deduce the format from the caller's file name
- #
- my ($format, $dummy1, $dummy2) = fileparse ($progname, "");
- $global->{myname} = $format;
- $format =~ s/sgml2*(.*)/$1/;
-
- #
- # check the option "--backend / -B"
- #
- if ($format eq "linuxdoc") {
- my @backends = @args;
- my $arg;
- while (@backends) {
- $arg = shift @backends;
- if ($arg eq "-B") {
- $arg = shift @backends;
- $format = $arg;
- last;
- }
- if ( $arg =~ s/--backend=(.*)/$1/ ) {
- $format = $arg;
- last;
- }
- }
- }
-
- $format = "global" if $format eq "check";
- usage ("") if $format eq "linuxdoc";
- $format = "latex2e" if $format eq "latex";
- $FmtList{$format} = $Formats{$format} or
- usage ("$global->{myname}: unknown format");
- $global->{format} = $format;
-
- #
- # Parse all the options.
- #
- my @files = LinuxDocTools::Utils::process_options (@args);
- $global->{language} = Any2ISO ($global->{language});
- #
- # check the number of given files
- $#files > -1 || usage ("no filenames given");
-
- #
- # Setup the SGML environment.
- # (Note that Debian package rewrite path to catalog of
- # iso-entities using debian/rules so that it can use
- # entities from sgml-data pacakge. debian/rules also
- # removes iso-entites sub directory after doing make install.)
- #
- $ENV{SGML_CATALOG_FILES} .= (defined $ENV{SGML_CATALOG_FILES} ? ":" : "") .
- "$main::prefix/share/sgml/sgml-iso-entities-8879.1986/catalog:" .
- "$main::prefix/share/sgml/entities/sgml-iso-entities-8879.1986/catalog";
- $ENV{SGML_CATALOG_FILES} .= ":$main::DataDir/linuxdoc-tools.catalog";
- $ENV{SGML_CATALOG_FILES} .= ":$main::/etc/sgml.catalog";
- if (-f "$main::DataDir/dtd/$format.dcl")
- {
- $ENV{SGMLDECL} = "$main::DataDir/dtd/$format.dcl";
- }
- elsif (-f "$main::DataDir/dtd/$global->{style}.dcl")
- {
- $ENV{SGMLDECL} = "$main::DataDir/dtd/$global->{style}.dcl";
- }
- elsif (-f "$main::DataDir/dtd/sgml.dcl")
- {
- $ENV{SGMLDECL} = "$main::DataDir/dtd/sgml.dcl";
- }
-
- #
- # OK. Give the list of files we distilled from the options
- # back to the caller.
- #
- return @files;
-}
-
-=item LinuxDocTools::process_file
-
-With all the configuration done, this routine will take a single filename
-and convert it to the currently active backend format. The conversion is
-done in a number of steps in tight interaction with the currently active
-backend (see also L<LinuxDocTools::BackEnd>):
-
-=over
-
-=item 1. Backend: set NSGMLS options and optionally create a pre-NSGMLS pipe.
-
-=item 2. Here: Run the preprocessor to handle conditionals.
-
-=item 3. Here: Run NSGMLS.
-
-=item 4. Backend: run pre-ASP conversion.
-
-=item 5. Here: Run SGMLSASP.
-
-=item 6. Backend: run post-ASP conversion, generating the output.
-
-=back
-
-All stages are influenced by command-line settings, currently active format,
-etcetera. See the code for details.
-
-=cut
-
-sub process_file
-{
- my $file = shift (@_);
- my $saved_umask = umask;
-
- print "Processing file $file\n";
- umask 0077;
-
- my ($filename, $filepath, $filesuffix) = fileparse ($file, "\.sgml");
- my $tmpnam = $filepath . '/' . $filename;
- $file = $tmpnam . $filesuffix;
- -f $file || $file =~ /.*.sgml$/ || ($file .= '.sgml');
- -f $file || ($file = $tmpnam . '.SGML');
- -f $file || die "Cannot find $file\n";
- $global->{filename} = $filename;
- $global->{file} = $file;
- $global->{filepath} = $filepath;
-
- my $tmp = new FileHandle "<$file";
- my $dtd;
- while ( <$tmp> )
- {
- tr/A-Z/a-z/;
- # check for [<!doctype ... system] type definition
- if ( /<!doctype\s*(\w*)\s*system/ )
- {
- $dtd = $1;
- last;
- }
- # check for <!doctype ... PUBLIC ... DTD ...
- if ( /<!doctype\s*\w*\s*public\s*.*\/\/dtd\s*(\w*)/mi )
- {
- $dtd = $1;
- last;
- }
- # check for <!doctype ...
- # PUBLIC ... DTD ...
- # (multi-line version)
- if ( /<!doctype\s*(\w*)/ )
- {
- $dtd = "precheck";
- next;
- }
- if ( /\s*public\s*.*\/\/dtd\s*(\w*)/ && $dtd eq "precheck" )
- {
- $dtd = $1;
- last;
- }
- }
- $tmp->close;
- if ( $global->{debug} )
- {
- print "DTD: " . $dtd . "\n";
- }
- $global->{dtd} = $dtd;
-
- # prepare temporary directory
- my $tmpdir = $ENV{'TMPDIR'} || '/tmp';
- $tmpdir = $tmpdir . '/' . 'linuxdoc-dir-' . $$;
- mkdir ($tmpdir, 0700) ||
- die " - temporary files can not be created, aborted - \n";
-
- my $tmpbase = $global->{tmpbase} = $tmpdir . '/sgmltmp.' . $filename;
- $ENV{"SGML_SEARCH_PATH"} .= ":$filepath";
-
- #
- # Set up the preprocessing command. Conditionals have to be
- # handled here until they can be moved into the DTD, otherwise
- # a validating SGML parser will choke on them.
- #
- # check if output option for latex is pdf or not
- if ($global->{format} eq "latex2e")
- {
- if ($Formats{$global->{format}}{output} eq "pdf")
- {
- $global->{define} .= " pdflatex=yes";
- }
- }
- #
-
- local $ENV{PATH} = "$ENV{PATH}:/usr/lib/linuxdoc-tools";
- my($precmd) = "|sgmlpre output=$global->{format} $global->{define}";
-
- #
- # You can hack $NsgmlsOpts here, etcetera.
- #
- $global->{NsgmlsOpts} .= "-D $main::prefix/share/sgml -D $main::DataDir";
- $global->{NsgmlsOpts} .= "-i$global->{include}" if ($global->{include});
- $global->{NsgmlsPrePipe} = "NOTHING";
- if ( defined $Formats{$global->{format}}{preNSGMLS} )
- {
- $global->{NsgmlsPrePipe} = &{$Formats{$global->{format}}{preNSGMLS}};
- }
-
- #
- # Run the prepocessor and nsgmls.
- #
- my ($ifile, $writensgmls);
-
- if ($global->{NsgmlsPrePipe} eq "NOTHING")
- {
- $ifile = new FileHandle $file;
- }
- else
- {
- $ifile = new FileHandle "$global->{NsgmlsPrePipe}|";
- }
-
- create_temp("$tmpbase.1");
- $writensgmls = new FileHandle
- "$precmd|$main::progs->{NSGMLS} $global->{NsgmlsOpts} $ENV{SGMLDECL} >\"$tmpbase.1\"";
- if ($global->{charset} eq "latin")
- {
- while (<$ifile>)
- {
- # Outline these commands later on - CdG
- #change latin1 characters to SGML
- #by Farzad Farid, adapted by Greg Hankins
- s//\&Agrave;/g;
- s//\&Aacute;/g;
- s//\&Acirc;/g;
- s//\&Atilde;/g;
- s//\&Auml;/g;
- s//\&Aring;/g;
- s//\&AElig;/g;
- s//\&Ccedil;/g;
- s//\&Egrave;/g;
- s//\&Eacute;/g;
- s//\&Ecirc;/g;
- s//\&Euml;/g;
- s//\&Igrave;/g;
- s//\&Iacute;/g;
- s//\&Icirc;/g;
- s//\&Iuml;/g;
- s//\&Ntilde;/g;
- s//\&Ograve;/g;
- s//\&Oacute;/g;
- s//\&Ocirc;/g;
- s//\&Otilde;/g;
- s//\&Ouml;/g;
- s//\&Oslash;/g;
- s//\&Ugrave;/g;
- s//\&Uacute;/g;
- s//\&Ucirc;/g;
- s//\&Uuml;/g;
- s//\&Yacute;/g;
- s//\&THORN;/g;
- s//\&szlig;/g;
- s//\&agrave;/g;
- s//\&aacute;/g;
- s//\&acirc;/g;
- s//\&atilde;/g;
- s//\&auml;/g;
- s//\&aring;/g;
- s//\&aelig;/g;
- s//\&ccedil;/g;
- s//\&egrave;/g;
- s//\&eacute;/g;
- s//\&ecirc;/g;
- s//\&euml;/g;
- s//\&igrave;/g;
- s//\&iacute;/g;
- s//\&icirc;/g;
- s//\&iuml;/g;
- s//\&mu;/g;
- s//\&eth;/g;
- s//\&ntilde;/g;
- s//\&ograve;/g;
- s//\&oacute;/g;
- s//\&ocirc;/g;
- s//\&otilde;/g;
- s//\&ouml;/g;
- s//\&oslash;/g;
- s//\&ugrave;/g;
- s//\&uacute;/g;
- s//\&ucirc;/g;
- s//\&uuml;/g;
- s//\&yacute;/g;
- s//\&thorn;/g;
- s//\&yuml;/g;
- print $writensgmls $_;
- }
- }
- else
- {
- while (<$ifile>)
- {
- print $writensgmls $_;
- }
- }
- $ifile->close;
- $writensgmls->close;
-
- #
- # Special case: if format is global, we're just checking.
- #
- $global->{format} eq "global" && cleanup;
-
- #
- # If the output file is empty, something went wrong.
- #
- ! -e "$tmpbase.1" and die "can't create file - exiting";
- -z "$tmpbase.1" and die "SGML parsing error - exiting";
- if ( $global->{debug} )
- {
- print "Nsgmls stage finished.\n";
- }
-
- #
- # If a preASP stage is defined, let the format handle it.
- #
- # preASP ($inhandle, $outhandle);
- #
- my $inpreasp = new FileHandle "<$tmpbase.1";
- my $outpreasp = new FileHandle "$tmpbase.2",O_WRONLY|O_CREAT|O_EXCL,0600;
- if (defined $Formats{$global->{format}}{preASP})
- {
- &{$Formats{$global->{format}}{preASP}}($inpreasp, $outpreasp) == 0 or
- die "error pre-processing $global->{format}.\n";
- }
- else
- {
- copy ($inpreasp, $outpreasp);
- }
- $inpreasp->close;
- $outpreasp->close;
- ! -e "$tmpbase.2" and die "can't create file - exiting";
-
- if ( $global->{debug} )
- {
- print "PreASP stage finished.\n";
- }
-
- #
- # Run sgmlsasp, with an optional style if specified.
- #
- # Search order:
- # - datadir/site/<dtd>/<format>
- # - datadir/dist/<dtd>/<format>
- # So we need to fetch the doctype from the intermediate.
- #
- # Note: this is a very simplistic check - but as far as I know,
- # it is correct. Am I right?
- #
- my $tmp = new FileHandle "<$tmpbase.2";
- my $dtd;
- while ( ($dtd = <$tmp>) && ! ( $dtd =~ /^\(/) ) { };
- $tmp->close;
- $dtd =~ s/^\(//;
- $dtd =~ tr/A-Z/a-z/;
- chop $dtd;
- $global->{dtd} = $dtd;
-
- my $style = "";
- if ($global->{style})
- {
- $style = "$main::DataDir/site/$dtd/$global->{format}/$global->{style}mapping";
- -r $style or
- $style = "$main::DataDir/dist/$dtd/$global->{format}/$global->{style}mapping";
- }
- my $mapping = "$main::DataDir/site/$dtd/$global->{format}/mapping";
- -r $mapping or $mapping = "$main::DataDir/dist/$dtd/$global->{format}/mapping";
-
- $global->{charset} = "nippon" if ($global->{language} eq "ja");
- #
- # we don't have Korean groff so charset should be latin1.
- #
- if ($global->{language} eq "ko")
- {
- if ($global->{format} eq "groff")
- {
- $global->{charset} = "latin1";
- }
- else
- {
- $global->{charset} = "euc-kr";
- }
- }
-
- if ($global->{format} eq "groff" or $global->{format} eq "latex2e")
- {
- if ($dtd eq "linuxdoctr")
- {
- $mapping = "$main::DataDir/dist/$dtd/$global->{format}/tr-mapping";
- }
- }
-
- create_temp("$tmpbase.3");
- system ("$main::progs->{SGMLSASP} $style $mapping <\"$tmpbase.2\" |
- expand -$global->{tabsize} >\"$tmpbase.3\"");
- ! -e "$tmpbase.3" and die "can't create file - exiting";
-
-
- if ( $global->{debug} )
- {
- print "ASP stage finished.\n";
- }
-
- #
- # If a postASP stage is defined, let the format handle it.
- # It should leave whatever it thinks is right based on $file.
- #
- # postASP ($inhandle)
- #
- umask $saved_umask;
- my $inpostasp = new FileHandle "<$tmpbase.3";
- if (defined $Formats{$global->{format}}{postASP})
- {
- &{$Formats{$global->{format}}{postASP}}($inpostasp) == 0 or
- die "error post-processing $global->{format}.\n";
- }
- $inpostasp->close;
-
- if ( $global->{debug} )
- {
- print "postASP stage finished.\n";
- }
-
- #
- # All done, remove the temporaries.
- #
- if( !$global->{debug} ) {
- remove_tmpfiles($tmpbase);
- }
-}
-
-=pod
-
-=back
-
-=head1 SEE ALSO
-
-Documentation for various sub-packages of LinuxDocTools.
-
-=head1 AUTHOR
-SGMLTools are written by Cees de Groot, C<E<lt>cg@cdegroot.comE<gt>>,
-and various SGML-Tools contributors as listed in C<CONTRIBUTORS>.
-Taketoshi Sano C<E<lt>sano@debian.org<gt>> rename to LinuxDocTools.
-
-=cut
-1;
diff --git a/doc/Makefile b/doc/Makefile
index f36642be..0d1deb8e 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,8 +1,8 @@
# Force rebuilds
.PHONY: progspell docs progdocs userdocs
-doc-srcdir := $(shell cd $(s) && pwd)
-sgml2 := $(doc-srcdir)/sgml2
+doc-srcdir := $(realpath $(srcdir)/doc)
+toolsdir := $(realpath $(srcdir)/tools)
docs: progdocs userdocs
@@ -23,10 +23,10 @@ $(o)%.sgml: $(s)%.sgml $(objdir)/.dir-stamp
cp $< $@
$(o)%.html: $(o)%.sgml
- cd $(dir $@) && $(sgml2)html $(notdir $<)
+ cd $(dir $@) && $(toolsdir)/linuxdoc -B html $(notdir $<)
$(o)%.tex: $(o)%.sgml
- cd $(dir $@) && $(sgml2)latex --output=tex $(notdir $<)
+ cd $(dir $@) && $(toolsdir)/linuxdoc -B latex --output=tex $(notdir $<)
$(o)%.dvi: $(o)%.tex
cd $(dir $@) && TEXINPUTS=$(TEXINPUTS):$(doc-srcdir)/tex latex $(notdir $<)
@@ -40,7 +40,7 @@ $(o)%.pdf: $(o)%.tex
TEXINPUTS=$(TEXINPUTS):$(doc-srcdir)/tex pdflatex -output-directory=$(dir $@) $<
$(o)%.txt: $(o)%.sgml
- cd $(dir $@) && $(sgml2)txt $(notdir $<)
+ cd $(dir $@) && $(toolsdir)/linuxdoc -B txt $(notdir $<)
$(o)prog.spell: $(o)prog.sgml $(s)prog-spell.sed
sed -f $(lastword $^) <$< >$@
diff --git a/doc/bird.sgml b/doc/bird.sgml
index e4ddded2..1d5ae056 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -14,7 +14,7 @@ configuration - something in config which is not keyword.
(set-fill-column 80)
- Copyright 1999,2000 Pavel Machek <pavel@ucw.cz>, distribute under GPL version 2 or later.
+ Copyright 1999 - 2022 CZ.NIC, z.s.p.o , distribute under GPL version 2 or later.
-->
@@ -23,7 +23,6 @@ configuration - something in config which is not keyword.
<title>BIRD 2.0 User's Guide
<author>
Ondrej Filip <it/&lt;feela@network.cz&gt;/,
-Pavel Machek <it/&lt;pavel@ucw.cz&gt;/,
Martin Mares <it/&lt;mj@ucw.cz&gt;/,
Maria Matejka <it/&lt;mq@jmq.cz&gt;/,
Ondrej Zajicek <it/&lt;santiago@crfreenet.org&gt;/
@@ -252,16 +251,9 @@ The global best route selection algorithm is (roughly) as follows:
</itemize>
<p><label id="dsc-table-sorted">Usually, a routing table just chooses a selected
-route from a list of entries for one network. But if the <cf/sorted/ option is
-activated, these lists of entries are kept completely sorted (according to
-preference or some protocol-dependent metric). This is needed for some features
-of some protocols (e.g. <cf/secondary/ option of BGP protocol, which allows to
-accept not just a selected route, but the first route (in the sorted list) that
-is accepted by filters), but it is incompatible with some other features (e.g.
-<cf/deterministic med/ option of BGP protocol, which activates a way of choosing
-selected route that cannot be described using comparison and ordering). Minor
-advantage is that routes are shown sorted in <cf/show route/, minor disadvantage
-is that it is slightly more computationally expensive.
+route from a list of entries for one network. Optionally, these lists of entries
+are kept completely sorted (according to preference or some protocol-dependent
+metric). See <ref id="rtable-sorted" name="sorted"> table option for details.
<sect>Routes and network types
<label id="routes">
@@ -628,18 +620,73 @@ include "tablename.conf";;
<cf/protocol/ times, and the <cf/iso long ms/ format for <cf/base/ and
<cf/log/ times.
- <tag><label id="opt-table"><m/nettype/ table <m/name/ [sorted]</tag>
- Create a new routing table. The default routing tables <cf/master4/ and
- <cf/master6/ are created implicitly, other routing tables have to be
- added by this command. Option <cf/sorted/ can be used to enable sorting
- of routes, see <ref id="dsc-table-sorted" name="sorted table">
- description for details.
+ <tag><label id="opt-table"><m/nettype/ table <m/name/ [ { <m/option/; [<m/.../] } ]</tag>
+ Define a new routing table. The default routing tables <cf/master4/ and
+ <cf/master6/ are defined implicitly, other routing tables have to be
+ defined by this option. See the <ref id="rtable-opts"
+ name="routing table configuration section"> for routing table options.
<tag><label id="opt-eval">eval <m/expr/</tag>
Evaluates given filter expression. It is used by the developers for testing of filters.
</descrip>
+<sect>Routing table options
+<label id="rtable-opts">
+
+<p>Most routing tables do not need any options and are defined without an option
+block, but there are still some options to tweak routing table behavior. Note
+that implicit tables (<cf/master4/ and <cf/master6/) can be redefined in order
+to set options.
+
+<descrip>
+ <tag><label id="rtable-sorted">sorted <m/switch/</tag>
+ Usually, a routing table just chooses the selected (best) route from a
+ list of routes for each network, while keeping remaining routes unsorted.
+ If enabled, these lists of routes are kept completely sorted (according
+ to preference or some protocol-dependent metric).
+
+ This is needed for some protocol features (e.g. <cf/secondary/ option of
+ BGP protocol, which allows to accept not just a selected route, but the
+ first route (in the sorted list) that is accepted by filters), but it is
+ incompatible with some other features (e.g. <cf/deterministic med/
+ option of BGP protocol, which activates a way of choosing selected route
+ that cannot be described using comparison and ordering). Minor advantage
+ is that routes are shown sorted in <cf/show route/, minor disadvantage
+ is that it is slightly more computationally expensive. Default: off.
+
+ <tag><label id="rtable-trie">trie <m/switch/</tag>
+ BIRD routing tables are implemented with hash tables, which is efficient
+ for exact-match lookups, but inconvenient for longest-match lookups or
+ interval lookups (finding superprefix or subprefixes). This option
+ activates additional trie structure that is used to accelerate these
+ lookups, while using the hash table for exact-match lookups.
+
+ This has advantage for <ref id="rpki" name="RPKI"> (on ROA tables),
+ for <ref id="bgp-gateway" name="recursive next-hops"> (on IGP tables),
+ and is required for <ref id="bgp-validate" name="flowspec validation">
+ (on base IP tables). Another advantage is that interval results (like
+ from <cf/show route in .../ command) are lexicographically sorted. The
+ disadvantage is that trie-enabled routing tables require more memory,
+ which may be an issue especially in multi-table setups. Default: off.
+
+ <tag><label id="rtable-min-settle-time">min settle time <m/time/</tag>
+ Specify a minimum value of the settle time. When a ROA table changes,
+ automatic <ref id="proto-rpki-reload" name="RPKI reload"> may be
+ triggered, after a short settle time. Minimum settle time is a delay
+ from the last ROA table change to wait for more updates. Default: 1 s.
+
+
+ <tag><label id="rtable-max-settle-time">max settle time <m/time/</tag>
+ Specify a maximum value of the settle time. When a ROA table changes,
+ automatic <ref id="proto-rpki-reload" name="RPKI reload"> may be
+ triggered, after a short settle time. Maximum settle time is an upper
+ limit to the settle time from the initial ROA table change even if
+ there are consecutive updates gradually renewing the settle time.
+ Default: 20 s.
+</descrip>
+
+
<sect>Protocol options
<label id="protocol-opts">
@@ -776,7 +823,7 @@ agreement").
protocol packets are processed in the local TX queues. This option is
Linux specific. Default value is 7 (highest priority, privileged traffic).
- <tag><label id="proto-pass">password "<m/password/" [ { <m>password options</m> } ]</tag>
+ <tag><label id="proto-pass">password "<m/password/" | <m/hex_key/ [ { <m>password options</m> } ] </tag>
Specifies a password that can be used by the protocol as a shared secret
key. Password option can be used more times to specify more passwords.
If more passwords are specified, it is a protocol-dependent decision
@@ -784,10 +831,14 @@ agreement").
authentication is enabled, authentication can be enabled by separate,
protocol-dependent <cf/authentication/ option.
- This option is allowed in BFD, OSPF and RIP protocols. BGP has also
- <cf/password/ option, but it is slightly different and described
- separately.
- Default: none.
+ A password can also be specified as a hexadecimal key. <m/hex_key/ is a
+ sequence of hexadecimal digit pairs, optionally colon-separated. A key
+ specified this way must be at least 16 bytes (32 digits) long (although
+ specific algorithms can impose other restrictions).
+
+ This option is allowed in BFD, OSPF, RIP, and Babel protocols. BGP has
+ also <cf/password/ option, but it is slightly different and described
+ separately. Default: none.
</descrip>
<p>Password option can contain section with some (not necessary all) password sub-options:
@@ -820,11 +871,11 @@ agreement").
<tag><label id="proto-pass-to">to "<m/time/"</tag>
Shorthand for setting both <cf/generate to/ and <cf/accept to/.
- <tag><label id="proto-pass-algorithm">algorithm ( keyed md5 | keyed sha1 | hmac sha1 | hmac sha256 | hmac sha384 | hmac sha512 )</tag>
+ <tag><label id="proto-pass-algorithm">algorithm ( keyed md5 | keyed sha1 | hmac sha1 | hmac sha256 | hmac sha384 | hmac sha512 | blake2s128 | blake2s256 | blake2b256 | blake2b512 )</tag>
The message authentication algorithm for the password when cryptographic
authentication is enabled. The default value depends on the protocol.
- For RIP and OSPFv2 it is Keyed-MD5 (for compatibility), for OSPFv3
- protocol it is HMAC-SHA-256.
+ For RIP and OSPFv2 it is Keyed-MD5 (for compatibility), for OSPFv3 and
+ Babel it is HMAC-SHA-256.
</descrip>
@@ -1288,6 +1339,9 @@ in the foot).
The same syntax can also be used to construct a pair from two arbitrary
integer expressions (for example <cf/(1+2,a)/).
+ Operators <cf/.asn/ and <cf/.data/ can be used to extract corresponding
+ components of a pair: <cf>(<m/asn/, <m/data/)</cf>.
+
<tag><label id="type-quad">quad</tag>
This is a dotted quad of numbers used to represent router IDs (and
others). Each component can have a value from 0 to 255. Literals of
@@ -1378,6 +1432,10 @@ in the foot).
pairs, LCs can be constructed using expressions for its parts, (e.g.
<cf/(myas, 10+20, 3*10)/, where <cf/myas/ is an integer variable).
+ Operators <cf/.asn/, <cf/.data1/, and <cf/.data2/ can be used
+ to extract corresponding components of LCs:
+ <cf>(<m/asn/, <m/data1/, <m/data2/)</cf>.
+
<tag><label id="type-set">int|pair|quad|ip|prefix|ec|lc|enum set</tag>
Filters recognize four types of sets. Sets are similar to strings: you
can pass them around but you can't modify them. Literals of type <cf>int
@@ -1521,7 +1579,7 @@ in the foot).
Clist is similar to a set, except that unlike other sets, it can be
modified. The type is used for community list (a set of pairs) and for
cluster list (a set of quads). There exist no literals of this type.
- There are three special operators on clists:
+ There are special operators on clists:
<cf><m/C/.len</cf> returns the length of clist <m/C/.
@@ -1548,6 +1606,15 @@ in the foot).
<cf><m/C/.add(<m/P/);</cf> if <m/C/ is appropriate route attribute (for
example <cf/bgp_community/). Similarly for <cf/delete/ and <cf/filter/.
+ <cf><m/C/.min</cf> returns the minimum element of clist <m/C/.
+
+ <cf><m/C/.max</cf> returns the maximum element of clist <m/C/.
+
+ Operators <cf/.min/, <cf/.max/ can be used together with <cf/filter/
+ to extract the community from the specific subset of communities
+ (e.g. localpref or prepend) without the need to check every possible
+ value (e.g. <cf/filter(bgp_community, [(23456, 1000..1099)]).min/).
+
<tag><label id="type-eclist">eclist</tag>
Eclist is a data type used for BGP extended community lists. Eclists
are very similar to clists, but they are sets of ECs instead of pairs.
@@ -1716,6 +1783,15 @@ Common route attributes are:
are merged to one ECMP route during export to the Kernel protocol
(with active <ref id="krt-merge-paths" name="marge paths"> option).
+ <tag><label id="rta-gw-mpls"><m/int/ gw_mpls</tag>
+ Outgoing MPLS label attached to route (i.e., incoming MPLS label on the
+ next hop router for this label-switched path). Reading returns the label
+ value and setting it sets it to the start of the label stack. Setting
+ implicit-NULL label (3) disables the MPLS label stack. Only the first
+ next hop and only one label in the label stack supported right now. This
+ is experimental option, will be likely changed in the future to handle
+ full MPLS label stack.
+
<tag><label id="rta-igp-metric"><m/int/ igp_metric</tag>
The optional attribute that can be used to specify a distance to the
network for routes that do not have a native protocol metric attribute
@@ -1803,6 +1879,19 @@ protocol babel [<name>] {
check link <switch>;
next hop ipv4 <address>;
next hop ipv6 <address>;
+ authentication none|mac [permissive];
+ password "&lt;text&gt;";
+ password "&lt;text&gt;" {
+ id &lt;num&gt;;
+ generate from "&lt;date&gt;";
+ generate to "&lt;date&gt;";
+ accept from "&lt;date&gt;";
+ accept to "&lt;date&gt;";
+ from "&lt;date&gt;";
+ to "&lt;date&gt;";
+ algorithm ( hmac sha1 | hmac sha256 | hmac sha384 |
+ hmac sha512 | blake2s128 | blake2s256 | blake2b256 | blake2b512 );
+ };
};
}
</code>
@@ -1893,6 +1982,24 @@ protocol babel [<name>] {
interface. If not set, the same link-local address that is used as the
source for Babel packets will be used. In normal operation, it should not
be necessary to set this option.
+
+ <tag><label id="babel-authentication">authentication none|mac [permissive]</tag>
+ Selects authentication method to be used. <cf/none/ means that packets
+ are not authenticated at all, <cf/mac/ means MAC authentication is
+ performed as described in <rfc id="8967">. If MAC authentication is
+ selected, the <cf/permissive/ suffix can be used to select an operation
+ mode where outgoing packets are signed, but incoming packets will be
+ accepted even if they fail authentication. This can be useful for
+ incremental deployment of MAC authentication across a network. If MAC
+ authentication is selected, a key must be specified with the
+ <cf/password/ configuration option. Default: none.
+
+ <tag><label id="babel-password">password "<m/text/"</tag>
+ Specifies a password used for authentication. See the <ref id="proto-pass"
+ name="password"> common option for a detailed description. The Babel
+ protocol will only accept HMAC-based algorithms or one of the Blake
+ algorithms, and the length of the supplied password string must match the
+ key size used by the selected algorithm.
</descrip>
<sect1>Attributes
@@ -2230,6 +2337,7 @@ avoid routing loops.
<item> <rfc id="8092"> - BGP Large Communities Attribute
<item> <rfc id="8203"> - BGP Administrative Shutdown Communication
<item> <rfc id="8212"> - Default EBGP Route Propagation Behavior without Policies
+<item> <rfc id="9117"> - Revised Validation Procedure for BGP Flow Specifications
</itemize>
<sect1>Route selection rules
@@ -2352,6 +2460,12 @@ using the following configuration parameters:
same address family and using the same local port) should have set
<cf/strict bind/, or none of them. Default: disabled.
+ <tag><label id="bgp-free-bind">free bind <m/switch/</tag>
+ Use IP_FREEBIND socket option for the listening socket, which allows
+ binding to an IP address not (yet) assigned to an interface. Note that
+ all BGP instances that share a listening socket should have the same
+ value of the <cf/freebind/ option. Default: disabled.
+
<tag><label id="bgp-check-link">check link <M>switch</M></tag>
BGP could use hardware link state into consideration. If enabled,
BIRD tracks the link state of the associated interface and when link
@@ -2563,13 +2677,6 @@ using the following configuration parameters:
disabled. Default: on, with automatic fallback to off when received
capability-related error.
- <tag><label id="bgp-advertise-ipv4">advertise ipv4 <m/switch/</tag>
- Advertise IPv4 multiprotocol capability. This is not a correct behavior
- according to the strict interpretation of <rfc id="4760">, but it is
- widespread and required by some BGP implementations (Cisco and Quagga).
- This option is relevant to IPv4 mode with enabled capability
- advertisement only. Default: on.
-
<tag><label id="bgp-advertise-hostname">advertise hostname <m/switch/</tag>
Advertise hostname capability along with the hostname. Default: off.
@@ -2615,7 +2722,7 @@ using the following configuration parameters:
<tag><label id="bgp-error-wait-time">error wait time <m/number/,<m/number/</tag>
Minimum and maximum delay in seconds between a protocol failure (either
- local or reported by the peer) and automatic restart. Doesn't apply
+ local or reported by the peer) and automatic restart. Doesn not apply
when <cf/disable after error/ is configured. If consecutive errors
happen, the delay is increased exponentially until it reaches the
maximum. Default: 60, 300.
@@ -2793,6 +2900,31 @@ be used in explicit configuration.
explicitly (to conserve memory). This option requires that the connected
routing table is <ref id="dsc-table-sorted" name="sorted">. Default: off.
+ <tag><label id="bgp-validate">validate <m/switch/</tag>
+ Apply flowspec validation procedure as described in <rfc id="8955">
+ section 6 and <rfc id="9117">. The Validation procedure enforces that
+ only routers in the forwarding path for a network can originate flowspec
+ rules for that network. The validation procedure should be used for EBGP
+ to prevent injection of malicious flowspec rules from outside, but it
+ should also be used for IBGP to ensure that selected flowspec rules are
+ consistent with selected IP routes. The validation procedure uses an IP
+ routing table (<ref id="bgp-base-table" name="base table">, see below)
+ against which flowspec rules are validated. This option is limited to
+ flowspec channels. Default: off (for compatibility reasons).
+
+ Note that currently the flowspec validation does not work reliably
+ together with <ref id="bgp-import-table" name="import table"> option
+ enabled on flowspec channels.
+
+ <tag><label id="bgp-base-table">base table <m/name/</tag>
+ Specifies an IP table used for the flowspec validation procedure. The
+ table must have enabled <cf/trie/ option, otherwise the validation
+ procedure would not work. The type of the table must be <cf/ipv4/ for
+ <cf/flow4/ channels and <cf/ipv6/ for <cf/flow6/ channels. This option
+ is limited to flowspec channels. Default: the main table of the
+ <cf/ipv4/ / <cf/ipv6/ channel of the same BGP instance, or the
+ <cf/master4/ / <cf/master6/ table if there is no such channel.
+
<tag><label id="bgp-extended-next-hop">extended next hop <m/switch/</tag>
BGP expects that announced next hops have the same address family as
associated network prefixes. This option provides an extension to use
@@ -3189,6 +3321,12 @@ channels.
allows to specify a limit on maximal number of nexthops in one route. By
default, multipath merging is disabled. If enabled, default value of the
limit is 16.
+
+ <tag><label id="krt-netlink-rx-buffer">netlink rx buffer <m/number/</tag> (Linux)
+ Set kernel receive buffer size (in bytes) for the netlink socket. The default
+ value is OS-dependent (from the <file>/proc/sys/net/core/rmem_default</file>
+ file), If you get some "Kernel dropped some netlink message ..." warnings,
+ you may increase this value.
</descrip>
<sect1>Attributes
@@ -5071,20 +5209,23 @@ options (<cf/bfd/ and <cf/weight 1/), the second nexthop has just <cf/weight 2/.
<p>The flow specification are rules for routers and firewalls for filtering
purpose. It is described by <rfc id="5575">. There are 3 types of arguments:
-<m/inet4/ or <m/inet6/ prefixes, bitmasks matching expressions and numbers
+<m/inet4/ or <m/inet6/ prefixes, numeric matching expressions and bitmask
matching expressions.
-Bitmasks matching is written using <m/value/<cf>/</cf><m/mask/ or
-<cf/!/<m/value/<cf>/</cf><m/mask/ pairs. It means that <cf/(/<m/data/ <cf/&/
-<m/mask/<cf/)/ is or is not equal to <m/value/.
-
-Numbers matching is a matching sequence of numbers and ranges separeted by a
+Numeric matching is a matching sequence of numbers and ranges separeted by a
commas (<cf/,/) (e.g. <cf/10,20,30/). Ranges can be written using double dots
<cf/../ notation (e.g. <cf/80..90,120..124/). An alternative notation are
sequence of one or more pairs of relational operators and values separated by
logical operators <cf/&&/ or <cf/||/. Allowed relational operators are <cf/=/,
<cf/!=/, <cf/</, <cf/<=/, <cf/>/, <cf/>=/, <cf/true/ and <cf/false/.
+Bitmask matching is written using <m/value/<cf>/</cf><m/mask/ or
+<cf/!/<m/value/<cf>/</cf><m/mask/ pairs. It means that <cf/(/<m/data/ <cf/&/
+<m/mask/<cf/)/ is or is not equal to <m/value/. It is also possible to use
+multiple value/mask pairs connected by logical operators <cf/&&/ or <cf/||/.
+Note that for negated matches, value must be either zero or equal to bitmask
+(e.g. !0x0/0xf or !0xf/0xf, but not !0x3/0xf).
+
<sect2>IPv4 Flowspec
<p><descrip>
@@ -5122,10 +5263,10 @@ logical operators <cf/&&/ or <cf/||/. Allowed relational operators are <cf/=/,
(0xfff).
<tag><label id="flow-length">length <m/numbers-match/</tag>
- Set a matching packet length (e.g. <cf>length > 1500;</cf>)
+ Set a matching packet length (e.g. <cf>length > 1500</cf>)
<tag><label id="flow-dscp">dscp <m/numbers-match/</tag>
- Set a matching DiffServ Code Point number (e.g. <cf>length > 1500;</cf>).
+ Set a matching DiffServ Code Point number (e.g. <cf>dscp 8..15</cf>).
<tag><label id="flow-fragment">fragment <m/fragmentation-type/</tag>
Set a matching type of packet fragmentation. Allowed fragmentation
@@ -5190,7 +5331,7 @@ protocol static {
next header = 23;
sport > 24 && < 30 || = 40 || 50,60,70..80;
dport = 50;
- tcp flags 0x03/0x0f, !0/0xff || 0x33/0x33;
+ tcp flags 0x03/0x0f && !0/0xff || 0x33/0x33;
fragment !is_fragment || !first_fragment;
label 0xaaaa/0xaaaa && 0x33/0x33;
};
@@ -5294,15 +5435,15 @@ name="atrey.karlin.mff.cuni.cz:/pub/rfc">).
</book>
<!--
-LocalWords: GPL IPv GateD BGPv RIPv OSPFv Linux sgml html dvi sgmltools Pavel
+LocalWords: GPL IPv GateD BGPv RIPv OSPFv Linux sgml html dvi sgmltools
LocalWords: linuxdoc dtd descrip config conf syslog stderr auth ospf bgp Mbps
LocalWords: router's eval expr num birdc ctl UNIX if's enums bool int ip GCC
LocalWords: len ipaddress pxlen netmask enum bgppath bgpmask clist gw md eth
-LocalWords: RTS printn quitbird iBGP AS'es eBGP RFC multiprotocol IGP Machek
+LocalWords: RTS printn quitbird iBGP AS'es eBGP RFC multiprotocol IGP
LocalWords: EGP misconfigurations keepalive pref aggr aggregator BIRD's RTC
LocalWords: OS'es AS's multicast nolisten misconfigured UID blackhole MRTD MTU
LocalWords: uninstalls ethernets IP binutils ANYCAST anycast dest RTD ICMP rfc
LocalWords: compat multicasts nonbroadcast pointopoint loopback sym stats
LocalWords: Perl SIGHUP dd mm yy HH MM SS EXT IA UNICAST multihop Discriminator txt
-LocalWords: proto wildcard Ondrej Filip
+LocalWords: proto wildcard
-->
diff --git a/doc/prog-head.sgml b/doc/prog-head.sgml
index 0eec367e..4daca3a3 100644
--- a/doc/prog-head.sgml
+++ b/doc/prog-head.sgml
@@ -12,9 +12,9 @@
<title>BIRD Programmer's Documentation
<author>
Ondrej Filip <it/&lt;feela@network.cz&gt;/,
-Pavel Machek <it/&lt;pavel@ucw.cz&gt;/,
Martin Mares <it/&lt;mj@ucw.cz&gt;/,
Ondrej Zajicek <it/&lt;santiago@crfreenet.org&gt;/
+Maria Matejka <it/&lt;mq@jmq.cz&gt;/,
</author>
<abstract>
diff --git a/doc/sgml2html b/doc/sgml2html
deleted file mode 100755
index ea8e8c92..00000000
--- a/doc/sgml2html
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/perl
-#
-# sgmltools.in
-#
-# $Id$
-#
-# SGML-Tools driver. Calls all other SGML-Tools components, contains
-# configuration information, etcetera.
-#
-package main;
-
-sub BEGIN
-{
- require 5.004;
-}
-use strict;
-
-use vars qw($prefix $DataDir $BinDir $progs);
-
-use FindBin;
-
-$prefix = "/usr";
-$DataDir = "$FindBin::Bin/sbase";
-$BinDir = "/usr/bin";
-
-use lib "/usr/share/linuxdoc-tools";
-use lib "/usr/perl5";
-use lib "/usr/lib/perl5";
-use lib "/usr/share/perl5";
-$progs = {
- "NSGMLS" => "/usr/bin/nsgmls",
- "SGMLSASP" => "/usr/bin/sgmlsasp",
- "GROFF" => "/usr/bin/groff",
- "GROFFMACRO" => "-ms",
- "AWK" => "/usr/share/linuxdoc-tools/awkwhich"
-};
-
-if (! -x $progs->{"NSGMLS"})
- { $progs->{"NSGMLS"} = "/usr/bin/onsgmls"; }
-
-$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
- (defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
-
-require "$FindBin::Bin/LinuxDocTools.pm";
-&LinuxDocTools::init;
-
-my @FileList = LinuxDocTools::process_options ("html", @ARGV);
-for my $curfile (@FileList)
- {
- LinuxDocTools::process_file ($curfile);
- }
-
-exit 0;
diff --git a/doc/sgml2latex b/doc/sgml2latex
deleted file mode 100755
index 79c6df03..00000000
--- a/doc/sgml2latex
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/perl
-#
-# sgmltools.in
-#
-# $Id$
-#
-# SGML-Tools driver. Calls all other SGML-Tools components, contains
-# configuration information, etcetera.
-#
-package main;
-
-sub BEGIN
-{
- require 5.004;
-}
-use strict;
-
-use vars qw($prefix $DataDir $BinDir $progs);
-
-use FindBin;
-
-$prefix = "/usr";
-$DataDir = "$FindBin::Bin/sbase";
-$BinDir = "/usr/bin";
-
-use lib "/usr/share/linuxdoc-tools";
-use lib "/usr/perl5";
-use lib "/usr/lib/perl5";
-use lib "/usr/share/perl5";
-$progs = {
- "NSGMLS" => "/usr/bin/nsgmls",
- "SGMLSASP" => "/usr/bin/sgmlsasp",
- "GROFF" => "/usr/bin/groff",
- "GROFFMACRO" => "-ms",
- "AWK" => "/usr/share/linuxdoc-tools/awkwhich"
-};
-
-if (! -x $progs->{"NSGMLS"})
- { $progs->{"NSGMLS"} = "/usr/bin/onsgmls"; }
-
-$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
- (defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
-
-require "$FindBin::Bin/LinuxDocTools.pm";
-&LinuxDocTools::init;
-
-my @FileList = LinuxDocTools::process_options ("latex", @ARGV);
-for my $curfile (@FileList)
- {
- LinuxDocTools::process_file ($curfile);
- }
-
-exit 0;
diff --git a/doc/sgml2txt b/doc/sgml2txt
deleted file mode 100755
index 013479fe..00000000
--- a/doc/sgml2txt
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/perl
-#
-# sgmltools.in
-#
-# $Id$
-#
-# SGML-Tools driver. Calls all other SGML-Tools components, contains
-# configuration information, etcetera.
-#
-package main;
-
-sub BEGIN
-{
- require 5.004;
-}
-use strict;
-
-use vars qw($prefix $DataDir $BinDir $progs);
-
-use FindBin;
-
-$prefix = "/usr";
-$DataDir = "$FindBin::Bin/sbase";
-$BinDir = "/usr/bin";
-
-use lib "/usr/share/linuxdoc-tools";
-use lib "/usr/perl5";
-use lib "/usr/lib/perl5";
-use lib "/usr/share/perl5";
-$progs = {
- "NSGMLS" => "/usr/bin/nsgmls",
- "SGMLSASP" => "/usr/bin/sgmlsasp",
- "GROFF" => "/usr/bin/groff",
- "GROFFMACRO" => "-ms",
- "AWK" => "/usr/share/linuxdoc-tools/awkwhich"
-};
-
-if (! -x $progs->{"NSGMLS"})
- { $progs->{"NSGMLS"} = "/usr/bin/onsgmls"; }
-
-$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
- (defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
-
-require "$FindBin::Bin/LinuxDocTools.pm";
-&LinuxDocTools::init;
-
-my @FileList = LinuxDocTools::process_options ("txt", @ARGV);
-for my $curfile (@FileList)
- {
- LinuxDocTools::process_file ($curfile);
- }
-
-exit 0;
diff --git a/filter/config.Y b/filter/config.Y
index 5cd52e40..8916ea97 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -278,14 +278,16 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
IF, THEN, ELSE, CASE,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
- FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT,
+ FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS,
PREFERENCE,
ROA_CHECK, ASN, SRC, DST,
IS_V4, IS_V6,
LEN, MAXLEN,
+ DATA, DATA1, DATA2,
DEFINED,
ADD, DELETE, CONTAINS, RESET,
PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
+ MIN, MAX,
EMPTY,
FILTER, WHERE, EVAL, ATTRIBUTE,
BT_ASSERT, BT_TEST_SUITE, BT_CHECK_ASSIGN, BT_TEST_SAME, FORMAT)
@@ -751,6 +753,7 @@ static_attr:
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
| WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
+ | GW_MPLS { $$ = f_new_static_attr(T_INT, SA_GW_MPLS, 0); }
;
term:
@@ -788,13 +791,18 @@ term:
| term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER, $1); }
| term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
| term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
- | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
+ | term '.' ASN { $$ = f_new_inst(FI_ASN, $1); }
| term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
| term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
| term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
| term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
| term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG, $1); }
+ | term '.' DATA { $$ = f_new_inst(FI_PAIR_DATA, $1); }
+ | term '.' DATA1 { $$ = f_new_inst(FI_LC_DATA1, $1); }
+ | term '.' DATA2 { $$ = f_new_inst(FI_LC_DATA2, $1); }
+ | term '.' MIN { $$ = f_new_inst(FI_MIN, $1); }
+ | term '.' MAX { $$ = f_new_inst(FI_MAX, $1); }
/* Communities */
/* This causes one shift/reduce conflict
diff --git a/filter/data.c b/filter/data.c
index 7c33d2cb..56c1fb17 100644
--- a/filter/data.c
+++ b/filter/data.c
@@ -68,6 +68,17 @@ f_type_name(enum f_type t)
return "?";
}
+enum f_type
+f_type_element_type(enum f_type t)
+{
+ switch(t) {
+ case T_CLIST: return T_PAIR;
+ case T_ECLIST: return T_EC;
+ case T_LCLIST: return T_LC;
+ default: return T_VOID;
+ };
+}
+
const struct f_val f_const_empty_path = {
.type = T_PATH,
.val.ad = &null_adata,
diff --git a/filter/data.h b/filter/data.h
index 61cdb43e..4cb6b7a8 100644
--- a/filter/data.h
+++ b/filter/data.h
@@ -100,6 +100,7 @@ enum f_sa_code {
SA_IFNAME,
SA_IFINDEX,
SA_WEIGHT,
+ SA_GW_MPLS,
} PACKED;
/* Static attribute definition (members of struct rta) */
@@ -139,18 +140,23 @@ struct f_tree {
void *data;
};
+#define TRIE_STEP 4
+#define TRIE_STACK_LENGTH 33
+
struct f_trie_node4
{
ip4_addr addr, mask, accept;
- uint plen;
- struct f_trie_node4 *c[2];
+ u16 plen;
+ u16 local;
+ struct f_trie_node4 *c[1 << TRIE_STEP];
};
struct f_trie_node6
{
ip6_addr addr, mask, accept;
- uint plen;
- struct f_trie_node6 *c[2];
+ u16 plen;
+ u16 local;
+ struct f_trie_node6 *c[1 << TRIE_STEP];
};
struct f_trie_node
@@ -167,9 +173,20 @@ struct f_trie
u8 zero;
s8 ipv4; /* -1 for undefined / empty */
u16 data_size; /* Additional data for each trie node */
+ u32 prefix_count; /* Works only for restricted tries (pxlen == l == h) */
struct f_trie_node root; /* Root trie node */
};
+struct f_trie_walk_state
+{
+ u8 ipv4;
+ u8 accept_length; /* Current inter-node prefix position */
+ u8 start_pos; /* Initial prefix position in stack[0] */
+ u8 local_pos; /* Current intra-node prefix position */
+ u8 stack_pos; /* Current node in stack below */
+ const struct f_trie_node *stack[TRIE_STACK_LENGTH];
+};
+
struct f_tree *f_new_tree(void);
struct f_tree *build_tree(struct f_tree *);
const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val);
@@ -180,13 +197,76 @@ void tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void
struct f_trie *f_new_trie(linpool *lp, uint data_size);
void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
int trie_match_net(const struct f_trie *t, const net_addr *n);
+int trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr_ip4 *dst, ip4_addr *found0);
+int trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr_ip6 *dst, ip6_addr *found0);
+void trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *from);
+int trie_walk_next(struct f_trie_walk_state *s, net_addr *net);
int trie_same(const struct f_trie *t1, const struct f_trie *t2);
void trie_format(const struct f_trie *t, buffer *buf);
+static inline int
+trie_match_next_longest_ip4(net_addr_ip4 *n, ip4_addr *found)
+{
+ while (n->pxlen)
+ {
+ n->pxlen--;
+ ip4_clrbit(&n->prefix, n->pxlen);
+
+ if (ip4_getbit(*found, n->pxlen))
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int
+trie_match_next_longest_ip6(net_addr_ip6 *n, ip6_addr *found)
+{
+ while (n->pxlen)
+ {
+ n->pxlen--;
+ ip6_clrbit(&n->prefix, n->pxlen);
+
+ if (ip6_getbit(*found, n->pxlen))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+#define TRIE_WALK_TO_ROOT_IP4(trie, net, dst) ({ \
+ net_addr_ip4 dst; \
+ ip4_addr _found; \
+ for (int _n = trie_match_longest_ip4(trie, net, &dst, &_found); \
+ _n; \
+ _n = trie_match_next_longest_ip4(&dst, &_found))
+
+#define TRIE_WALK_TO_ROOT_IP6(trie, net, dst) ({ \
+ net_addr_ip6 dst; \
+ ip6_addr _found; \
+ for (int _n = trie_match_longest_ip6(trie, net, &dst, &_found); \
+ _n; \
+ _n = trie_match_next_longest_ip6(&dst, &_found))
+
+#define TRIE_WALK_TO_ROOT_END })
+
+
+#define TRIE_WALK(trie, net, from) ({ \
+ net_addr net; \
+ struct f_trie_walk_state tws_; \
+ trie_walk_init(&tws_, trie, from); \
+ while (trie_walk_next(&tws_, &net))
+
+#define TRIE_WALK_END })
+
+
#define F_CMP_ERROR 999
const char *f_type_name(enum f_type t);
+enum f_type f_type_element_type(enum f_type t);
+
int val_same(const struct f_val *v1, const struct f_val *v2);
int val_compare(const struct f_val *v1, const struct f_val *v2);
void val_format(const struct f_val *v, buffer *buf);
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 1378fe4a..901d2939 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -533,6 +533,7 @@
case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
case SA_WEIGHT: RESULT(sa.f_type, i, rta->nh.weight + 1); break;
+ case SA_GW_MPLS: RESULT(sa.f_type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break;
default:
bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
@@ -569,6 +570,7 @@
rta->nh.iface = n->iface;
rta->nh.next = NULL;
rta->hostentry = NULL;
+ rta->nh.labels = 0;
}
break;
@@ -587,6 +589,7 @@
rta->nh.iface = NULL;
rta->nh.next = NULL;
rta->hostentry = NULL;
+ rta->nh.labels = 0;
}
break;
@@ -601,6 +604,22 @@
rta->nh.iface = ifa;
rta->nh.next = NULL;
rta->hostentry = NULL;
+ rta->nh.labels = 0;
+ }
+ break;
+
+ case SA_GW_MPLS:
+ {
+ if (v1.val.i >= 0x100000)
+ runtime( "Invalid MPLS label" );
+
+ if (v1.val.i != MPLS_NULL)
+ {
+ rta->nh.label[0] = v1.val.i;
+ rta->nh.labels = 1;
+ }
+ else
+ rta->nh.labels = 0;
}
break;
@@ -891,14 +910,31 @@
((net_addr_roa6 *) v1.val.net)->max_pxlen);
}
- INST(FI_ROA_ASN, 1, 1) { /* Get ROA ASN */
- ARG(1, T_NET);
- if (!net_is_roa(v1.val.net))
- runtime( "ROA expected" );
+ INST(FI_ASN, 1, 1) { /* Get ROA ASN or community ASN part */
+ ARG_ANY(1);
+ RESULT_TYPE(T_INT);
+ switch(v1.type)
+ {
+ case T_NET:
+ if (!net_is_roa(v1.val.net))
+ runtime( "ROA expected" );
- RESULT(T_INT, i, (v1.val.net->type == NET_ROA4) ?
- ((net_addr_roa4 *) v1.val.net)->asn :
- ((net_addr_roa6 *) v1.val.net)->asn);
+ RESULT_(T_INT, i, (v1.val.net->type == NET_ROA4) ?
+ ((net_addr_roa4 *) v1.val.net)->asn :
+ ((net_addr_roa6 *) v1.val.net)->asn);
+ break;
+
+ case T_PAIR:
+ RESULT_(T_INT, i, v1.val.i >> 16);
+ break;
+
+ case T_LC:
+ RESULT_(T_INT, i, v1.val.lc.asn);
+ break;
+
+ default:
+ runtime( "Net, pair or lc expected" );
+ }
}
INST(FI_IP, 1, 1) { /* Convert prefix to ... */
@@ -932,6 +968,89 @@
RESULT(T_INT, i, as_path_get_last_nonaggregated(v1.val.ad));
}
+ INST(FI_PAIR_DATA, 1, 1) { /* Get data part from the standard community */
+ ARG(1, T_PAIR);
+ RESULT(T_INT, i, v1.val.i & 0xFFFF);
+ }
+
+ INST(FI_LC_DATA1, 1, 1) { /* Get data1 part from the large community */
+ ARG(1, T_LC);
+ RESULT(T_INT, i, v1.val.lc.ldp1);
+ }
+
+ INST(FI_LC_DATA2, 1, 1) { /* Get data2 part from the large community */
+ ARG(1, T_LC);
+ RESULT(T_INT, i, v1.val.lc.ldp2);
+ }
+
+ INST(FI_MIN, 1, 1) { /* Get minimum element from set */
+ ARG_ANY(1);
+ RESULT_TYPE(f_type_element_type(v1.type));
+ switch(v1.type)
+ {
+ case T_CLIST:
+ {
+ u32 val = 0;
+ int_set_min(v1.val.ad, &val);
+ RESULT_(T_PAIR, i, val);
+ }
+ break;
+
+ case T_ECLIST:
+ {
+ u64 val = 0;
+ ec_set_min(v1.val.ad, &val);
+ RESULT_(T_EC, ec, val);
+ }
+ break;
+
+ case T_LCLIST:
+ {
+ lcomm val = { 0, 0, 0 };
+ lc_set_min(v1.val.ad, &val);
+ RESULT_(T_LC, lc, val);
+ }
+ break;
+
+ default:
+ runtime( "Clist or lclist expected" );
+ }
+ }
+
+ INST(FI_MAX, 1, 1) { /* Get maximum element from set */
+ ARG_ANY(1);
+ RESULT_TYPE(f_type_element_type(v1.type));
+ switch(v1.type)
+ {
+ case T_CLIST:
+ {
+ u32 val = 0;
+ int_set_max(v1.val.ad, &val);
+ RESULT_(T_PAIR, i, val);
+ }
+ break;
+
+ case T_ECLIST:
+ {
+ u64 val = 0;
+ ec_set_max(v1.val.ad, &val);
+ RESULT_(T_EC, ec, val);
+ }
+ break;
+
+ case T_LCLIST:
+ {
+ lcomm val = { 0, 0, 0 };
+ lc_set_max(v1.val.ad, &val);
+ RESULT_(T_LC, lc, val);
+ }
+ break;
+
+ default:
+ runtime( "Clist or lclist expected" );
+ }
+ }
+
INST(FI_RETURN, 1, 1) {
NEVER_CONSTANT;
/* Acquire the return value */
diff --git a/filter/test.conf b/filter/test.conf
index 63af25bb..484628e5 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -335,6 +335,26 @@ ip p;
p = 1234:5678::;
bt_assert(!p.is_v4);
bt_assert(p.mask(24) = 1234:5600::);
+
+ p = 1:2:3:4:5:6:7:8;
+ bt_assert(!p.is_v4);
+ bt_assert(format(p) = "1:2:3:4:5:6:7:8");
+ bt_assert(p.mask(64) = 1:2:3:4::);
+
+ p = 10:20:30:40:50:60:70:80;
+ bt_assert(!p.is_v4);
+ bt_assert(format(p) = "10:20:30:40:50:60:70:80");
+ bt_assert(p.mask(64) = 10:20:30:40::);
+
+ p = 1090:20a0:30b0:40c0:50d0:60e0:70f0:8000;
+ bt_assert(!p.is_v4);
+ bt_assert(format(p) = "1090:20a0:30b0:40c0:50d0:60e0:70f0:8000");
+ bt_assert(p.mask(64) = 1090:20a0:30b0:40c0::);
+
+ p = ::fffe:6:c0c:936d:88c7:35d3;
+ bt_assert(!p.is_v4);
+ bt_assert(format(p) = "::fffe:6:c0c:936d:88c7:35d3");
+ bt_assert(p.mask(64) = 0:0:fffe:6::);
}
bt_test_suite(t_ip, "Testing ip address");
@@ -479,6 +499,33 @@ prefix set pxs;
bt_assert(1.2.0.0/16 ~ [ 1.0.0.0/8{ 15 , 17 } ]);
bt_assert([ 10.0.0.0/8{ 15 , 17 } ] != [ 11.0.0.0/8{ 15 , 17 } ]);
+
+ /* Formatting of prefix sets, some cases are a bit strange */
+ bt_assert(format([ 0.0.0.0/0 ]) = "[0.0.0.0/0]");
+ bt_assert(format([ 10.10.0.0/32 ]) = "[10.10.0.0/32{0.0.0.1}]");
+ bt_assert(format([ 10.10.0.0/17 ]) = "[10.10.0.0/17{0.0.128.0}]");
+ bt_assert(format([ 10.10.0.0/17{17,19} ]) = "[10.10.0.0/17{0.0.224.0}]"); # 224 = 128+64+32
+ bt_assert(format([ 10.10.128.0/17{18,19} ]) = "[10.10.128.0/18{0.0.96.0}, 10.10.192.0/18{0.0.96.0}]"); # 96 = 64+32
+ bt_assert(format([ 10.10.64.0/18- ]) = "[0.0.0.0/0, 0.0.0.0/1{128.0.0.0}, 0.0.0.0/2{64.0.0.0}, 0.0.0.0/3{32.0.0.0}, 10.10.0.0/16{255.255.0.0}, 10.10.0.0/17{0.0.128.0}, 10.10.64.0/18{0.0.64.0}]");
+ bt_assert(format([ 10.10.64.0/18+ ]) = "[10.10.64.0/18{0.0.96.0}, 10.10.64.0/20{0.0.31.255}, 10.10.80.0/20{0.0.31.255}, 10.10.96.0/20{0.0.31.255}, 10.10.112.0/20{0.0.31.255}]");
+
+ bt_assert(format([ 10.10.160.0/19 ]) = "[10.10.160.0/19{0.0.32.0}]");
+ bt_assert(format([ 10.10.160.0/19{19,22} ]) = "[10.10.160.0/19{0.0.32.0}, 10.10.160.0/20{0.0.28.0}, 10.10.176.0/20{0.0.28.0}]"); # 28 = 16+8+4
+ bt_assert(format([ 10.10.160.0/19+ ]) = "[10.10.160.0/19{0.0.32.0}, 10.10.160.0/20{0.0.31.255}, 10.10.176.0/20{0.0.31.255}]");
+
+ bt_assert(format([ ::/0 ]) = "[::/0]");
+ bt_assert(format([ 11:22:33:44:55:66:77:88/128 ]) = "[11:22:33:44:55:66:77:88/128{::1}]");
+ bt_assert(format([ 11:22:33:44::/64 ]) = "[11:22:33:44::/64{0:0:0:1::}]");
+ bt_assert(format([ 11:22:33:44::/64+ ]) = "[11:22:33:44::/64{::1:ffff:ffff:ffff:ffff}]");
+
+ bt_assert(format([ 11:22:33:44::/65 ]) = "[11:22:33:44::/65{::8000:0:0:0}]");
+ bt_assert(format([ 11:22:33:44::/65{65,67} ]) = "[11:22:33:44::/65{::e000:0:0:0}]"); # e = 8+4+2
+ bt_assert(format([ 11:22:33:44:8000::/65{66,67} ]) = "[11:22:33:44:8000::/66{::6000:0:0:0}, 11:22:33:44:c000::/66{::6000:0:0:0}]"); # 6 = 4+2
+ bt_assert(format([ 11:22:33:44:4000::/66- ]) = "[::/0, ::/1{8000::}, ::/2{4000::}, ::/3{2000::}, 11:22:33:44::/64{ffff:ffff:ffff:ffff::}, 11:22:33:44::/65{::8000:0:0:0}, 11:22:33:44:4000::/66{::4000:0:0:0}]");
+ bt_assert(format([ 11:22:33:44:4000::/66+ ]) = "[11:22:33:44:4000::/66{::6000:0:0:0}, 11:22:33:44:4000::/68{::1fff:ffff:ffff:ffff}, 11:22:33:44:5000::/68{::1fff:ffff:ffff:ffff}, 11:22:33:44:6000::/68{::1fff:ffff:ffff:ffff}, 11:22:33:44:7000::/68{::1fff:ffff:ffff:ffff}]");
+ bt_assert(format([ 11:22:33:44:c000::/67 ]) = "[11:22:33:44:c000::/67{::2000:0:0:0}]");
+ bt_assert(format([ 11:22:33:44:c000::/67{67,71} ]) = "[11:22:33:44:c000::/67{::2000:0:0:0}, 11:22:33:44:c000::/68{::1e00:0:0:0}, 11:22:33:44:d000::/68{::1e00:0:0:0}]");
+ bt_assert(format([ 11:22:33:44:c000::/67+ ]) = "[11:22:33:44:c000::/67{::2000:0:0:0}, 11:22:33:44:c000::/68{::1fff:ffff:ffff:ffff}, 11:22:33:44:d000::/68{::1fff:ffff:ffff:ffff}]");
}
bt_test_suite(t_prefix_set, "Testing prefix sets");
@@ -558,6 +605,12 @@ prefix set pxs;
bt_assert(2000::/29 !~ pxs);
bt_assert(1100::/10 !~ pxs);
bt_assert(2010::/26 !~ pxs);
+
+ pxs = [ 52E0::/13{13,128} ];
+ bt_assert(52E7:BE81:379B:E6FD:541F:B0D0::/93 ~ pxs);
+
+ pxs = [ 41D8:8718::/30{0,30}, 413A:99A8:6C00::/38{38,128} ];
+ bt_assert(4180::/9 ~ pxs);
}
bt_test_suite(t_prefix6_set, "Testing prefix IPv6 sets");
@@ -579,10 +632,11 @@ prefix p;
bt_assert(format(flow6 { sport 0..0x400; }) = "flow6 { sport 0..1024; }");
bt_assert(format(flow6 { icmp type 80; }) = "flow6 { icmp type 80; }");
bt_assert(format(flow6 { icmp code 90; }) = "flow6 { icmp code 90; }");
- bt_assert(format(flow6 { tcp flags 0x03/0x0f; }) = "flow6 { tcp flags 0x3/0x3,0x0/0xc; }");
+ bt_assert(format(flow6 { tcp flags 0x03/0x0f; }) = "flow6 { tcp flags 0x3/0x3 && 0x0/0xc; }");
bt_assert(format(flow6 { length 0..65535; }) = "flow6 { length 0..65535; }");
bt_assert(format(flow6 { dscp = 63; }) = "flow6 { dscp 63; }");
bt_assert(format(flow6 { fragment is_fragment || !first_fragment; }) = "flow6 { fragment is_fragment || !first_fragment; }");
+ bt_assert(format(flow6 { label 1000..2000; }) = "flow6 { label 1000..2000; }");
bt_assert(format(flow6 { }) = "flow6 { }");
}
@@ -683,6 +737,11 @@ clist l;
clist l2;
clist r;
{
+ bt_assert((10, 20).asn = 10);
+ bt_assert((10, 20).data = 20);
+ bt_assert(p23.asn = 2);
+ bt_assert(p23.data = 3);
+
l = - empty -;
bt_assert(l !~ [(*,*)]);
bt_assert((l ~ [(*,*)]) != (l !~ [(*,*)]));
@@ -775,6 +834,12 @@ clist r;
r = filter(l, [(3,1), (*,2)]);
bt_assert(r = add(add(-empty-, (3,1)), (3,2)));
bt_assert(format(r) = "(clist (3,1) (3,2))");
+
+ # minimim & maximum element
+ r = add(add(add(add(add(-empty-, (2,1)), (1,3)), (2,2)), (3,1)), (2,3));
+ bt_assert(format(r) = "(clist (2,1) (1,3) (2,2) (3,1) (2,3))");
+ bt_assert(r.min = (1,3));
+ bt_assert(r.max = (3,1));
}
bt_test_suite(t_clist, "Testing lists of communities");
@@ -880,6 +945,12 @@ eclist r;
r = filter(el, [(rt, 10, 1), (rt, 10, 25..30), (ro, 10, 40)]);
bt_assert(r = add(add(--empty--, (rt, 10, 1)), (rt, 10, 30)));
bt_assert(format(r) = "(eclist (rt, 10, 1) (rt, 10, 30))");
+
+ # minimim & maximum element
+ r = add(add(add(add(add(--empty--, (rt, 2, 1)), (rt, 1, 3)), (rt, 2, 2)), (rt, 3, 1)), (rt, 2, 3));
+ bt_assert(format(r) = "(eclist (rt, 2, 1) (rt, 1, 3) (rt, 2, 2) (rt, 3, 1) (rt, 2, 3))");
+ bt_assert(r.min = (rt, 1, 3));
+ bt_assert(r.max = (rt, 3, 1));
}
bt_test_suite(t_eclist, "Testing lists of extended communities");
@@ -939,6 +1010,10 @@ lclist r;
bt_assert(---empty--- = ---empty---);
bt_assert((10, 20, 30) !~ ---empty---);
+ bt_assert((10, 20, 30).asn = 10);
+ bt_assert((10, 20, 30).data1 = 20);
+ bt_assert((10, 20, 30).data2 = 30);
+
ll = --- empty ---;
ll = add(ll, (ten, 20, 30));
ll = add(ll, (1000, 2000, 3000));
@@ -985,6 +1060,12 @@ lclist r;
r = filter(ll, [(5..15, *, *), (20, 15..25, *)]);
bt_assert(r = add(add(---empty---, (10, 10, 10)), (20, 20, 20)));
bt_assert(format(r) = "(lclist (10, 10, 10) (20, 20, 20))");
+
+ # minimim & maximum element
+ r = add(add(add(add(add(---empty---, (2, 3, 3)), (1, 2, 3)), (2, 3, 1)), (3, 1, 2)), (2, 1, 3));
+ bt_assert(format(r) = "(lclist (2, 3, 3) (1, 2, 3) (2, 3, 1) (3, 1, 2) (2, 1, 3))");
+ bt_assert(r.min = (1, 2, 3));
+ bt_assert(r.max = (3, 1, 2));
}
bt_test_suite(t_lclist, "Testing lists of large communities");
diff --git a/filter/trie.c b/filter/trie.c
index 1a4e1ac3..12ba0b82 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -1,7 +1,8 @@
/*
* Filters: Trie for prefix sets
*
- * Copyright 2009 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2021 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2021 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -9,53 +10,68 @@
/**
* DOC: Trie for prefix sets
*
- * We use a (compressed) trie to represent prefix sets. Every node
- * in the trie represents one prefix (&addr/&plen) and &plen also
- * indicates the index of the bit in the address that is used to
- * branch at the node. If we need to represent just a set of
- * prefixes, it would be simple, but we have to represent a
- * set of prefix patterns. Each prefix pattern consists of
- * &ppaddr/&pplen and two integers: &low and &high, and a prefix
- * &paddr/&plen matches that pattern if the first MIN(&plen, &pplen)
- * bits of &paddr and &ppaddr are the same and &low <= &plen <= &high.
- *
- * We use a bitmask (&accept) to represent accepted prefix lengths
- * at a node. As there are 33 prefix lengths (0..32 for IPv4), but
- * there is just one prefix of zero length in the whole trie so we
- * have &zero flag in &f_trie (indicating whether the trie accepts
- * prefix 0.0.0.0/0) as a special case, and &accept bitmask
+ * We use a (compressed) trie to represent prefix sets. Every node in the trie
+ * represents one prefix (&addr/&plen) and &plen also indicates the index of
+ * bits in the address that are used to branch at the node. Note that such
+ * prefix is not necessary a member of the prefix set, it is just a canonical
+ * prefix associated with a node. Prefix lengths of nodes are aligned to
+ * multiples of &TRIE_STEP (4) and there is 16-way branching in each
+ * node. Therefore, we say that a node is associated with a range of prefix
+ * lengths (&plen .. &plen + TRIE_STEP - 1).
+ *
+ * The prefix set is not just a set of prefixes, it is defined by a set of
+ * prefix patterns. Each prefix pattern consists of &ppaddr/&pplen and two
+ * integers: &low and &high. The tested prefix &paddr/&plen matches that pattern
+ * if the first MIN(&plen, &pplen) bits of &paddr and &ppaddr are the same and
+ * &low <= &plen <= &high.
+ *
+ * There are two ways to represent accepted prefixes for a node. First, there is
+ * a bitmask &local, which represents independently all 15 prefixes that extend
+ * the canonical prefix of the node and are within a range of prefix lengths
+ * associated with the node. E.g., for node 10.0.0.0/8 they are 10.0.0.0/8,
+ * 10.0.0.0/9, 10.128.0.0/9, .. 10.224.0.0/11. This order (first by length, then
+ * lexicographically) is used for indexing the bitmask &local, starting at
+ * position 1. I.e., index is 2^(plen - base) + offset within the same length,
+ * see function trie_local_mask6() for details.
+ *
+ * Second, we use a bitmask &accept to represent accepted prefix lengths at a
+ * node. The bit is set means that all prefixes of given length that are either
+ * subprefixes or superprefixes of the canonical prefix are accepted. As there
+ * are 33 prefix lengths (0..32 for IPv4), but there is just one prefix of zero
+ * length in the whole trie so we have &zero flag in &f_trie (indicating whether
+ * the trie accepts prefix 0.0.0.0/0) as a special case, and &accept bitmask
* represents accepted prefix lengths from 1 to 32.
*
- * There are two cases in prefix matching - a match when the length
- * of the prefix is smaller that the length of the prefix pattern,
- * (&plen < &pplen) and otherwise. The second case is simple - we
- * just walk through the trie and look at every visited node
- * whether that prefix accepts our prefix length (&plen). The
- * first case is tricky - we don't want to examine every descendant
- * of a final node, so (when we create the trie) we have to propagate
- * that information from nodes to their ascendants.
- *
- * Suppose that we have two masks (M1 and M2) for a node. Mask M1
- * represents accepted prefix lengths by just the node and mask M2
- * represents accepted prefix lengths by the node or any of its
- * descendants. Therefore M2 is a bitwise or of M1 and children's
- * M2 and this is a maintained invariant during trie building.
- * Basically, when we want to match a prefix, we walk through the trie,
- * check mask M1 for our prefix length and when we came to
- * final node, we check mask M2.
- *
- * There are two differences in the real implementation. First,
- * we use a compressed trie so there is a case that we skip our
- * final node (if it is not in the trie) and we came to node that
- * is either extension of our prefix, or completely out of path
- * In the first case, we also have to check M2.
- *
- * Second, we really need not to maintain two separate bitmasks.
- * Checks for mask M1 are always larger than &applen and we need
- * just the first &pplen bits of mask M2 (if trie compression
- * hadn't been used it would suffice to know just $applen-th bit),
- * so we have to store them together in &accept mask - the first
- * &pplen bits of mask M2 and then mask M1.
+ * One complication is handling of prefix patterns with unaligned prefix length.
+ * When such pattern is to be added, we add a primary node above (with rounded
+ * down prefix length &nlen) and a set of secondary nodes below (with rounded up
+ * prefix lengths &slen). Accepted prefix lengths of the original prefix pattern
+ * are then represented in different places based on their lengths. For prefixes
+ * shorter than &nlen, it is &accept bitmask of the primary node, for prefixes
+ * between &nlen and &slen - 1 it is &local bitmask of the primary node, and for
+ * prefixes longer of equal &slen it is &accept bitmasks of secondary nodes.
+ *
+ * There are two cases in prefix matching - a match when the length of the
+ * prefix is smaller that the length of the prefix pattern, (&plen < &pplen) and
+ * otherwise. The second case is simple - we just walk through the trie and look
+ * at every visited node whether that prefix accepts our prefix length (&plen).
+ * The first case is tricky - we do not want to examine every descendant of a
+ * final node, so (when we create the trie) we have to propagate that
+ * information from nodes to their ascendants.
+ *
+ * There are two kinds of propagations - propagation from child's &accept
+ * bitmask to parent's &accept bitmask, and propagation from child's &accept
+ * bitmask to parent's &local bitmask. The first kind is simple - as all
+ * superprefixes of a parent are also all superprefixes of appropriate length of
+ * a child, then we can just add (by bitwise or) a child &accept mask masked by
+ * parent prefix length mask to the parent &accept mask. This handles prefixes
+ * shorter than node &plen.
+ *
+ * The second kind of propagation is necessary to handle superprefixes of a
+ * child that are represented by parent &local mask - that are in the range of
+ * prefix lengths associated with the parent. For each accepted (by child
+ * &accept mask) prefix length from that range, we need to set appropriate bit
+ * in &local mask. See function trie_amask_to_local() for details.
*
* There are four cases when we walk through a trie:
*
@@ -65,8 +81,32 @@
* - we are beyond the end of path (node length > &plen)
* - we are still on path and keep walking (node length < &plen)
*
- * The walking code in trie_match_prefix() is structured according to
- * these cases.
+ * The walking code in trie_match_net() is structured according to these cases.
+ *
+ * Iteration over prefixes in a trie can be done using TRIE_WALK() macro, or
+ * directly using trie_walk_init() and trie_walk_next() functions. The second
+ * approach allows suspending the iteration and continuing in it later.
+ * Prefixes are enumerated in the usual lexicographic order and may be
+ * restricted to a subset of the trie (all subnets of a specified prefix).
+ *
+ * Note that the trie walk does not reliably enumerate `implicit' prefixes
+ * defined by &low and &high fields in prefix patterns, it is supposed to be
+ * used on tries constructed from `explicit' prefixes (&low == &plen == &high
+ * in call to trie_add_prefix()).
+ *
+ * The trie walk has three basic state variables stored in the struct
+ * &f_trie_walk_state -- the current node in &stack[stack_pos], &accept_length
+ * for iteration over inter-node prefixes (non-branching prefixes on compressed
+ * path between the current node and its parent node, stored in the bitmap
+ * &accept of the current node) and &local_pos for iteration over intra-node
+ * prefixes (stored in the bitmap &local).
+ *
+ * The trie also supports longest-prefix-match query by trie_match_longest_ip4()
+ * and it can be extended to iteration over all covering prefixes for a given
+ * prefix (from longest to shortest) using TRIE_WALK_TO_ROOT_IP4() macro. There
+ * are also IPv6 versions (for practical reasons, these functions and macros are
+ * separate for IPv4 and IPv6). There is the same limitation to enumeration of
+ * `implicit' prefixes like with the previous TRIE_WALK() macro.
*/
#include "nest/bird.h"
@@ -86,7 +126,10 @@
#define ipa_mkmask(x) ip6_mkmask(x)
#define ipa_masklen(x) ip6_masklen(&x)
#define ipa_pxlen(x,y) ip6_pxlen(x,y)
-#define ipa_getbit(x,n) ip6_getbit(x,n)
+#define ipa_getbit(a,p) ip6_getbit(a,p)
+#define ipa_getbits(a,p,n) ip6_getbits(a,p,n)
+#define ipa_setbits(a,p,n) ip6_setbits(a,p,n)
+#define trie_local_mask(a,b,c) trie_local_mask6(a,b,c)
#define ipt_from_ip4(x) _MI6(_I(x), 0, 0, 0)
#define ipt_to_ip4(x) _MI4(_I0(x))
@@ -109,10 +152,11 @@ f_new_trie(linpool *lp, uint data_size)
}
static inline struct f_trie_node4 *
-new_node4(struct f_trie *t, int plen, ip4_addr paddr, ip4_addr pmask, ip4_addr amask)
+new_node4(struct f_trie *t, uint plen, uint local, ip4_addr paddr, ip4_addr pmask, ip4_addr amask)
{
struct f_trie_node4 *n = lp_allocz(t->lp, sizeof(struct f_trie_node4) + t->data_size);
n->plen = plen;
+ n->local = local;
n->addr = paddr;
n->mask = pmask;
n->accept = amask;
@@ -120,10 +164,11 @@ new_node4(struct f_trie *t, int plen, ip4_addr paddr, ip4_addr pmask, ip4_addr a
}
static inline struct f_trie_node6 *
-new_node6(struct f_trie *t, int plen, ip6_addr paddr, ip6_addr pmask, ip6_addr amask)
+new_node6(struct f_trie *t, uint plen, uint local, ip6_addr paddr, ip6_addr pmask, ip6_addr amask)
{
struct f_trie_node6 *n = lp_allocz(t->lp, sizeof(struct f_trie_node6) + t->data_size);
n->plen = plen;
+ n->local = local;
n->addr = paddr;
n->mask = pmask;
n->accept = amask;
@@ -131,24 +176,24 @@ new_node6(struct f_trie *t, int plen, ip6_addr paddr, ip6_addr pmask, ip6_addr a
}
static inline struct f_trie_node *
-new_node(struct f_trie *t, int plen, ip_addr paddr, ip_addr pmask, ip_addr amask)
+new_node(struct f_trie *t, uint plen, uint local, ip_addr paddr, ip_addr pmask, ip_addr amask)
{
if (t->ipv4)
- return (struct f_trie_node *) new_node4(t, plen, ipt_to_ip4(paddr), ipt_to_ip4(pmask), ipt_to_ip4(amask));
+ return (struct f_trie_node *) new_node4(t, plen, local, ipt_to_ip4(paddr), ipt_to_ip4(pmask), ipt_to_ip4(amask));
else
- return (struct f_trie_node *) new_node6(t, plen, ipa_to_ip6(paddr), ipa_to_ip6(pmask), ipa_to_ip6(amask));
+ return (struct f_trie_node *) new_node6(t, plen, local, ipa_to_ip6(paddr), ipa_to_ip6(pmask), ipa_to_ip6(amask));
}
static inline void
attach_node4(struct f_trie_node4 *parent, struct f_trie_node4 *child)
{
- parent->c[ip4_getbit(child->addr, parent->plen) ? 1 : 0] = child;
+ parent->c[ip4_getbits(child->addr, parent->plen, TRIE_STEP)] = child;
}
static inline void
attach_node6(struct f_trie_node6 *parent, struct f_trie_node6 *child)
{
- parent->c[ip6_getbit(child->addr, parent->plen) ? 1 : 0] = child;
+ parent->c[ip6_getbits(child->addr, parent->plen, TRIE_STEP)] = child;
}
static inline void
@@ -160,63 +205,96 @@ attach_node(struct f_trie_node *parent, struct f_trie_node *child, int v4)
attach_node6(&parent->v6, &child->v6);
}
-#define GET_ADDR(N,F,X) ((X) ? ipt_from_ip4((N)->v4.F) : ipa_from_ip6((N)->v6.F))
-#define SET_ADDR(N,F,X,V) ({ if (X) (N)->v4.F =ipt_to_ip4(V); else (N)->v6.F =ipa_to_ip6(V); })
-#define GET_CHILD(N,F,X,I) ((X) ? (struct f_trie_node *) (N)->v4.c[I] : (struct f_trie_node *) (N)->v6.c[I])
-/**
- * trie_add_prefix
- * @t: trie to add to
- * @net: IP network prefix
- * @l: prefix lower bound
- * @h: prefix upper bound
+/*
+ * Internal prefixes of a node a represented by the local bitmask, each bit for
+ * one prefix. Bit 0 is unused, Bit 1 is for the main prefix of the node,
+ * remaining bits correspond to subprefixes by this pattern:
*
- * Adds prefix (prefix pattern) @n to trie @t. @l and @h are lower
- * and upper bounds on accepted prefix lengths, both inclusive.
- * 0 <= l, h <= 32 (128 for IPv6).
+ * 1
+ * 2 3
+ * 4 5 6 7
+ * 8 9 A B C D E F
*
- * Returns a pointer to the allocated node. The function can return a pointer to
- * an existing node if @px and @plen are the same. If px/plen == 0/0 (or ::/0),
- * a pointer to the root node is returned. Returns NULL when called with
- * mismatched IPv4/IPv6 net type.
+ * E.g. for 10.0.0.0/8 node, the 10.64.0.0/10 would be position 5.
*/
-void *
-trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
+/*
+ * Compute appropriate mask representing prefix px/plen in local bitmask of node
+ * with prefix length nlen. Assuming that nlen <= plen < (nlen + TRIE_STEP).
+ */
+static inline uint
+trie_local_mask4(ip4_addr px, uint plen, uint nlen)
{
- uint plen = net_pxlen(net);
- ip_addr px;
- int v4;
+ uint step = plen - nlen;
+ uint pos = (1u << step) + ip4_getbits(px, nlen, step);
+ return 1u << pos;
+}
- switch (net->type)
- {
- case NET_IP4: px = ipt_from_ip4(net4_prefix(net)); v4 = 1; break;
- case NET_IP6: px = ipa_from_ip6(net6_prefix(net)); v4 = 0; break;
- default: bug("invalid type");
- }
+static inline uint
+trie_local_mask6(ip6_addr px, uint plen, uint nlen)
+{
+ uint step = plen - nlen;
+ uint pos = (1u << step) + ip6_getbits(px, nlen, step);
+ return 1u << pos;
+}
- if (t->ipv4 != v4)
- {
- if (t->ipv4 < 0)
- t->ipv4 = v4;
- else
- return NULL;
- }
+/*
+ * Compute an appropriate local mask (for a node with prefix length nlen)
+ * representing prefixes of px that are accepted by amask and fall within the
+ * range associated with that node. Used for propagation of child accept mask
+ * to parent local mask.
+ */
+static inline uint
+trie_amask_to_local(ip_addr px, ip_addr amask, uint nlen)
+{
+ uint local = 0;
- if (l == 0)
- t->zero = 1;
- else
- l--;
+ for (uint plen = MAX(nlen, 1); plen < (nlen + TRIE_STEP); plen++)
+ if (ipa_getbit(amask, plen - 1))
+ local |= trie_local_mask(px, plen, nlen);
- if (h < plen)
- plen = h;
+ return local;
+}
+
+/*
+ * Compute a bitmask representing a level of subprefixes (of the same length),
+ * using specified position as a root. E.g., level 2 from root position 3 would
+ * be bit positions C-F, returned as bitmask 0xf000.
+ */
+static inline uint
+trie_level_mask(uint pos, uint level)
+{
+ return ((1u << (1u << level)) - 1) << (pos << level);
+}
- ip_addr amask = ipa_xor(ipa_mkmask(l), ipa_mkmask(h));
+
+#define GET_ADDR(N,F,X) ((X) ? ipt_from_ip4((N)->v4.F) : ipa_from_ip6((N)->v6.F))
+#define SET_ADDR(N,F,X,V) ({ if (X) (N)->v4.F =ipt_to_ip4(V); else (N)->v6.F =ipa_to_ip6(V); })
+
+#define GET_LOCAL(N,X) ((X) ? (N)->v4.local : (N)->v6.local)
+#define ADD_LOCAL(N,X,V) ({ uint v_ = (V); if (X) (N)->v4.local |= v_; else (N)->v6.local |= v_; })
+
+#define GET_CHILD(N,X,I) ((X) ? (struct f_trie_node *) (N)->v4.c[I] : (struct f_trie_node *) (N)->v6.c[I])
+
+
+static void *
+trie_add_node(struct f_trie *t, uint plen, ip_addr px, uint local, uint l, uint h)
+{
+ uint l_ = l ? (l - 1) : 0;
+ ip_addr amask = (l_ < h) ? ipa_xor(ipa_mkmask(l_), ipa_mkmask(h)) : IPA_NONE;
ip_addr pmask = ipa_mkmask(plen);
ip_addr paddr = ipa_and(px, pmask);
struct f_trie_node *o = NULL;
struct f_trie_node *n = &t->root;
+ int v4 = t->ipv4;
+ /* Add all bits for each active level (0x0002 0x000c 0x00f0 0xff00) */
+ for (uint i = 0; i < TRIE_STEP; i++)
+ if ((l <= (plen + i)) && ((plen + i) <= h))
+ local |= trie_level_mask(1, i);
+
+ DBG("Insert node %I/%u (%I %x)\n", paddr, plen, amask, local);
while (n)
{
ip_addr naddr = GET_ADDR(n, addr, v4);
@@ -225,23 +303,31 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
ip_addr cmask = ipa_and(nmask, pmask);
uint nlen = v4 ? n->v4.plen : n->v6.plen;
+ DBG("Found node %I/%u (%I %x)\n",
+ naddr, nlen, accept, v4 ? n->v4.local : n->v6.local);
+
if (ipa_compare(ipa_and(paddr, cmask), ipa_and(naddr, cmask)))
{
/* We are out of path - we have to add branching node 'b'
between node 'o' and node 'n', and attach new node 'a'
as the other child of 'b'. */
- int blen = ipa_pxlen(paddr, naddr);
+ int blen = ROUND_DOWN_POW2(ipa_pxlen(paddr, naddr), TRIE_STEP);
ip_addr bmask = ipa_mkmask(blen);
ip_addr baddr = ipa_and(px, bmask);
/* Merge accept masks from children to get accept mask for node 'b' */
ip_addr baccm = ipa_and(ipa_or(amask, accept), bmask);
+ uint bloc = trie_amask_to_local(naddr, accept, blen) |
+ trie_amask_to_local(paddr, amask, blen);
- struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
- struct f_trie_node *b = new_node(t, blen, baddr, bmask, baccm);
+ struct f_trie_node *a = new_node(t, plen, local, paddr, pmask, amask);
+ struct f_trie_node *b = new_node(t, blen, bloc, baddr, bmask, baccm);
attach_node(o, b, v4);
attach_node(b, n, v4);
attach_node(b, a, v4);
+ t->prefix_count++;
+
+ DBG("Case 1\n");
return a;
}
@@ -249,66 +335,195 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
{
/* We add new node 'a' between node 'o' and node 'n' */
amask = ipa_or(amask, ipa_and(accept, pmask));
- struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
+ local |= trie_amask_to_local(naddr, accept, plen);
+ struct f_trie_node *a = new_node(t, plen, local, paddr, pmask, amask);
attach_node(o, a, v4);
attach_node(a, n, v4);
+ t->prefix_count++;
+
+ DBG("Case 2\n");
return a;
}
if (plen == nlen)
{
- /* We already found added node in trie. Just update accept mask */
+ /* We already found added node in trie. Just update accept and local mask */
accept = ipa_or(accept, amask);
SET_ADDR(n, accept, v4, accept);
+
+ if ((GET_LOCAL(n, v4) & local) != local)
+ t->prefix_count++;
+
+ ADD_LOCAL(n, v4, local);
+
+ DBG("Case 3\n");
return n;
}
/* Update accept mask part M2 and go deeper */
accept = ipa_or(accept, ipa_and(amask, nmask));
SET_ADDR(n, accept, v4, accept);
+ ADD_LOCAL(n, v4, trie_amask_to_local(paddr, amask, nlen));
+
+ DBG("Step %u\n", ipa_getbits(paddr, nlen));
/* n->plen < plen and plen <= 32 (128) */
o = n;
- n = GET_CHILD(n, c, v4, ipa_getbit(paddr, nlen) ? 1 : 0);
+ n = GET_CHILD(n, v4, ipa_getbits(paddr, nlen, TRIE_STEP));
}
/* We add new tail node 'a' after node 'o' */
- struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
+ struct f_trie_node *a = new_node(t, plen, local, paddr, pmask, amask);
attach_node(o, a, v4);
+ t->prefix_count++;
+ DBG("Case 4\n");
return a;
}
+/**
+ * trie_add_prefix
+ * @t: trie to add to
+ * @net: IP network prefix
+ * @l: prefix lower bound
+ * @h: prefix upper bound
+ *
+ * Adds prefix (prefix pattern) @n to trie @t. @l and @h are lower
+ * and upper bounds on accepted prefix lengths, both inclusive.
+ * 0 <= l, h <= 32 (128 for IPv6).
+ *
+ * Returns a pointer to the allocated node. The function can return a pointer to
+ * an existing node if @px and @plen are the same. If px/plen == 0/0 (or ::/0),
+ * a pointer to the root node is returned. Returns NULL when called with
+ * mismatched IPv4/IPv6 net type.
+ */
+void *
+trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
+{
+ uint plen = net_pxlen(net);
+ ip_addr px;
+ int v4;
+
+ switch (net->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ px = ipt_from_ip4(net4_prefix(net));
+ v4 = 1;
+ break;
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ case NET_IP6_SADR:
+ px = ipa_from_ip6(net6_prefix(net));
+ v4 = 0;
+ break;
+
+ default:
+ bug("invalid type");
+ }
+
+ if (t->ipv4 != v4)
+ {
+ if (t->ipv4 < 0)
+ t->ipv4 = v4;
+ else
+ return NULL;
+ }
+
+ DBG("\nInsert net %N (%u-%u)\n", net, l, h);
+
+ if (l == 0)
+ t->zero = 1;
+
+ if (h < plen)
+ plen = h;
+
+ /* Primary node length, plen rounded down */
+ uint nlen = ROUND_DOWN_POW2(plen, TRIE_STEP);
+
+ if (plen == nlen)
+ return trie_add_node(t, nlen, px, 0, l, h);
+
+ /* Secondary node length, plen rouned up */
+ uint slen = nlen + TRIE_STEP;
+ void *node = NULL;
+
+ /*
+ * For unaligned prefix lengths it is more complicated. We need to encode
+ * matching prefixes of lengths from l to h. There are three cases of lengths:
+ *
+ * 1) 0..nlen are encoded by the accept mask of the primary node
+ * 2) nlen..(slen-1) are encoded by the local mask of the primary node
+ * 3) slen..max are encoded in secondary nodes
+ */
+
+ if (l < slen)
+ {
+ uint local = 0;
+
+ /* Compute local bits for accepted nlen..(slen-1) prefixes */
+ for (uint i = 0; i < TRIE_STEP; i++)
+ if ((l <= (nlen + i)) && ((nlen + i) <= h))
+ {
+ uint pos = (1u << i) + ipa_getbits(px, nlen, i);
+ uint len = ((nlen + i) <= plen) ? 1 : (1u << (nlen + i - plen));
+
+ /* We need to fill 'len' bits starting at 'pos' position */
+ local |= ((1u << len) - 1) << pos;
+ }
+
+ /* Add the primary node */
+ node = trie_add_node(t, nlen, px, local, l, nlen);
+ }
+
+ if (slen <= h)
+ {
+ uint l2 = MAX(l, slen);
+ uint max = (1u << (slen - plen));
+
+ /* Add secondary nodes */
+ for (uint i = 0; i < max; i++)
+ node = trie_add_node(t, slen, ipa_setbits(px, slen - 1, i), 0, l2, h);
+ }
+
+ return node;
+}
+
+
static int
trie_match_net4(const struct f_trie *t, ip4_addr px, uint plen)
{
- ip4_addr pmask = ip4_mkmask(plen);
- ip4_addr paddr = ip4_and(px, pmask);
-
if (plen == 0)
return t->zero;
int plentest = plen - 1;
+ uint nlen = ROUND_DOWN_POW2(plen, TRIE_STEP);
+ uint local = trie_local_mask4(px, plen, nlen);
const struct f_trie_node4 *n = &t->root.v4;
while (n)
{
- ip4_addr cmask = ip4_and(n->mask, pmask);
-
/* We are out of path */
- if (ip4_compare(ip4_and(paddr, cmask), ip4_and(n->addr, cmask)))
+ if (!ip4_prefix_equal(px, n->addr, MIN(plen, n->plen)))
return 0;
+ /* Check local mask */
+ if ((n->plen == nlen) && (n->local & local))
+ return 1;
+
/* Check accept mask */
if (ip4_getbit(n->accept, plentest))
return 1;
/* We finished trie walk and still no match */
- if (plen <= n->plen)
+ if (nlen <= n->plen)
return 0;
/* Choose children */
- n = n->c[(ip4_getbit(paddr, n->plen)) ? 1 : 0];
+ n = n->c[ip4_getbits(px, n->plen, TRIE_STEP)];
}
return 0;
@@ -317,33 +532,34 @@ trie_match_net4(const struct f_trie *t, ip4_addr px, uint plen)
static int
trie_match_net6(const struct f_trie *t, ip6_addr px, uint plen)
{
- ip6_addr pmask = ip6_mkmask(plen);
- ip6_addr paddr = ip6_and(px, pmask);
-
if (plen == 0)
return t->zero;
int plentest = plen - 1;
+ uint nlen = ROUND_DOWN_POW2(plen, TRIE_STEP);
+ uint local = trie_local_mask6(px, plen, nlen);
const struct f_trie_node6 *n = &t->root.v6;
while (n)
{
- ip6_addr cmask = ip6_and(n->mask, pmask);
-
/* We are out of path */
- if (ip6_compare(ip6_and(paddr, cmask), ip6_and(n->addr, cmask)))
+ if (!ip6_prefix_equal(px, n->addr, MIN(plen, n->plen)))
return 0;
+ /* Check local mask */
+ if ((n->plen == nlen) && (n->local & local))
+ return 1;
+
/* Check accept mask */
if (ip6_getbit(n->accept, plentest))
return 1;
/* We finished trie walk and still no match */
- if (plen <= n->plen)
+ if (nlen <= n->plen)
return 0;
/* Choose children */
- n = n->c[(ip6_getbit(paddr, n->plen)) ? 1 : 0];
+ n = n->c[ip6_getbits(px, n->plen, TRIE_STEP)];
}
return 0;
@@ -378,6 +594,412 @@ trie_match_net(const struct f_trie *t, const net_addr *n)
}
}
+
+/**
+ * trie_match_longest_ip4
+ * @t: trie
+ * @net: net address
+ * @dst: return value
+ * @found0: optional returned bitmask of found nodes
+ *
+ * Perform longest prefix match for the address @net and return the resulting
+ * prefix in the buffer @dst. The bitmask @found0 is used to report lengths of
+ * prefixes on the path from the root to the resulting prefix. E.g., if there is
+ * also a /20 shorter matching prefix, then 20-th bit is set in @found0. This
+ * can be used to enumerate all matching prefixes for the network @net using
+ * function trie_match_next_longest_ip4() or macro TRIE_WALK_TO_ROOT_IP4().
+ *
+ * This function assumes IPv4 trie, there is also an IPv6 variant. The @net
+ * argument is typed as net_addr_ip4, but would accept any IPv4-based net_addr,
+ * like net4_prefix(). Anyway, returned @dst is always net_addr_ip4.
+ *
+ * Result: 1 if a matching prefix was found, 0 if not.
+ */
+int
+trie_match_longest_ip4(const struct f_trie *t, const net_addr_ip4 *net, net_addr_ip4 *dst, ip4_addr *found0)
+{
+ ASSERT(t->ipv4);
+
+ const ip4_addr prefix = net->prefix;
+ const int pxlen = net->pxlen;
+
+ const struct f_trie_node4 *n = &t->root.v4;
+ int len = 0;
+
+ ip4_addr found = IP4_NONE;
+ int last = -1;
+
+ while (n)
+ {
+ /* We are out of path */
+ if (!ip4_prefix_equal(prefix, n->addr, MIN(pxlen, n->plen)))
+ goto done;
+
+ /* Check accept mask */
+ for (; len < n->plen; len++)
+ {
+ if (len > pxlen)
+ goto done;
+
+ if (ip4_getbit(n->accept, len - 1))
+ {
+ /* len is always < 32 due to len < n->plen */
+ ip4_setbit(&found, len);
+ last = len;
+ }
+ }
+
+ /* Special case for max length, there is only one valid local position */
+ if (len == IP4_MAX_PREFIX_LENGTH)
+ {
+ if (n->local & (1u << 1))
+ last = len;
+
+ goto done;
+ }
+
+ /* Check local mask */
+ for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip4_getbit(prefix, len), len++)
+ {
+ if (len > pxlen)
+ goto done;
+
+ if (n->local & (1u << pos))
+ {
+ /* len is always < 32 due to special case above */
+ ip4_setbit(&found, len);
+ last = len;
+ }
+ }
+
+ /* Choose child */
+ n = n->c[ip4_getbits(prefix, n->plen, TRIE_STEP)];
+ }
+
+done:
+ if (last < 0)
+ return 0;
+
+ *dst = NET_ADDR_IP4(ip4_and(prefix, ip4_mkmask(last)), last);
+
+ if (found0)
+ *found0 = found;
+
+ return 1;
+}
+
+
+/**
+ * trie_match_longest_ip6
+ * @t: trie
+ * @net: net address
+ * @dst: return value
+ * @found0: optional returned bitmask of found nodes
+ *
+ * Perform longest prefix match for the address @net and return the resulting
+ * prefix in the buffer @dst. The bitmask @found0 is used to report lengths of
+ * prefixes on the path from the root to the resulting prefix. E.g., if there is
+ * also a /20 shorter matching prefix, then 20-th bit is set in @found0. This
+ * can be used to enumerate all matching prefixes for the network @net using
+ * function trie_match_next_longest_ip6() or macro TRIE_WALK_TO_ROOT_IP6().
+ *
+ * This function assumes IPv6 trie, there is also an IPv4 variant. The @net
+ * argument is typed as net_addr_ip6, but would accept any IPv6-based net_addr,
+ * like net6_prefix(). Anyway, returned @dst is always net_addr_ip6.
+ *
+ * Result: 1 if a matching prefix was found, 0 if not.
+ */
+int
+trie_match_longest_ip6(const struct f_trie *t, const net_addr_ip6 *net, net_addr_ip6 *dst, ip6_addr *found0)
+{
+ ASSERT(!t->ipv4);
+
+ const ip6_addr prefix = net->prefix;
+ const int pxlen = net->pxlen;
+
+ const struct f_trie_node6 *n = &t->root.v6;
+ int len = 0;
+
+ ip6_addr found = IP6_NONE;
+ int last = -1;
+
+ while (n)
+ {
+ /* We are out of path */
+ if (!ip6_prefix_equal(prefix, n->addr, MIN(pxlen, n->plen)))
+ goto done;
+
+ /* Check accept mask */
+ for (; len < n->plen; len++)
+ {
+ if (len > pxlen)
+ goto done;
+
+ if (ip6_getbit(n->accept, len - 1))
+ {
+ /* len is always < 128 due to len < n->plen */
+ ip6_setbit(&found, len);
+ last = len;
+ }
+ }
+
+ /* Special case for max length, there is only one valid local position */
+ if (len == IP6_MAX_PREFIX_LENGTH)
+ {
+ if (n->local & (1u << 1))
+ last = len;
+
+ goto done;
+ }
+
+ /* Check local mask */
+ for (int pos = 1; pos < (1 << TRIE_STEP); pos = 2 * pos + ip6_getbit(prefix, len), len++)
+ {
+ if (len > pxlen)
+ goto done;
+
+ if (n->local & (1u << pos))
+ {
+ /* len is always < 128 due to special case above */
+ ip6_setbit(&found, len);
+ last = len;
+ }
+ }
+
+ /* Choose child */
+ n = n->c[ip6_getbits(prefix, n->plen, TRIE_STEP)];
+ }
+
+done:
+ if (last < 0)
+ return 0;
+
+ *dst = NET_ADDR_IP6(ip6_and(prefix, ip6_mkmask(last)), last);
+
+ if (found0)
+ *found0 = found;
+
+ return 1;
+}
+
+#define SAME_PREFIX(A,B,X,L) ((X) ? ip4_prefix_equal((A)->v4.addr, net4_prefix(B), (L)) : ip6_prefix_equal((A)->v6.addr, net6_prefix(B), (L)))
+#define GET_NET_BITS(N,X,A,B) ((X) ? ip4_getbits(net4_prefix(N), (A), (B)) : ip6_getbits(net6_prefix(N), (A), (B)))
+
+/**
+ * trie_walk_init
+ * @s: walk state
+ * @t: trie
+ * @net: optional subnet for walk
+ *
+ * Initialize walk state for subsequent walk through nodes of the trie @t by
+ * trie_walk_next(). The argument @net allows to restrict walk to given subnet,
+ * otherwise full walk over all nodes is used. This is done by finding node at
+ * or below @net and starting position in it.
+ */
+void
+trie_walk_init(struct f_trie_walk_state *s, const struct f_trie *t, const net_addr *net)
+{
+ *s = (struct f_trie_walk_state) {
+ .ipv4 = t->ipv4,
+ .accept_length = 0,
+ .start_pos = 1,
+ .local_pos = 1,
+ .stack_pos = 0,
+ .stack[0] = &t->root
+ };
+
+ if (!net)
+ return;
+
+ /* We want to find node of level at least plen */
+ int plen = ROUND_DOWN_POW2(net->pxlen, TRIE_STEP);
+ const struct f_trie_node *n = &t->root;
+ const int v4 = t->ipv4;
+
+ while (n)
+ {
+ int nlen = v4 ? n->v4.plen : n->v6.plen;
+
+ /* We are out of path */
+ if (!SAME_PREFIX(n, net, v4, MIN(net->pxlen, nlen)))
+ break;
+
+ /* We found final node */
+ if (nlen >= plen)
+ {
+ if (nlen == plen)
+ {
+ /* Find proper local_pos, while accept_length is not used */
+ int step = net->pxlen - plen;
+ s->start_pos = s->local_pos = (1u << step) + GET_NET_BITS(net, v4, plen, step);
+ s->accept_length = plen;
+ }
+ else
+ {
+ /* Start from pos 1 in local node, but first try accept mask */
+ s->accept_length = net->pxlen;
+ }
+
+ s->stack[0] = n;
+ return;
+ }
+
+ /* Choose child */
+ n = GET_CHILD(n, v4, GET_NET_BITS(net, v4, nlen, TRIE_STEP));
+ }
+
+ s->stack[0] = NULL;
+ return;
+}
+
+#define GET_ACCEPT_BIT(N,X,B) ((X) ? ip4_getbit((N)->v4.accept, (B)) : ip6_getbit((N)->v6.accept, (B)))
+#define GET_LOCAL_BIT(N,X,B) (((X) ? (N)->v4.local : (N)->v6.local) & (1u << (B)))
+
+/**
+ * trie_walk_next
+ * @s: walk state
+ * @net: return value
+ *
+ * Find the next prefix in the trie walk and return it in the buffer @net.
+ * Prefixes are walked in the usual lexicographic order and may be restricted
+ * to a subset of the trie during walk setup by trie_walk_init(). Note that the
+ * trie walk does not iterate reliably over 'implicit' prefixes defined by &low
+ * and &high fields in prefix patterns, it is supposed to be used on tries
+ * constructed from 'explicit' prefixes (&low == &plen == &high in call to
+ * trie_add_prefix()).
+ *
+ * Result: 1 if the next prefix was found, 0 for the end of walk.
+ */
+int
+trie_walk_next(struct f_trie_walk_state *s, net_addr *net)
+{
+ const struct f_trie_node *n = s->stack[s->stack_pos];
+ int len = s->accept_length;
+ int pos = s->local_pos;
+ int v4 = s->ipv4;
+
+ /*
+ * The walk has three basic state variables -- n, len and pos. In each node n,
+ * we first walk superprefixes (by len in &accept bitmask), and then we walk
+ * internal positions (by pos in &local bitmask). These positions are:
+ *
+ * 1
+ * 2 3
+ * 4 5 6 7
+ * 8 9 A B C D E F
+ *
+ * We walk them depth-first, including virtual positions 10-1F that are
+ * equivalent of position 1 in child nodes 0-F.
+ */
+
+ if (!n)
+ {
+ memset(net, 0, v4 ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6));
+ return 0;
+ }
+
+next_node:;
+ /* Current node prefix length */
+ int nlen = v4 ? n->v4.plen : n->v6.plen;
+
+ /* First, check for accept prefix */
+ for (; len < nlen; len++)
+ if (GET_ACCEPT_BIT(n, v4, len - 1))
+ {
+ if (v4)
+ net_fill_ip4(net, ip4_and(n->v4.addr, ip4_mkmask(len)), len);
+ else
+ net_fill_ip6(net, ip6_and(n->v6.addr, ip6_mkmask(len)), len);
+
+ s->local_pos = pos;
+ s->accept_length = len + 1;
+ return 1;
+ }
+
+next_pos:
+ /* Bottom of this node */
+ if (pos >= (1 << TRIE_STEP))
+ {
+ const struct f_trie_node *child = GET_CHILD(n, v4, pos - (1 << TRIE_STEP));
+ int dir = 0;
+
+ /* No child node */
+ if (!child)
+ {
+ /* Step up until return from left child (pos is even) */
+ do
+ {
+ /* Step up from start node */
+ if ((s->stack_pos == 0) && (pos == s->start_pos))
+ {
+ s->stack[0] = NULL;
+ memset(net, 0, v4 ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6));
+ return 0;
+ }
+
+ /* Top of this node */
+ if (pos == 1)
+ {
+ ASSERT(s->stack_pos);
+ const struct f_trie_node *old = n;
+
+ /* Move to parent node */
+ s->stack_pos--;
+ n = s->stack[s->stack_pos];
+ nlen = v4 ? n->v4.plen : n->v6.plen;
+
+ pos = v4 ?
+ ip4_getbits(old->v4.addr, nlen, TRIE_STEP) :
+ ip6_getbits(old->v6.addr, nlen, TRIE_STEP);
+ pos += (1 << TRIE_STEP);
+ len = nlen;
+
+ ASSERT(GET_CHILD(n, v4, pos - (1 << TRIE_STEP)) == old);
+ }
+
+ /* Step up */
+ dir = pos % 2;
+ pos = pos / 2;
+ }
+ while (dir);
+
+ /* Continue with step down to the right child */
+ pos = 2 * pos + 1;
+ goto next_pos;
+ }
+
+ /* Move to child node */
+ pos = 1;
+ len = nlen + TRIE_STEP;
+
+ s->stack_pos++;
+ n = s->stack[s->stack_pos] = child;
+ goto next_node;
+ }
+
+ /* Check for local prefix */
+ if (GET_LOCAL_BIT(n, v4, pos))
+ {
+ /* Convert pos to address of local network */
+ int x = (pos >= 2) + (pos >= 4) + (pos >= 8);
+ int y = pos & ((1u << x) - 1);
+
+ if (v4)
+ net_fill_ip4(net, !x ? n->v4.addr : ip4_setbits(n->v4.addr, nlen + x - 1, y), nlen + x);
+ else
+ net_fill_ip6(net, !x ? n->v6.addr : ip6_setbits(n->v6.addr, nlen + x - 1, y), nlen + x);
+
+ s->local_pos = 2 * pos;
+ s->accept_length = len;
+ return 1;
+ }
+
+ /* Step down */
+ pos = 2 * pos;
+ goto next_pos;
+}
+
+
static int
trie_node_same4(const struct f_trie_node4 *t1, const struct f_trie_node4 *t2)
{
@@ -392,7 +1014,11 @@ trie_node_same4(const struct f_trie_node4 *t1, const struct f_trie_node4 *t2)
(! ip4_equal(t1->accept, t2->accept)))
return 0;
- return trie_node_same4(t1->c[0], t2->c[0]) && trie_node_same4(t1->c[1], t2->c[1]);
+ for (uint i = 0; i < (1 << TRIE_STEP); i++)
+ if (! trie_node_same4(t1->c[i], t2->c[i]))
+ return 0;
+
+ return 1;
}
static int
@@ -409,7 +1035,11 @@ trie_node_same6(const struct f_trie_node6 *t1, const struct f_trie_node6 *t2)
(! ip6_equal(t1->accept, t2->accept)))
return 0;
- return trie_node_same6(t1->c[0], t2->c[0]) && trie_node_same6(t1->c[1], t2->c[1]);
+ for (uint i = 0; i < (1 << TRIE_STEP); i++)
+ if (! trie_node_same6(t1->c[i], t2->c[i]))
+ return 0;
+
+ return 1;
}
/**
@@ -431,30 +1061,70 @@ trie_same(const struct f_trie *t1, const struct f_trie *t2)
return trie_node_same6(&t1->root.v6, &t2->root.v6);
}
+
+static const u8 log2[16] = {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3};
+
static void
-trie_node_format4(const struct f_trie_node4 *t, buffer *buf)
+trie_node_format(const struct f_trie_node *n, buffer *buf, int v4)
{
- if (t == NULL)
+ if (n == NULL)
return;
- if (ip4_nonzero(t->accept))
- buffer_print(buf, "%I4/%d{%I4}, ", t->addr, t->plen, t->accept);
+ if (v4)
+ {
+ if (ip4_nonzero(n->v4.accept))
+ buffer_print(buf, "%I4/%d{%I4}, ", n->v4.addr, n->v4.plen, n->v4.accept);
+ }
+ else
+ {
+ if (ip6_nonzero(n->v6.accept))
+ buffer_print(buf, "%I6/%d{%I6}, ", n->v6.addr, n->v6.plen, n->v6.accept);
+ }
- trie_node_format4(t->c[0], buf);
- trie_node_format4(t->c[1], buf);
-}
+ int nlen = v4 ? n->v4.plen : n->v6.plen;
+ uint local = v4 ? n->v4.local : n->v6.local;
-static void
-trie_node_format6(const struct f_trie_node6 *t, buffer *buf)
-{
- if (t == NULL)
- return;
+ for (int i = (nlen ? 0 : 1); i < TRIE_STEP; i++)
+ if (GET_ACCEPT_BIT(n, v4, nlen + i - 1))
+ local &= ~trie_level_mask(1, i);
- if (ip6_nonzero(t->accept))
- buffer_print(buf, "%I6/%d{%I6}, ", t->addr, t->plen, t->accept);
+ for (int pos = 2; local && (pos < (1 << TRIE_STEP)); pos++)
+ if (local & (1u << pos))
+ {
+ int lvl = log2[pos];
+ int plen = nlen + lvl;
+
+ int i;
+ for (i = 0; lvl + i < TRIE_STEP; i++)
+ {
+ uint lmask = trie_level_mask(pos, i);
+
+ if ((local & lmask) != lmask)
+ break;
+
+ local &= ~lmask;
+ }
+
+ uint addr_bits = pos & ((1u << lvl) - 1);
+ uint accept_bits = (1u << i) - 1;
+ int h = plen + i - 1;
+
+ if (v4)
+ {
+ ip4_addr addr = ip4_setbits(n->v4.addr, plen - 1, addr_bits);
+ ip4_addr mask = ip4_setbits(IP4_NONE, h - 1, accept_bits);
+ buffer_print(buf, "%I4/%d{%I4}, ", addr, plen, mask);
+ }
+ else
+ {
+ ip6_addr addr = ip6_setbits(n->v6.addr, plen - 1, addr_bits);
+ ip6_addr mask = ip6_setbits(IP6_NONE, h - 1, accept_bits);
+ buffer_print(buf, "%I6/%d{%I6}, ", addr, plen, mask);
+ }
+ }
- trie_node_format6(t->c[0], buf);
- trie_node_format6(t->c[1], buf);
+ for (int i = 0; i < (1 << TRIE_STEP); i++)
+ trie_node_format(GET_CHILD(n, v4, i), buf, v4);
}
/**
@@ -472,10 +1142,7 @@ trie_format(const struct f_trie *t, buffer *buf)
if (t->zero)
buffer_print(buf, "%I/%d, ", t->ipv4 ? IPA_NONE4 : IPA_NONE6, 0);
- if (t->ipv4)
- trie_node_format4(&t->root.v4, buf);
- else
- trie_node_format6(&t->root.v6, buf);
+ trie_node_format(&t->root, buf, t->ipv4);
if (buf->pos == buf->end)
return;
diff --git a/filter/trie_test.c b/filter/trie_test.c
index b2b36716..cae86995 100644
--- a/filter/trie_test.c
+++ b/filter/trie_test.c
@@ -14,9 +14,12 @@
#include "conf/conf.h"
#define TESTS_NUM 10
-#define PREFIXES_NUM 10
+#define PREFIXES_NUM 32
#define PREFIX_TESTS_NUM 10000
+#define PREFIX_BENCH_NUM 100000000
+#define TRIE_BUFFER_SIZE 1024
+#define TEST_BUFFER_SIZE (1024*1024)
#define BIG_BUFFER_SIZE 10000
/* Wrapping structure for storing f_prefixes structures in list */
@@ -31,146 +34,860 @@ xrandom(u32 max)
return (bt_random() % max);
}
+static inline uint
+get_exp_random(void)
+{
+ uint r, n = 0;
+
+ for (r = bt_random(); r & 1; r = r >> 1)
+ n++;
+
+ return n;
+}
+
static int
-is_prefix_included(list *prefixes, struct f_prefix *needle)
+compare_prefixes(const void *a, const void *b)
{
- struct f_prefix_node *n;
- WALK_LIST(n, *prefixes)
- {
- ip6_addr cmask = ip6_mkmask(MIN(n->prefix.net.pxlen, needle->net.pxlen));
+ return net_compare(&((const struct f_prefix *) a)->net,
+ &((const struct f_prefix *) b)->net);
+}
+
+static inline int
+matching_ip4_nets(const net_addr_ip4 *a, const net_addr_ip4 *b)
+{
+ ip4_addr cmask = ip4_mkmask(MIN(a->pxlen, b->pxlen));
+ return ip4_compare(ip4_and(a->prefix, cmask), ip4_and(b->prefix, cmask)) == 0;
+}
+
+static inline int
+matching_ip6_nets(const net_addr_ip6 *a, const net_addr_ip6 *b)
+{
+ ip6_addr cmask = ip6_mkmask(MIN(a->pxlen, b->pxlen));
+ return ip6_compare(ip6_and(a->prefix, cmask), ip6_and(b->prefix, cmask)) == 0;
+}
- ip6_addr ip = net6_prefix(&n->prefix.net);
- ip6_addr needle_ip = net6_prefix(&needle->net);
+static inline int
+matching_nets(const net_addr *a, const net_addr *b)
+{
+ if (a->type != b->type)
+ return 0;
+
+ return (a->type == NET_IP4) ?
+ matching_ip4_nets((const net_addr_ip4 *) a, (const net_addr_ip4 *) b) :
+ matching_ip6_nets((const net_addr_ip6 *) a, (const net_addr_ip6 *) b);
+}
- if ((ipa_compare(ipa_and(ip, cmask), ipa_and(needle_ip, cmask)) == 0) &&
- (n->prefix.lo <= needle->net.pxlen) && (needle->net.pxlen <= n->prefix.hi))
+static int
+is_prefix_included(list *prefixes, const net_addr *needle)
+{
+ struct f_prefix_node *n;
+ WALK_LIST(n, *prefixes)
+ if (matching_nets(&n->prefix.net, needle) &&
+ (n->prefix.lo <= needle->pxlen) && (needle->pxlen <= n->prefix.hi))
{
- bt_debug("FOUND\t" PRIip6 "/%d %d-%d\n", ARGip6(net6_prefix(&n->prefix.net)), n->prefix.net.pxlen, n->prefix.lo, n->prefix.hi);
+ char buf[64];
+ bt_format_net(buf, 64, &n->prefix.net);
+ bt_debug("FOUND %s %d-%d\n", buf, n->prefix.lo, n->prefix.hi);
+
return 1; /* OK */
}
- }
+
return 0; /* FAIL */
}
-static struct f_prefix
-get_random_ip6_prefix(void)
+static void
+get_random_net(net_addr *net, int v6)
{
- struct f_prefix p;
- u8 pxlen = xrandom(120)+8;
- ip6_addr ip6 = ip6_build(bt_random(),bt_random(),bt_random(),bt_random());
- net_addr_ip6 net6 = NET_ADDR_IP6(ip6, pxlen);
+ if (!v6)
+ {
+ uint pxlen = xrandom(24)+8;
+ ip4_addr ip4 = ip4_from_u32((u32) bt_random());
+ net_fill_ip4(net, ip4_and(ip4, ip4_mkmask(pxlen)), pxlen);
+ }
+ else
+ {
+ uint pxlen = xrandom(120)+8;
+ ip6_addr ip6 = ip6_build(bt_random(), bt_random(), bt_random(), bt_random());
+ net_fill_ip6(net, ip6_and(ip6, ip6_mkmask(pxlen)), pxlen);
+ }
+}
- p.net = *((net_addr*) &net6);
+static void
+get_random_prefix(struct f_prefix *px, int v6, int tight)
+{
+ get_random_net(&px->net, v6);
+
+ if (tight)
+ {
+ px->lo = px->hi = px->net.pxlen;
+ }
+ else if (bt_random() % 2)
+ {
+ px->lo = 0;
+ px->hi = px->net.pxlen;
+ }
+ else
+ {
+ px->lo = px->net.pxlen;
+ px->hi = net_max_prefix_length[px->net.type];
+ }
+}
+
+static void
+get_random_ip4_subnet(net_addr_ip4 *net, const net_addr_ip4 *src, int pxlen)
+{
+ *net = NET_ADDR_IP4(ip4_and(src->prefix, ip4_mkmask(pxlen)), pxlen);
+
+ if (pxlen > src->pxlen)
+ {
+ ip4_addr rnd = ip4_from_u32((u32) bt_random());
+ ip4_addr mask = ip4_xor(ip4_mkmask(src->pxlen), ip4_mkmask(pxlen));
+ net->prefix = ip4_or(net->prefix, ip4_and(rnd, mask));
+ }
+}
+
+static void
+get_random_ip6_subnet(net_addr_ip6 *net, const net_addr_ip6 *src, int pxlen)
+{
+ *net = NET_ADDR_IP6(ip6_and(src->prefix, ip6_mkmask(pxlen)), pxlen);
+
+ if (pxlen > src->pxlen)
+ {
+ ip6_addr rnd = ip6_build(bt_random(), bt_random(), bt_random(), bt_random());
+ ip6_addr mask = ip6_xor(ip6_mkmask(src->pxlen), ip6_mkmask(pxlen));
+ net->prefix = ip6_or(net->prefix, ip6_and(rnd, mask));
+ }
+}
+
+static void
+get_random_subnet(net_addr *net, const net_addr *src, int pxlen)
+{
+ if (src->type == NET_IP4)
+ get_random_ip4_subnet((net_addr_ip4 *) net, (const net_addr_ip4 *) src, pxlen);
+ else
+ get_random_ip6_subnet((net_addr_ip6 *) net, (const net_addr_ip6 *) src, pxlen);
+}
+
+static void
+get_inner_net(net_addr *net, const struct f_prefix *src)
+{
+ int pxlen, step;
if (bt_random() % 2)
{
- p.lo = 0;
- p.hi = p.net.pxlen;
+ step = get_exp_random();
+ step = MIN(step, src->hi - src->lo);
+ pxlen = (bt_random() % 2) ? (src->lo + step) : (src->hi - step);
}
else
+ pxlen = src->lo + bt_random() % (src->hi - src->lo + 1);
+
+ get_random_subnet(net, &src->net, pxlen);
+}
+
+static void
+swap_random_bits_ip4(net_addr_ip4 *net, int num)
+{
+ for (int i = 0; i < num; i++)
{
- p.lo = p.net.pxlen;
- p.hi = net_max_prefix_length[p.net.type];
+ ip4_addr swap = IP4_NONE;
+ ip4_setbit(&swap, bt_random() % net->pxlen);
+ net->prefix = ip4_xor(net->prefix, swap);
}
+}
- return p;
+static void
+swap_random_bits_ip6(net_addr_ip6 *net, int num)
+{
+ for (int i = 0; i < num; i++)
+ {
+ ip6_addr swap = IP6_NONE;
+ ip6_setbit(&swap, bt_random() % net->pxlen);
+ net->prefix = ip6_xor(net->prefix, swap);
+ }
}
static void
-generate_random_ipv6_prefixes(list *prefixes)
+swap_random_bits(net_addr *net, int num)
{
- int i;
- for (i = 0; i < PREFIXES_NUM; i++)
+ if (net->type == NET_IP4)
+ swap_random_bits_ip4((net_addr_ip4 *) net, num);
+ else
+ swap_random_bits_ip6((net_addr_ip6 *) net, num);
+}
+
+static void
+get_outer_net(net_addr *net, const struct f_prefix *src)
+{
+ int pxlen, step;
+ int inside = 0;
+ int max = net_max_prefix_length[src->net.type];
+
+ if ((src->lo > 0) && (bt_random() % 3))
+ {
+ step = 1 + get_exp_random();
+ step = MIN(step, src->lo);
+ pxlen = src->lo - step;
+ }
+ else if ((src->hi < max) && (bt_random() % 2))
{
- struct f_prefix f = get_random_ip6_prefix();
+ step = 1 + get_exp_random();
+ step = MIN(step, max - src->hi);
+ pxlen = src->hi + step;
+ }
+ else
+ {
+ pxlen = src->lo + bt_random() % (src->hi - src->lo + 1);
+ inside = 1;
+ }
- struct f_prefix_node *px = calloc(1, sizeof(struct f_prefix_node));
- px->prefix = f;
+ get_random_subnet(net, &src->net, pxlen);
- bt_debug("ADD\t" PRIip6 "/%d %d-%d\n", ARGip6(net6_prefix(&px->prefix.net)), px->prefix.net.pxlen, px->prefix.lo, px->prefix.hi);
+ /* Perhaps swap some bits in prefix */
+ if ((net->pxlen > 0) && (inside || (bt_random() % 4)))
+ swap_random_bits(net, 1 + get_exp_random());
+}
+
+static list *
+make_random_prefix_list(linpool *lp, int num, int v6, int tight)
+{
+ list *prefixes = lp_allocz(lp, sizeof(struct f_prefix_node));
+ init_list(prefixes);
+
+ for (int i = 0; i < num; i++)
+ {
+ struct f_prefix_node *px = lp_allocz(lp, sizeof(struct f_prefix_node));
+ get_random_prefix(&px->prefix, v6, tight);
add_tail(prefixes, &px->n);
+
+ char buf[64];
+ bt_format_net(buf, 64, &px->prefix.net);
+ bt_debug("ADD %s{%d,%d}\n", buf, px->prefix.lo, px->prefix.hi);
+ }
+
+ return prefixes;
+}
+
+static struct f_trie *
+make_trie_from_prefix_list(linpool *lp, list *prefixes)
+{
+ struct f_trie *trie = f_new_trie(lp, 0);
+
+ struct f_prefix_node *n;
+ WALK_LIST(n, *prefixes)
+ trie_add_prefix(trie, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+
+ return trie;
+}
+
+/*
+ * Read sequence of prefixes from file handle and return prefix list.
+ * Each prefix is on one line, sequence terminated by empty line or eof.
+ * Arg @plus means prefix should include all longer ones.
+ */
+static list *
+read_prefix_list(linpool *lp, FILE *f, int v6, int plus)
+{
+ ASSERT(!v6);
+
+ uint a0, a1, a2, a3, pl;
+ char s[32];
+ int n;
+
+ list *pxlist = lp_allocz(lp, sizeof(struct f_prefix_node));
+ init_list(pxlist);
+
+ errno = 0;
+ while (fgets(s, 32, f))
+ {
+ if (s[0] == '\n')
+ return pxlist;
+
+ n = sscanf(s, "%u.%u.%u.%u/%u", &a0, &a1, &a2, &a3, &pl);
+
+ if (n != 5)
+ bt_abort_msg("Invalid content of trie_data");
+
+ struct f_prefix_node *px = lp_allocz(lp, sizeof(struct f_prefix_node));
+ net_fill_ip4(&px->prefix.net, ip4_build(a0, a1, a2, a3), pl);
+ px->prefix.lo = pl;
+ px->prefix.hi = plus ? IP4_MAX_PREFIX_LENGTH : pl;
+ add_tail(pxlist, &px->n);
+
+ char buf[64];
+ bt_format_net(buf, 64, &px->prefix.net);
+ bt_debug("ADD %s{%d,%d}\n", buf, px->prefix.lo, px->prefix.hi);
}
+
+ bt_syscall(errno, "fgets()");
+ return EMPTY_LIST(*pxlist) ? NULL : pxlist;
+}
+
+/*
+ * Open file, read multiple sequences of prefixes from it. Fill @data with
+ * prefix lists and @trie with generated tries. Return number of sequences /
+ * tries. Use separate linpool @lp0 for prefix lists and @lp1 for tries.
+ * Arg @plus means prefix should include all longer ones.
+ */
+static int
+read_prefix_file(const char *filename, int plus,
+ linpool *lp0, linpool *lp1,
+ list *data[], struct f_trie *trie[])
+{
+ FILE *f = fopen(filename, "r");
+ bt_syscall(!f, "fopen(%s)", filename);
+
+ int n = 0;
+ list *pxlist;
+ while (pxlist = read_prefix_list(lp0, f, 0, plus))
+ {
+ data[n] = pxlist;
+ trie[n] = make_trie_from_prefix_list(lp1, pxlist);
+ bt_debug("NEXT\n");
+ n++;
+ }
+
+ fclose(f);
+ bt_debug("DONE reading %d tries\n", n);
+
+ return n;
+}
+
+/*
+ * Select random subset of @dn prefixes from prefix list @src of length @sn,
+ * and store them to buffer @dst (of size @dn). Prefixes may be chosen multiple
+ * times. Randomize order of prefixes in @dst buffer.
+ */
+static void
+select_random_prefix_subset(list *src[], net_addr dst[], int sn, int dn)
+{
+ int pn = 0;
+
+ if (!dn)
+ return;
+
+ /* Compute total prefix number */
+ for (int i = 0; i < sn; i++)
+ pn += list_length(src[i]);
+
+ /* Change of selecting a prefix */
+ int rnd = (pn / dn) + 10;
+ int n = 0;
+
+ /* Iterate indefinitely over src array */
+ for (int i = 0; 1; i++, i = (i < sn) ? i : 0)
+ {
+ struct f_prefix_node *px;
+ WALK_LIST(px, *src[i])
+ {
+ if (xrandom(rnd) != 0)
+ continue;
+
+ net_copy(&dst[n], &px->prefix.net);
+ n++;
+
+ /* We have enough */
+ if (n == dn)
+ goto done;
+ }
+ }
+
+done:
+ /* Shuffle networks */
+ for (int i = 0; i < dn; i++)
+ {
+ int j = xrandom(dn);
+
+ if (i == j)
+ continue;
+
+ net_addr tmp;
+ net_copy(&tmp, &dst[i]);
+ net_copy(&dst[i], &dst[j]);
+ net_copy(&dst[j], &tmp);
+ }
+}
+
+/* Fill @dst buffer with @dn randomly generated /32 prefixes */
+static void
+make_random_addresses(net_addr dst[], int dn)
+{
+ for (int i = 0; i < dn; i++)
+ net_fill_ip4(&dst[i], ip4_from_u32((u32) bt_random()), IP4_MAX_PREFIX_LENGTH);
+}
+
+static void
+test_match_net(list *prefixes, struct f_trie *trie, const net_addr *net)
+{
+ char buf[64];
+ bt_format_net(buf, 64, net);
+ bt_debug("TEST %s\n", buf);
+
+ int should_be = is_prefix_included(prefixes, net);
+ int is_there = trie_match_net(trie, net);
+
+ bt_assert_msg(should_be == is_there, "Prefix %s %s match", buf,
+ (should_be ? "should" : "should not"));
}
static int
-t_match_net(void)
+t_match_random_net(void)
{
bt_bird_init();
bt_config_parse(BT_CONFIG_SIMPLE);
- uint round;
- for (round = 0; round < TESTS_NUM; round++)
+ int v6 = 0;
+ linpool *lp = lp_new_default(&root_pool);
+ for (int round = 0; round < TESTS_NUM; round++)
{
- list prefixes; /* of structs f_extended_prefix */
- init_list(&prefixes);
- struct f_trie *trie = f_new_trie(config->mem, 0);
+ list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0);
+ struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
- generate_random_ipv6_prefixes(&prefixes);
- struct f_prefix_node *n;
- WALK_LIST(n, prefixes)
+ for (int i = 0; i < PREFIX_TESTS_NUM; i++)
{
- trie_add_prefix(trie, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+ net_addr net;
+ get_random_net(&net, v6);
+ test_match_net(prefixes, trie, &net);
}
- int i;
- for (i = 0; i < PREFIX_TESTS_NUM; i++)
+ v6 = !v6;
+ lp_flush(lp);
+ }
+
+ bt_bird_cleanup();
+ return 1;
+}
+
+static int
+t_match_inner_net(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ int v6 = 0;
+ linpool *lp = lp_new_default(&root_pool);
+ for (int round = 0; round < TESTS_NUM; round++)
+ {
+ list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0);
+ struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+
+ struct f_prefix_node *n = HEAD(*prefixes);
+ for (int i = 0; i < PREFIX_TESTS_NUM; i++)
{
- struct f_prefix f = get_random_ip6_prefix();
- bt_debug("TEST\t" PRIip6 "/%d\n", ARGip6(net6_prefix(&f.net)), f.net.pxlen);
+ net_addr net;
+ get_inner_net(&net, &n->prefix);
+ test_match_net(prefixes, trie, &net);
- int should_be = is_prefix_included(&prefixes, &f);
- int is_there = trie_match_net(trie, &f.net);
- bt_assert_msg(should_be == is_there, "Prefix " PRIip6 "/%d %s", ARGip6(net6_prefix(&f.net)), f.net.pxlen, (should_be ? "should be found in trie" : "should not be found in trie"));
+ n = NODE_VALID(NODE_NEXT(n)) ? NODE_NEXT(n) : HEAD(*prefixes);
}
- struct f_prefix_node *nxt;
- WALK_LIST_DELSAFE(n, nxt, prefixes)
+ v6 = !v6;
+ lp_flush(lp);
+ }
+
+ bt_bird_cleanup();
+ return 1;
+}
+
+static int
+t_match_outer_net(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ int v6 = 0;
+ linpool *lp = lp_new_default(&root_pool);
+ for (int round = 0; round < TESTS_NUM; round++)
+ {
+ list *prefixes = make_random_prefix_list(lp, PREFIXES_NUM, v6, 0);
+ struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+
+ struct f_prefix_node *n = HEAD(*prefixes);
+ for (int i = 0; i < PREFIX_TESTS_NUM; i++)
{
- free(n);
+ net_addr net;
+ get_outer_net(&net, &n->prefix);
+ test_match_net(prefixes, trie, &net);
+
+ n = NODE_VALID(NODE_NEXT(n)) ? NODE_NEXT(n) : HEAD(*prefixes);
}
+
+ v6 = !v6;
+ lp_flush(lp);
}
+ v6 = !v6;
bt_bird_cleanup();
return 1;
}
+/*
+ * Read prefixes from @filename, build set of tries, prepare test data and do
+ * PREFIX_BENCH_NUM trie lookups. With @plus = 0, use random subset of known
+ * prefixes as test data, with @plus = 1, use randomly generated /32 prefixes
+ * as test data.
+ */
+static int
+benchmark_trie_dataset(const char *filename, int plus)
+{
+ int n = 0;
+ linpool *lp0 = lp_new_default(&root_pool);
+ linpool *lp1 = lp_new_default(&root_pool);
+ list *data[TRIE_BUFFER_SIZE];
+ struct f_trie *trie[TRIE_BUFFER_SIZE];
+ net_addr *nets;
+
+ bt_reset_suite_case_timer();
+ bt_log_suite_case_result(1, "Reading %s", filename, n);
+ n = read_prefix_file(filename, plus, lp0, lp1, data, trie);
+ bt_log_suite_case_result(1, "Read prefix data, %d lists, ", n);
+
+ size_t trie_size = rmemsize(lp1).effective * 1000 / (1024*1024);
+ bt_log_suite_case_result(1, "Trie size %u.%03u MB",
+ (uint) (trie_size / 1000), (uint) (trie_size % 1000));
+
+ int t = PREFIX_BENCH_NUM / n;
+ int tb = MIN(t, TEST_BUFFER_SIZE);
+ nets = lp_alloc(lp0, tb * sizeof(net_addr));
+
+ if (!plus)
+ select_random_prefix_subset(data, nets, n, tb);
+ else
+ make_random_addresses(nets, tb);
+
+ bt_log_suite_case_result(1, "Make test data, %d (%d) tests", t, tb);
+ bt_reset_suite_case_timer();
+
+ /*
+ int match = 0;
+ for (int i = 0; i < t; i++)
+ for (int j = 0; j < n; j++)
+ test_match_net(data[j], trie[j], &nets[i]);
+ */
+
+ int match = 0;
+ for (int i = 0; i < t; i++)
+ for (int j = 0; j < n; j++)
+ if (trie_match_net(trie[j], &nets[i % TEST_BUFFER_SIZE]))
+ match++;
+
+ bt_log_suite_case_result(1, "Matching done, %d / %d matches", match, t * n);
+
+ rfree(lp0);
+ rfree(lp1);
+
+ return 1;
+}
+
+static int UNUSED
+t_bench_trie_datasets_subset(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ /* Specific datasets, not included */
+ benchmark_trie_dataset("trie-data-bgp-1", 0);
+ benchmark_trie_dataset("trie-data-bgp-10", 0);
+ benchmark_trie_dataset("trie-data-bgp-100", 0);
+ benchmark_trie_dataset("trie-data-bgp-1000", 0);
+
+ bt_bird_cleanup();
+
+ return 1;
+}
+
+static int UNUSED
+t_bench_trie_datasets_random(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ /* Specific datasets, not included */
+ benchmark_trie_dataset("trie-data-bgp-1", 1);
+ benchmark_trie_dataset("trie-data-bgp-10", 1);
+ benchmark_trie_dataset("trie-data-bgp-100", 1);
+ benchmark_trie_dataset("trie-data-bgp-1000", 1);
+
+ bt_bird_cleanup();
+
+ return 1;
+}
+
+
static int
t_trie_same(void)
{
bt_bird_init();
bt_config_parse(BT_CONFIG_SIMPLE);
- int round;
- for (round = 0; round < TESTS_NUM*4; round++)
+ int v6 = 0;
+ linpool *lp = lp_new_default(&root_pool);
+ for (int round = 0; round < TESTS_NUM*4; round++)
{
- struct f_trie * trie1 = f_new_trie(config->mem, 0);
- struct f_trie * trie2 = f_new_trie(config->mem, 0);
+ list *prefixes = make_random_prefix_list(lp, 100 * PREFIXES_NUM, v6, 0);
+ struct f_trie *trie1 = f_new_trie(lp, 0);
+ struct f_trie *trie2 = f_new_trie(lp, 0);
- list prefixes; /* a list of f_extended_prefix structures */
- init_list(&prefixes);
- int i;
- for (i = 0; i < 100; i++)
- generate_random_ipv6_prefixes(&prefixes);
+ struct f_prefix_node *n;
+ WALK_LIST(n, *prefixes)
+ trie_add_prefix(trie1, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+
+ WALK_LIST_BACKWARDS(n, *prefixes)
+ trie_add_prefix(trie2, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+
+ bt_assert(trie_same(trie1, trie2));
+
+ v6 = !v6;
+ lp_flush(lp);
+ }
+
+ bt_bird_cleanup();
+ return 1;
+}
+
+static inline void
+log_networks(const net_addr *a, const net_addr *b)
+{
+ if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL)
+ {
+ char buf0[64];
+ char buf1[64];
+ bt_format_net(buf0, 64, a);
+ bt_format_net(buf1, 64, b);
+ bt_debug("Found %s expected %s\n", buf0, buf1);
+ }
+}
+
+static int
+t_trie_walk(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ linpool *lp = lp_new_default(&root_pool);
+ for (int round = 0; round < TESTS_NUM*8; round++)
+ {
+ int level = round / TESTS_NUM;
+ int v6 = level % 2;
+ int num = PREFIXES_NUM * (int[]){1, 10, 100, 1000}[level / 2];
+ int pos = 0, end = 0;
+ list *prefixes = make_random_prefix_list(lp, num, v6, 1);
+ struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+ struct f_prefix *pxset = malloc((num + 1) * sizeof(struct f_prefix));
struct f_prefix_node *n;
- WALK_LIST(n, prefixes)
+ WALK_LIST(n, *prefixes)
+ pxset[pos++] = n->prefix;
+ memset(&pxset[pos], 0, sizeof (struct f_prefix));
+
+ qsort(pxset, num, sizeof(struct f_prefix), compare_prefixes);
+
+
+ /* Full walk */
+ bt_debug("Full walk (round %d, %d nets)\n", round, num);
+
+ pos = 0;
+ uint pxc = 0;
+ TRIE_WALK(trie, net, NULL)
{
- trie_add_prefix(trie1, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+ log_networks(&net, &pxset[pos].net);
+ bt_assert(net_equal(&net, &pxset[pos].net));
+
+ /* Skip possible duplicates */
+ while (net_equal(&pxset[pos].net, &pxset[pos + 1].net))
+ pos++;
+
+ pos++;
+ pxc++;
}
- WALK_LIST_BACKWARDS(n, prefixes)
+ TRIE_WALK_END;
+
+ bt_assert(pos == num);
+ bt_assert(pxc == trie->prefix_count);
+ bt_debug("Full walk done\n");
+
+
+ /* Prepare net for subnet walk - start with random prefix */
+ pos = bt_random() % num;
+ end = pos + (int[]){2, 2, 3, 4}[level / 2];
+ end = MIN(end, num);
+
+ struct f_prefix from = pxset[pos];
+
+ /* Find a common superprefix to several subsequent prefixes */
+ for (; pos < end; pos++)
{
- trie_add_prefix(trie2, &n->prefix.net, n->prefix.lo, n->prefix.hi);
+ if (net_equal(&from.net, &pxset[pos].net))
+ continue;
+
+ int common = !v6 ?
+ ip4_pxlen(net4_prefix(&from.net), net4_prefix(&pxset[pos].net)) :
+ ip6_pxlen(net6_prefix(&from.net), net6_prefix(&pxset[pos].net));
+ from.net.pxlen = MIN(from.net.pxlen, common);
+
+ if (!v6)
+ ((net_addr_ip4 *) &from.net)->prefix =
+ ip4_and(net4_prefix(&from.net), net4_prefix(&pxset[pos].net));
+ else
+ ((net_addr_ip6 *) &from.net)->prefix =
+ ip6_and(net6_prefix(&from.net), net6_prefix(&pxset[pos].net));
}
- bt_assert(trie_same(trie1, trie2));
+ /* Fix irrelevant bits */
+ if (!v6)
+ ((net_addr_ip4 *) &from.net)->prefix =
+ ip4_and(net4_prefix(&from.net), ip4_mkmask(net4_pxlen(&from.net)));
+ else
+ ((net_addr_ip6 *) &from.net)->prefix =
+ ip6_and(net6_prefix(&from.net), ip6_mkmask(net6_pxlen(&from.net)));
+
+
+ /* Find initial position for final prefix */
+ for (pos = 0; pos < num; pos++)
+ if (compare_prefixes(&pxset[pos], &from) >= 0)
+ break;
+
+ int p0 = pos;
+ char buf0[64];
+ bt_format_net(buf0, 64, &from.net);
+ bt_debug("Subnet walk for %s (round %d, %d nets)\n", buf0, round, num);
+
+ /* Subnet walk */
+ TRIE_WALK(trie, net, &from.net)
+ {
+ log_networks(&net, &pxset[pos].net);
+ bt_assert(net_equal(&net, &pxset[pos].net));
+ bt_assert(net_in_netX(&net, &from.net));
+
+ /* Skip possible duplicates */
+ while (net_equal(&pxset[pos].net, &pxset[pos + 1].net))
+ pos++;
- struct f_prefix_node *nxt;
- WALK_LIST_DELSAFE(n, nxt, prefixes)
+ pos++;
+ }
+ TRIE_WALK_END;
+
+ bt_assert((pos == num) || !net_in_netX(&pxset[pos].net, &from.net));
+ bt_debug("Subnet walk done for %s (found %d nets)\n", buf0, pos - p0);
+
+ lp_flush(lp);
+ }
+
+ bt_bird_cleanup();
+ return 1;
+}
+
+static int
+find_covering_nets(struct f_prefix *prefixes, int num, const net_addr *net, net_addr *found)
+{
+ struct f_prefix key;
+ net_addr *n = &key.net;
+ int found_num = 0;
+
+ net_copy(n, net);
+
+ while (1)
+ {
+ struct f_prefix *px =
+ bsearch(&key, prefixes, num, sizeof(struct f_prefix), compare_prefixes);
+
+ if (px)
+ {
+ net_copy(&found[found_num], n);
+ found_num++;
+ }
+
+ if (n->pxlen == 0)
+ return found_num;
+
+ n->pxlen--;
+
+ if (n->type == NET_IP4)
+ ip4_clrbit(&((net_addr_ip4 *) n)->prefix, n->pxlen);
+ else
+ ip6_clrbit(&((net_addr_ip6 *) n)->prefix, n->pxlen);
+ }
+}
+
+static int
+t_trie_walk_to_root(void)
+{
+ bt_bird_init();
+ bt_config_parse(BT_CONFIG_SIMPLE);
+
+ linpool *lp = lp_new_default(&root_pool);
+ for (int round = 0; round < TESTS_NUM * 4; round++)
+ {
+ int level = round / TESTS_NUM;
+ int v6 = level % 2;
+ int num = PREFIXES_NUM * (int[]){32, 512}[level / 2];
+ int pos = 0;
+ int st = 0, sn = 0, sm = 0;
+
+ list *prefixes = make_random_prefix_list(lp, num, v6, 1);
+ struct f_trie *trie = make_trie_from_prefix_list(lp, prefixes);
+ struct f_prefix *pxset = malloc((num + 1) * sizeof(struct f_prefix));
+
+ struct f_prefix_node *pxn;
+ WALK_LIST(pxn, *prefixes)
+ pxset[pos++] = pxn->prefix;
+ memset(&pxset[pos], 0, sizeof (struct f_prefix));
+
+ qsort(pxset, num, sizeof(struct f_prefix), compare_prefixes);
+
+ int i;
+ for (i = 0; i < (PREFIX_TESTS_NUM / 10); i++)
{
- free(n);
+ net_addr from;
+ get_random_net(&from, v6);
+
+ net_addr found[129];
+ int found_num = find_covering_nets(pxset, num, &from, found);
+ int n = 0;
+
+ if (bt_verbose >= BT_VERBOSE_ABSOLUTELY_ALL)
+ {
+ char buf[64];
+ bt_format_net(buf, 64, &from);
+ bt_debug("Lookup for %s (expect %d)\n", buf, found_num);
+ }
+
+ /* Walk to root, separate for IPv4 and IPv6 */
+ if (!v6)
+ {
+ TRIE_WALK_TO_ROOT_IP4(trie, (net_addr_ip4 *) &from, net)
+ {
+ log_networks((net_addr *) &net, &found[n]);
+ bt_assert((n < found_num) && net_equal((net_addr *) &net, &found[n]));
+ n++;
+ }
+ TRIE_WALK_TO_ROOT_END;
+ }
+ else
+ {
+ TRIE_WALK_TO_ROOT_IP6(trie, (net_addr_ip6 *) &from, net)
+ {
+ log_networks((net_addr *) &net, &found[n]);
+ bt_assert((n < found_num) && net_equal((net_addr *) &net, &found[n]));
+ n++;
+ }
+ TRIE_WALK_TO_ROOT_END;
+ }
+
+ bt_assert(n == found_num);
+
+ /* Stats */
+ st += n;
+ sn += !!n;
+ sm = MAX(sm, n);
}
+
+ bt_debug("Success in %d / %d, sum %d, max %d\n", sn, i, st, sm);
+
+ lp_flush(lp);
}
+ bt_bird_cleanup();
return 1;
}
@@ -179,8 +896,15 @@ main(int argc, char *argv[])
{
bt_init(argc, argv);
- bt_test_suite(t_match_net, "Testing random prefix matching");
+ bt_test_suite(t_match_random_net, "Testing random prefix matching");
+ bt_test_suite(t_match_inner_net, "Testing random inner prefix matching");
+ bt_test_suite(t_match_outer_net, "Testing random outer prefix matching");
bt_test_suite(t_trie_same, "A trie filled forward should be same with a trie filled backward.");
+ bt_test_suite(t_trie_walk, "Testing TRIE_WALK() on random tries");
+ bt_test_suite(t_trie_walk_to_root, "Testing TRIE_WALK_TO_ROOT() on random tries");
+
+ // bt_test_suite(t_bench_trie_datasets_subset, "Benchmark tries from datasets by random subset of nets");
+ // bt_test_suite(t_bench_trie_datasets_random, "Benchmark tries from datasets by generated addresses");
return bt_exit_value();
}
diff --git a/lib/Makefile b/lib/Makefile
index 5c78b2a9..4378a7bd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,4 +1,4 @@
-src := bitmap.c bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
obj := $(src-o-files)
$(all-daemon)
diff --git a/lib/birdlib.h b/lib/birdlib.h
index 23036c1b..81d4908a 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -32,6 +32,9 @@ struct align_probe { char x; long int y; };
#define MAX(a,b) MAX_(a,b)
#endif
+#define ROUND_DOWN_POW2(a,b) ((a) & ~((b)-1))
+#define ROUND_UP_POW2(a,b) (((a)+((b)-1)) & ~((b)-1))
+
#define U64(c) UINT64_C(c)
#define ABS(a) ((a)>=0 ? (a) : -(a))
#define DELTA(a,b) (((a)>=(b))?(a)-(b):(b)-(a))
@@ -74,6 +77,9 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define PACKED __attribute__((packed))
#define NONNULL(...) __attribute__((nonnull((__VA_ARGS__))))
+#define STATIC_ASSERT(EXP) _Static_assert(EXP, #EXP)
+#define STATIC_ASSERT_MSG(EXP,MSG) _Static_assert(EXP, MSG)
+
#ifndef HAVE_THREAD_LOCAL
#define _Thread_local
#endif
@@ -192,5 +198,7 @@ asm(
/* Pseudorandom numbers */
u32 random_u32(void);
+void random_init(void);
+void random_bytes(void *buf, size_t size);
#endif
diff --git a/lib/bitops.h b/lib/bitops.h
index a4c48a10..0beda2a3 100644
--- a/lib/bitops.h
+++ b/lib/bitops.h
@@ -28,6 +28,7 @@ u32 u32_log2(u32 v);
static inline u32 u32_hash(u32 v) { return v * 2902958171u; }
static inline u8 u32_popcount(u32 v) { return __builtin_popcount(v); }
+static inline u8 u64_popcount(u64 v) { return __builtin_popcountll(v); }
static inline int u32_clz(u32 v) { return __builtin_clz(v); }
static inline int u32_ctz(u32 v) { return __builtin_ctz(v); }
diff --git a/lib/blake2-impl.h b/lib/blake2-impl.h
new file mode 100644
index 00000000..0970eda0
--- /dev/null
+++ b/lib/blake2-impl.h
@@ -0,0 +1,153 @@
+/*
+ * BIRD Library -- BLAKE2 Support Code
+ *
+ * Based on the code from BLAKE2 reference source code package
+ *
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ *
+ * You may use this under the terms of the CC0, the OpenSSL Licence, or the
+ * Apache Public License 2.0, at your option. The terms of these licenses
+ * can be found at:
+ *
+ * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
+ * - OpenSSL license : https://www.openssl.org/source/license.html
+ * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * More information about the BLAKE2 hash function can be found at
+ * https://blake2.net/ web.
+ */
+
+#ifndef _BIRD_BLAKE2_IMPL_H_
+#define _BIRD_BLAKE2_IMPL_H_
+
+#include "nest/bird.h"
+
+
+static inline u32 load32(const void *src)
+{
+#if !defined(CPU_BIG_ENDIAN)
+ u32 w;
+ memcpy(&w, src, sizeof w);
+ return w;
+#else
+ const u8 *p = (const u8 *) src;
+ return ((u32) (p[0]) << 0) |
+ ((u32) (p[1]) << 8) |
+ ((u32) (p[2]) << 16) |
+ ((u32) (p[3]) << 24) ;
+#endif
+}
+
+static inline u64 load64(const void *src)
+{
+#if !defined(CPU_BIG_ENDIAN)
+ u64 w;
+ memcpy(&w, src, sizeof w);
+ return w;
+#else
+ const u8 *p = (const u8 *) src;
+ return ((u64) (p[0]) << 0) |
+ ((u64) (p[1]) << 8) |
+ ((u64) (p[2]) << 16) |
+ ((u64) (p[3]) << 24) |
+ ((u64) (p[4]) << 32) |
+ ((u64) (p[5]) << 40) |
+ ((u64) (p[6]) << 48) |
+ ((u64) (p[7]) << 56) ;
+#endif
+}
+
+static inline u16 load16(const void *src)
+{
+#if !defined(CPU_BIG_ENDIAN)
+ u16 w;
+ memcpy(&w, src, sizeof w);
+ return w;
+#else
+ const u8 *p = (const u8 *) src;
+ return (u16) (((u32) (p[0]) << 0) |
+ ((u32) (p[1]) << 8));
+#endif
+}
+
+static inline void store16(void *dst, u16 w)
+{
+#if !defined(CPU_BIG_ENDIAN)
+ memcpy(dst, &w, sizeof w);
+#else
+ u8 *p = (u8 *) dst;
+ *p++ = (u8)w; w >>= 8;
+ *p++ = (u8)w;
+#endif
+}
+
+static inline void store32(void *dst, u32 w)
+{
+#if !defined(CPU_BIG_ENDIAN)
+ memcpy(dst, &w, sizeof w);
+#else
+ u8 *p = (u8 *)dst;
+ p[0] = (u8) (w >> 0);
+ p[1] = (u8) (w >> 8);
+ p[2] = (u8) (w >> 16);
+ p[3] = (u8) (w >> 24);
+#endif
+}
+
+static inline void store64(void *dst, u64 w)
+{
+#if !defined(CPU_BIG_ENDIAN)
+ memcpy(dst, &w, sizeof w);
+#else
+ u8 *p = (u8 *) dst;
+ p[0] = (u8) (w >> 0);
+ p[1] = (u8) (w >> 8);
+ p[2] = (u8) (w >> 16);
+ p[3] = (u8) (w >> 24);
+ p[4] = (u8) (w >> 32);
+ p[5] = (u8) (w >> 40);
+ p[6] = (u8) (w >> 48);
+ p[7] = (u8) (w >> 56);
+#endif
+}
+
+static inline u64 load48(const void *src)
+{
+ const u8 *p = (const u8 *) src;
+ return ((u64) (p[0]) << 0) |
+ ((u64) (p[1]) << 8) |
+ ((u64) (p[2]) << 16) |
+ ((u64) (p[3]) << 24) |
+ ((u64) (p[4]) << 32) |
+ ((u64) (p[5]) << 40) ;
+}
+
+static inline void store48(void *dst, u64 w)
+{
+ u8 *p = (u8 *) dst;
+ p[0] = (u8) (w >> 0);
+ p[1] = (u8) (w >> 8);
+ p[2] = (u8) (w >> 16);
+ p[3] = (u8) (w >> 24);
+ p[4] = (u8) (w >> 32);
+ p[5] = (u8) (w >> 40);
+}
+
+static inline u32 rotr32(const u32 w, const uint c)
+{
+ return (w >> c) | (w << (32 - c));
+}
+
+static inline u64 rotr64(const u64 w, const uint c)
+{
+ return (w >> c) | (w << (64 - c));
+}
+
+/* prevents compiler optimizing out memset() */
+static inline void secure_zero_memory(void *v, size_t n)
+{
+ static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
+ memset_v(v, 0, n);
+}
+
+#endif
diff --git a/lib/blake2-kat.h b/lib/blake2-kat.h
new file mode 100644
index 00000000..2a3f9c18
--- /dev/null
+++ b/lib/blake2-kat.h
@@ -0,0 +1,4130 @@
+/*
+ * BIRD Library -- BLAKE2 Test Vectors
+ *
+ * Based on the code from BLAKE2 reference source code package
+ *
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ *
+ * You may use this under the terms of the CC0, the OpenSSL Licence, or the
+ * Apache Public License 2.0, at your option. The terms of these licenses
+ * can be found at:
+ *
+ * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
+ * - OpenSSL license : https://www.openssl.org/source/license.html
+ * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * More information about the BLAKE2 hash function can be found at
+ * https://blake2.net/ web.
+ */
+
+#ifndef _BIRD_BLAKE2_KAT_H_
+#define _BIRD_BLAKE2_KAT_H_
+
+#include <stdint.h>
+
+#define BLAKE2_KAT_LENGTH 256
+
+static const uint8_t blake2s_keyed_kat[BLAKE2_KAT_LENGTH][BLAKE2S_256_SIZE] = {
+ {
+ 0x48, 0xA8, 0x99, 0x7D, 0xA4, 0x07, 0x87, 0x6B,
+ 0x3D, 0x79, 0xC0, 0xD9, 0x23, 0x25, 0xAD, 0x3B,
+ 0x89, 0xCB, 0xB7, 0x54, 0xD8, 0x6A, 0xB7, 0x1A,
+ 0xEE, 0x04, 0x7A, 0xD3, 0x45, 0xFD, 0x2C, 0x49
+ },
+ {
+ 0x40, 0xD1, 0x5F, 0xEE, 0x7C, 0x32, 0x88, 0x30,
+ 0x16, 0x6A, 0xC3, 0xF9, 0x18, 0x65, 0x0F, 0x80,
+ 0x7E, 0x7E, 0x01, 0xE1, 0x77, 0x25, 0x8C, 0xDC,
+ 0x0A, 0x39, 0xB1, 0x1F, 0x59, 0x80, 0x66, 0xF1
+ },
+ {
+ 0x6B, 0xB7, 0x13, 0x00, 0x64, 0x4C, 0xD3, 0x99,
+ 0x1B, 0x26, 0xCC, 0xD4, 0xD2, 0x74, 0xAC, 0xD1,
+ 0xAD, 0xEA, 0xB8, 0xB1, 0xD7, 0x91, 0x45, 0x46,
+ 0xC1, 0x19, 0x8B, 0xBE, 0x9F, 0xC9, 0xD8, 0x03
+ },
+ {
+ 0x1D, 0x22, 0x0D, 0xBE, 0x2E, 0xE1, 0x34, 0x66,
+ 0x1F, 0xDF, 0x6D, 0x9E, 0x74, 0xB4, 0x17, 0x04,
+ 0x71, 0x05, 0x56, 0xF2, 0xF6, 0xE5, 0xA0, 0x91,
+ 0xB2, 0x27, 0x69, 0x74, 0x45, 0xDB, 0xEA, 0x6B
+ },
+ {
+ 0xF6, 0xC3, 0xFB, 0xAD, 0xB4, 0xCC, 0x68, 0x7A,
+ 0x00, 0x64, 0xA5, 0xBE, 0x6E, 0x79, 0x1B, 0xEC,
+ 0x63, 0xB8, 0x68, 0xAD, 0x62, 0xFB, 0xA6, 0x1B,
+ 0x37, 0x57, 0xEF, 0x9C, 0xA5, 0x2E, 0x05, 0xB2
+ },
+ {
+ 0x49, 0xC1, 0xF2, 0x11, 0x88, 0xDF, 0xD7, 0x69,
+ 0xAE, 0xA0, 0xE9, 0x11, 0xDD, 0x6B, 0x41, 0xF1,
+ 0x4D, 0xAB, 0x10, 0x9D, 0x2B, 0x85, 0x97, 0x7A,
+ 0xA3, 0x08, 0x8B, 0x5C, 0x70, 0x7E, 0x85, 0x98
+ },
+ {
+ 0xFD, 0xD8, 0x99, 0x3D, 0xCD, 0x43, 0xF6, 0x96,
+ 0xD4, 0x4F, 0x3C, 0xEA, 0x0F, 0xF3, 0x53, 0x45,
+ 0x23, 0x4E, 0xC8, 0xEE, 0x08, 0x3E, 0xB3, 0xCA,
+ 0xDA, 0x01, 0x7C, 0x7F, 0x78, 0xC1, 0x71, 0x43
+ },
+ {
+ 0xE6, 0xC8, 0x12, 0x56, 0x37, 0x43, 0x8D, 0x09,
+ 0x05, 0xB7, 0x49, 0xF4, 0x65, 0x60, 0xAC, 0x89,
+ 0xFD, 0x47, 0x1C, 0xF8, 0x69, 0x2E, 0x28, 0xFA,
+ 0xB9, 0x82, 0xF7, 0x3F, 0x01, 0x9B, 0x83, 0xA9
+ },
+ {
+ 0x19, 0xFC, 0x8C, 0xA6, 0x97, 0x9D, 0x60, 0xE6,
+ 0xED, 0xD3, 0xB4, 0x54, 0x1E, 0x2F, 0x96, 0x7C,
+ 0xED, 0x74, 0x0D, 0xF6, 0xEC, 0x1E, 0xAE, 0xBB,
+ 0xFE, 0x81, 0x38, 0x32, 0xE9, 0x6B, 0x29, 0x74
+ },
+ {
+ 0xA6, 0xAD, 0x77, 0x7C, 0xE8, 0x81, 0xB5, 0x2B,
+ 0xB5, 0xA4, 0x42, 0x1A, 0xB6, 0xCD, 0xD2, 0xDF,
+ 0xBA, 0x13, 0xE9, 0x63, 0x65, 0x2D, 0x4D, 0x6D,
+ 0x12, 0x2A, 0xEE, 0x46, 0x54, 0x8C, 0x14, 0xA7
+ },
+ {
+ 0xF5, 0xC4, 0xB2, 0xBA, 0x1A, 0x00, 0x78, 0x1B,
+ 0x13, 0xAB, 0xA0, 0x42, 0x52, 0x42, 0xC6, 0x9C,
+ 0xB1, 0x55, 0x2F, 0x3F, 0x71, 0xA9, 0xA3, 0xBB,
+ 0x22, 0xB4, 0xA6, 0xB4, 0x27, 0x7B, 0x46, 0xDD
+ },
+ {
+ 0xE3, 0x3C, 0x4C, 0x9B, 0xD0, 0xCC, 0x7E, 0x45,
+ 0xC8, 0x0E, 0x65, 0xC7, 0x7F, 0xA5, 0x99, 0x7F,
+ 0xEC, 0x70, 0x02, 0x73, 0x85, 0x41, 0x50, 0x9E,
+ 0x68, 0xA9, 0x42, 0x38, 0x91, 0xE8, 0x22, 0xA3
+ },
+ {
+ 0xFB, 0xA1, 0x61, 0x69, 0xB2, 0xC3, 0xEE, 0x10,
+ 0x5B, 0xE6, 0xE1, 0xE6, 0x50, 0xE5, 0xCB, 0xF4,
+ 0x07, 0x46, 0xB6, 0x75, 0x3D, 0x03, 0x6A, 0xB5,
+ 0x51, 0x79, 0x01, 0x4A, 0xD7, 0xEF, 0x66, 0x51
+ },
+ {
+ 0xF5, 0xC4, 0xBE, 0xC6, 0xD6, 0x2F, 0xC6, 0x08,
+ 0xBF, 0x41, 0xCC, 0x11, 0x5F, 0x16, 0xD6, 0x1C,
+ 0x7E, 0xFD, 0x3F, 0xF6, 0xC6, 0x56, 0x92, 0xBB,
+ 0xE0, 0xAF, 0xFF, 0xB1, 0xFE, 0xDE, 0x74, 0x75
+ },
+ {
+ 0xA4, 0x86, 0x2E, 0x76, 0xDB, 0x84, 0x7F, 0x05,
+ 0xBA, 0x17, 0xED, 0xE5, 0xDA, 0x4E, 0x7F, 0x91,
+ 0xB5, 0x92, 0x5C, 0xF1, 0xAD, 0x4B, 0xA1, 0x27,
+ 0x32, 0xC3, 0x99, 0x57, 0x42, 0xA5, 0xCD, 0x6E
+ },
+ {
+ 0x65, 0xF4, 0xB8, 0x60, 0xCD, 0x15, 0xB3, 0x8E,
+ 0xF8, 0x14, 0xA1, 0xA8, 0x04, 0x31, 0x4A, 0x55,
+ 0xBE, 0x95, 0x3C, 0xAA, 0x65, 0xFD, 0x75, 0x8A,
+ 0xD9, 0x89, 0xFF, 0x34, 0xA4, 0x1C, 0x1E, 0xEA
+ },
+ {
+ 0x19, 0xBA, 0x23, 0x4F, 0x0A, 0x4F, 0x38, 0x63,
+ 0x7D, 0x18, 0x39, 0xF9, 0xD9, 0xF7, 0x6A, 0xD9,
+ 0x1C, 0x85, 0x22, 0x30, 0x71, 0x43, 0xC9, 0x7D,
+ 0x5F, 0x93, 0xF6, 0x92, 0x74, 0xCE, 0xC9, 0xA7
+ },
+ {
+ 0x1A, 0x67, 0x18, 0x6C, 0xA4, 0xA5, 0xCB, 0x8E,
+ 0x65, 0xFC, 0xA0, 0xE2, 0xEC, 0xBC, 0x5D, 0xDC,
+ 0x14, 0xAE, 0x38, 0x1B, 0xB8, 0xBF, 0xFE, 0xB9,
+ 0xE0, 0xA1, 0x03, 0x44, 0x9E, 0x3E, 0xF0, 0x3C
+ },
+ {
+ 0xAF, 0xBE, 0xA3, 0x17, 0xB5, 0xA2, 0xE8, 0x9C,
+ 0x0B, 0xD9, 0x0C, 0xCF, 0x5D, 0x7F, 0xD0, 0xED,
+ 0x57, 0xFE, 0x58, 0x5E, 0x4B, 0xE3, 0x27, 0x1B,
+ 0x0A, 0x6B, 0xF0, 0xF5, 0x78, 0x6B, 0x0F, 0x26
+ },
+ {
+ 0xF1, 0xB0, 0x15, 0x58, 0xCE, 0x54, 0x12, 0x62,
+ 0xF5, 0xEC, 0x34, 0x29, 0x9D, 0x6F, 0xB4, 0x09,
+ 0x00, 0x09, 0xE3, 0x43, 0x4B, 0xE2, 0xF4, 0x91,
+ 0x05, 0xCF, 0x46, 0xAF, 0x4D, 0x2D, 0x41, 0x24
+ },
+ {
+ 0x13, 0xA0, 0xA0, 0xC8, 0x63, 0x35, 0x63, 0x5E,
+ 0xAA, 0x74, 0xCA, 0x2D, 0x5D, 0x48, 0x8C, 0x79,
+ 0x7B, 0xBB, 0x4F, 0x47, 0xDC, 0x07, 0x10, 0x50,
+ 0x15, 0xED, 0x6A, 0x1F, 0x33, 0x09, 0xEF, 0xCE
+ },
+ {
+ 0x15, 0x80, 0xAF, 0xEE, 0xBE, 0xBB, 0x34, 0x6F,
+ 0x94, 0xD5, 0x9F, 0xE6, 0x2D, 0xA0, 0xB7, 0x92,
+ 0x37, 0xEA, 0xD7, 0xB1, 0x49, 0x1F, 0x56, 0x67,
+ 0xA9, 0x0E, 0x45, 0xED, 0xF6, 0xCA, 0x8B, 0x03
+ },
+ {
+ 0x20, 0xBE, 0x1A, 0x87, 0x5B, 0x38, 0xC5, 0x73,
+ 0xDD, 0x7F, 0xAA, 0xA0, 0xDE, 0x48, 0x9D, 0x65,
+ 0x5C, 0x11, 0xEF, 0xB6, 0xA5, 0x52, 0x69, 0x8E,
+ 0x07, 0xA2, 0xD3, 0x31, 0xB5, 0xF6, 0x55, 0xC3
+ },
+ {
+ 0xBE, 0x1F, 0xE3, 0xC4, 0xC0, 0x40, 0x18, 0xC5,
+ 0x4C, 0x4A, 0x0F, 0x6B, 0x9A, 0x2E, 0xD3, 0xC5,
+ 0x3A, 0xBE, 0x3A, 0x9F, 0x76, 0xB4, 0xD2, 0x6D,
+ 0xE5, 0x6F, 0xC9, 0xAE, 0x95, 0x05, 0x9A, 0x99
+ },
+ {
+ 0xE3, 0xE3, 0xAC, 0xE5, 0x37, 0xEB, 0x3E, 0xDD,
+ 0x84, 0x63, 0xD9, 0xAD, 0x35, 0x82, 0xE1, 0x3C,
+ 0xF8, 0x65, 0x33, 0xFF, 0xDE, 0x43, 0xD6, 0x68,
+ 0xDD, 0x2E, 0x93, 0xBB, 0xDB, 0xD7, 0x19, 0x5A
+ },
+ {
+ 0x11, 0x0C, 0x50, 0xC0, 0xBF, 0x2C, 0x6E, 0x7A,
+ 0xEB, 0x7E, 0x43, 0x5D, 0x92, 0xD1, 0x32, 0xAB,
+ 0x66, 0x55, 0x16, 0x8E, 0x78, 0xA2, 0xDE, 0xCD,
+ 0xEC, 0x33, 0x30, 0x77, 0x76, 0x84, 0xD9, 0xC1
+ },
+ {
+ 0xE9, 0xBA, 0x8F, 0x50, 0x5C, 0x9C, 0x80, 0xC0,
+ 0x86, 0x66, 0xA7, 0x01, 0xF3, 0x36, 0x7E, 0x6C,
+ 0xC6, 0x65, 0xF3, 0x4B, 0x22, 0xE7, 0x3C, 0x3C,
+ 0x04, 0x17, 0xEB, 0x1C, 0x22, 0x06, 0x08, 0x2F
+ },
+ {
+ 0x26, 0xCD, 0x66, 0xFC, 0xA0, 0x23, 0x79, 0xC7,
+ 0x6D, 0xF1, 0x23, 0x17, 0x05, 0x2B, 0xCA, 0xFD,
+ 0x6C, 0xD8, 0xC3, 0xA7, 0xB8, 0x90, 0xD8, 0x05,
+ 0xF3, 0x6C, 0x49, 0x98, 0x97, 0x82, 0x43, 0x3A
+ },
+ {
+ 0x21, 0x3F, 0x35, 0x96, 0xD6, 0xE3, 0xA5, 0xD0,
+ 0xE9, 0x93, 0x2C, 0xD2, 0x15, 0x91, 0x46, 0x01,
+ 0x5E, 0x2A, 0xBC, 0x94, 0x9F, 0x47, 0x29, 0xEE,
+ 0x26, 0x32, 0xFE, 0x1E, 0xDB, 0x78, 0xD3, 0x37
+ },
+ {
+ 0x10, 0x15, 0xD7, 0x01, 0x08, 0xE0, 0x3B, 0xE1,
+ 0xC7, 0x02, 0xFE, 0x97, 0x25, 0x36, 0x07, 0xD1,
+ 0x4A, 0xEE, 0x59, 0x1F, 0x24, 0x13, 0xEA, 0x67,
+ 0x87, 0x42, 0x7B, 0x64, 0x59, 0xFF, 0x21, 0x9A
+ },
+ {
+ 0x3C, 0xA9, 0x89, 0xDE, 0x10, 0xCF, 0xE6, 0x09,
+ 0x90, 0x94, 0x72, 0xC8, 0xD3, 0x56, 0x10, 0x80,
+ 0x5B, 0x2F, 0x97, 0x77, 0x34, 0xCF, 0x65, 0x2C,
+ 0xC6, 0x4B, 0x3B, 0xFC, 0x88, 0x2D, 0x5D, 0x89
+ },
+ {
+ 0xB6, 0x15, 0x6F, 0x72, 0xD3, 0x80, 0xEE, 0x9E,
+ 0xA6, 0xAC, 0xD1, 0x90, 0x46, 0x4F, 0x23, 0x07,
+ 0xA5, 0xC1, 0x79, 0xEF, 0x01, 0xFD, 0x71, 0xF9,
+ 0x9F, 0x2D, 0x0F, 0x7A, 0x57, 0x36, 0x0A, 0xEA
+ },
+ {
+ 0xC0, 0x3B, 0xC6, 0x42, 0xB2, 0x09, 0x59, 0xCB,
+ 0xE1, 0x33, 0xA0, 0x30, 0x3E, 0x0C, 0x1A, 0xBF,
+ 0xF3, 0xE3, 0x1E, 0xC8, 0xE1, 0xA3, 0x28, 0xEC,
+ 0x85, 0x65, 0xC3, 0x6D, 0xEC, 0xFF, 0x52, 0x65
+ },
+ {
+ 0x2C, 0x3E, 0x08, 0x17, 0x6F, 0x76, 0x0C, 0x62,
+ 0x64, 0xC3, 0xA2, 0xCD, 0x66, 0xFE, 0xC6, 0xC3,
+ 0xD7, 0x8D, 0xE4, 0x3F, 0xC1, 0x92, 0x45, 0x7B,
+ 0x2A, 0x4A, 0x66, 0x0A, 0x1E, 0x0E, 0xB2, 0x2B
+ },
+ {
+ 0xF7, 0x38, 0xC0, 0x2F, 0x3C, 0x1B, 0x19, 0x0C,
+ 0x51, 0x2B, 0x1A, 0x32, 0xDE, 0xAB, 0xF3, 0x53,
+ 0x72, 0x8E, 0x0E, 0x9A, 0xB0, 0x34, 0x49, 0x0E,
+ 0x3C, 0x34, 0x09, 0x94, 0x6A, 0x97, 0xAE, 0xEC
+ },
+ {
+ 0x8B, 0x18, 0x80, 0xDF, 0x30, 0x1C, 0xC9, 0x63,
+ 0x41, 0x88, 0x11, 0x08, 0x89, 0x64, 0x83, 0x92,
+ 0x87, 0xFF, 0x7F, 0xE3, 0x1C, 0x49, 0xEA, 0x6E,
+ 0xBD, 0x9E, 0x48, 0xBD, 0xEE, 0xE4, 0x97, 0xC5
+ },
+ {
+ 0x1E, 0x75, 0xCB, 0x21, 0xC6, 0x09, 0x89, 0x02,
+ 0x03, 0x75, 0xF1, 0xA7, 0xA2, 0x42, 0x83, 0x9F,
+ 0x0B, 0x0B, 0x68, 0x97, 0x3A, 0x4C, 0x2A, 0x05,
+ 0xCF, 0x75, 0x55, 0xED, 0x5A, 0xAE, 0xC4, 0xC1
+ },
+ {
+ 0x62, 0xBF, 0x8A, 0x9C, 0x32, 0xA5, 0xBC, 0xCF,
+ 0x29, 0x0B, 0x6C, 0x47, 0x4D, 0x75, 0xB2, 0xA2,
+ 0xA4, 0x09, 0x3F, 0x1A, 0x9E, 0x27, 0x13, 0x94,
+ 0x33, 0xA8, 0xF2, 0xB3, 0xBC, 0xE7, 0xB8, 0xD7
+ },
+ {
+ 0x16, 0x6C, 0x83, 0x50, 0xD3, 0x17, 0x3B, 0x5E,
+ 0x70, 0x2B, 0x78, 0x3D, 0xFD, 0x33, 0xC6, 0x6E,
+ 0xE0, 0x43, 0x27, 0x42, 0xE9, 0xB9, 0x2B, 0x99,
+ 0x7F, 0xD2, 0x3C, 0x60, 0xDC, 0x67, 0x56, 0xCA
+ },
+ {
+ 0x04, 0x4A, 0x14, 0xD8, 0x22, 0xA9, 0x0C, 0xAC,
+ 0xF2, 0xF5, 0xA1, 0x01, 0x42, 0x8A, 0xDC, 0x8F,
+ 0x41, 0x09, 0x38, 0x6C, 0xCB, 0x15, 0x8B, 0xF9,
+ 0x05, 0xC8, 0x61, 0x8B, 0x8E, 0xE2, 0x4E, 0xC3
+ },
+ {
+ 0x38, 0x7D, 0x39, 0x7E, 0xA4, 0x3A, 0x99, 0x4B,
+ 0xE8, 0x4D, 0x2D, 0x54, 0x4A, 0xFB, 0xE4, 0x81,
+ 0xA2, 0x00, 0x0F, 0x55, 0x25, 0x26, 0x96, 0xBB,
+ 0xA2, 0xC5, 0x0C, 0x8E, 0xBD, 0x10, 0x13, 0x47
+ },
+ {
+ 0x56, 0xF8, 0xCC, 0xF1, 0xF8, 0x64, 0x09, 0xB4,
+ 0x6C, 0xE3, 0x61, 0x66, 0xAE, 0x91, 0x65, 0x13,
+ 0x84, 0x41, 0x57, 0x75, 0x89, 0xDB, 0x08, 0xCB,
+ 0xC5, 0xF6, 0x6C, 0xA2, 0x97, 0x43, 0xB9, 0xFD
+ },
+ {
+ 0x97, 0x06, 0xC0, 0x92, 0xB0, 0x4D, 0x91, 0xF5,
+ 0x3D, 0xFF, 0x91, 0xFA, 0x37, 0xB7, 0x49, 0x3D,
+ 0x28, 0xB5, 0x76, 0xB5, 0xD7, 0x10, 0x46, 0x9D,
+ 0xF7, 0x94, 0x01, 0x66, 0x22, 0x36, 0xFC, 0x03
+ },
+ {
+ 0x87, 0x79, 0x68, 0x68, 0x6C, 0x06, 0x8C, 0xE2,
+ 0xF7, 0xE2, 0xAD, 0xCF, 0xF6, 0x8B, 0xF8, 0x74,
+ 0x8E, 0xDF, 0x3C, 0xF8, 0x62, 0xCF, 0xB4, 0xD3,
+ 0x94, 0x7A, 0x31, 0x06, 0x95, 0x80, 0x54, 0xE3
+ },
+ {
+ 0x88, 0x17, 0xE5, 0x71, 0x98, 0x79, 0xAC, 0xF7,
+ 0x02, 0x47, 0x87, 0xEC, 0xCD, 0xB2, 0x71, 0x03,
+ 0x55, 0x66, 0xCF, 0xA3, 0x33, 0xE0, 0x49, 0x40,
+ 0x7C, 0x01, 0x78, 0xCC, 0xC5, 0x7A, 0x5B, 0x9F
+ },
+ {
+ 0x89, 0x38, 0x24, 0x9E, 0x4B, 0x50, 0xCA, 0xDA,
+ 0xCC, 0xDF, 0x5B, 0x18, 0x62, 0x13, 0x26, 0xCB,
+ 0xB1, 0x52, 0x53, 0xE3, 0x3A, 0x20, 0xF5, 0x63,
+ 0x6E, 0x99, 0x5D, 0x72, 0x47, 0x8D, 0xE4, 0x72
+ },
+ {
+ 0xF1, 0x64, 0xAB, 0xBA, 0x49, 0x63, 0xA4, 0x4D,
+ 0x10, 0x72, 0x57, 0xE3, 0x23, 0x2D, 0x90, 0xAC,
+ 0xA5, 0xE6, 0x6A, 0x14, 0x08, 0x24, 0x8C, 0x51,
+ 0x74, 0x1E, 0x99, 0x1D, 0xB5, 0x22, 0x77, 0x56
+ },
+ {
+ 0xD0, 0x55, 0x63, 0xE2, 0xB1, 0xCB, 0xA0, 0xC4,
+ 0xA2, 0xA1, 0xE8, 0xBD, 0xE3, 0xA1, 0xA0, 0xD9,
+ 0xF5, 0xB4, 0x0C, 0x85, 0xA0, 0x70, 0xD6, 0xF5,
+ 0xFB, 0x21, 0x06, 0x6E, 0xAD, 0x5D, 0x06, 0x01
+ },
+ {
+ 0x03, 0xFB, 0xB1, 0x63, 0x84, 0xF0, 0xA3, 0x86,
+ 0x6F, 0x4C, 0x31, 0x17, 0x87, 0x76, 0x66, 0xEF,
+ 0xBF, 0x12, 0x45, 0x97, 0x56, 0x4B, 0x29, 0x3D,
+ 0x4A, 0xAB, 0x0D, 0x26, 0x9F, 0xAB, 0xDD, 0xFA
+ },
+ {
+ 0x5F, 0xA8, 0x48, 0x6A, 0xC0, 0xE5, 0x29, 0x64,
+ 0xD1, 0x88, 0x1B, 0xBE, 0x33, 0x8E, 0xB5, 0x4B,
+ 0xE2, 0xF7, 0x19, 0x54, 0x92, 0x24, 0x89, 0x20,
+ 0x57, 0xB4, 0xDA, 0x04, 0xBA, 0x8B, 0x34, 0x75
+ },
+ {
+ 0xCD, 0xFA, 0xBC, 0xEE, 0x46, 0x91, 0x11, 0x11,
+ 0x23, 0x6A, 0x31, 0x70, 0x8B, 0x25, 0x39, 0xD7,
+ 0x1F, 0xC2, 0x11, 0xD9, 0xB0, 0x9C, 0x0D, 0x85,
+ 0x30, 0xA1, 0x1E, 0x1D, 0xBF, 0x6E, 0xED, 0x01
+ },
+ {
+ 0x4F, 0x82, 0xDE, 0x03, 0xB9, 0x50, 0x47, 0x93,
+ 0xB8, 0x2A, 0x07, 0xA0, 0xBD, 0xCD, 0xFF, 0x31,
+ 0x4D, 0x75, 0x9E, 0x7B, 0x62, 0xD2, 0x6B, 0x78,
+ 0x49, 0x46, 0xB0, 0xD3, 0x6F, 0x91, 0x6F, 0x52
+ },
+ {
+ 0x25, 0x9E, 0xC7, 0xF1, 0x73, 0xBC, 0xC7, 0x6A,
+ 0x09, 0x94, 0xC9, 0x67, 0xB4, 0xF5, 0xF0, 0x24,
+ 0xC5, 0x60, 0x57, 0xFB, 0x79, 0xC9, 0x65, 0xC4,
+ 0xFA, 0xE4, 0x18, 0x75, 0xF0, 0x6A, 0x0E, 0x4C
+ },
+ {
+ 0x19, 0x3C, 0xC8, 0xE7, 0xC3, 0xE0, 0x8B, 0xB3,
+ 0x0F, 0x54, 0x37, 0xAA, 0x27, 0xAD, 0xE1, 0xF1,
+ 0x42, 0x36, 0x9B, 0x24, 0x6A, 0x67, 0x5B, 0x23,
+ 0x83, 0xE6, 0xDA, 0x9B, 0x49, 0xA9, 0x80, 0x9E
+ },
+ {
+ 0x5C, 0x10, 0x89, 0x6F, 0x0E, 0x28, 0x56, 0xB2,
+ 0xA2, 0xEE, 0xE0, 0xFE, 0x4A, 0x2C, 0x16, 0x33,
+ 0x56, 0x5D, 0x18, 0xF0, 0xE9, 0x3E, 0x1F, 0xAB,
+ 0x26, 0xC3, 0x73, 0xE8, 0xF8, 0x29, 0x65, 0x4D
+ },
+ {
+ 0xF1, 0x60, 0x12, 0xD9, 0x3F, 0x28, 0x85, 0x1A,
+ 0x1E, 0xB9, 0x89, 0xF5, 0xD0, 0xB4, 0x3F, 0x3F,
+ 0x39, 0xCA, 0x73, 0xC9, 0xA6, 0x2D, 0x51, 0x81,
+ 0xBF, 0xF2, 0x37, 0x53, 0x6B, 0xD3, 0x48, 0xC3
+ },
+ {
+ 0x29, 0x66, 0xB3, 0xCF, 0xAE, 0x1E, 0x44, 0xEA,
+ 0x99, 0x6D, 0xC5, 0xD6, 0x86, 0xCF, 0x25, 0xFA,
+ 0x05, 0x3F, 0xB6, 0xF6, 0x72, 0x01, 0xB9, 0xE4,
+ 0x6E, 0xAD, 0xE8, 0x5D, 0x0A, 0xD6, 0xB8, 0x06
+ },
+ {
+ 0xDD, 0xB8, 0x78, 0x24, 0x85, 0xE9, 0x00, 0xBC,
+ 0x60, 0xBC, 0xF4, 0xC3, 0x3A, 0x6F, 0xD5, 0x85,
+ 0x68, 0x0C, 0xC6, 0x83, 0xD5, 0x16, 0xEF, 0xA0,
+ 0x3E, 0xB9, 0x98, 0x5F, 0xAD, 0x87, 0x15, 0xFB
+ },
+ {
+ 0x4C, 0x4D, 0x6E, 0x71, 0xAE, 0xA0, 0x57, 0x86,
+ 0x41, 0x31, 0x48, 0xFC, 0x7A, 0x78, 0x6B, 0x0E,
+ 0xCA, 0xF5, 0x82, 0xCF, 0xF1, 0x20, 0x9F, 0x5A,
+ 0x80, 0x9F, 0xBA, 0x85, 0x04, 0xCE, 0x66, 0x2C
+ },
+ {
+ 0xFB, 0x4C, 0x5E, 0x86, 0xD7, 0xB2, 0x22, 0x9B,
+ 0x99, 0xB8, 0xBA, 0x6D, 0x94, 0xC2, 0x47, 0xEF,
+ 0x96, 0x4A, 0xA3, 0xA2, 0xBA, 0xE8, 0xED, 0xC7,
+ 0x75, 0x69, 0xF2, 0x8D, 0xBB, 0xFF, 0x2D, 0x4E
+ },
+ {
+ 0xE9, 0x4F, 0x52, 0x6D, 0xE9, 0x01, 0x96, 0x33,
+ 0xEC, 0xD5, 0x4A, 0xC6, 0x12, 0x0F, 0x23, 0x95,
+ 0x8D, 0x77, 0x18, 0xF1, 0xE7, 0x71, 0x7B, 0xF3,
+ 0x29, 0x21, 0x1A, 0x4F, 0xAE, 0xED, 0x4E, 0x6D
+ },
+ {
+ 0xCB, 0xD6, 0x66, 0x0A, 0x10, 0xDB, 0x3F, 0x23,
+ 0xF7, 0xA0, 0x3D, 0x4B, 0x9D, 0x40, 0x44, 0xC7,
+ 0x93, 0x2B, 0x28, 0x01, 0xAC, 0x89, 0xD6, 0x0B,
+ 0xC9, 0xEB, 0x92, 0xD6, 0x5A, 0x46, 0xC2, 0xA0
+ },
+ {
+ 0x88, 0x18, 0xBB, 0xD3, 0xDB, 0x4D, 0xC1, 0x23,
+ 0xB2, 0x5C, 0xBB, 0xA5, 0xF5, 0x4C, 0x2B, 0xC4,
+ 0xB3, 0xFC, 0xF9, 0xBF, 0x7D, 0x7A, 0x77, 0x09,
+ 0xF4, 0xAE, 0x58, 0x8B, 0x26, 0x7C, 0x4E, 0xCE
+ },
+ {
+ 0xC6, 0x53, 0x82, 0x51, 0x3F, 0x07, 0x46, 0x0D,
+ 0xA3, 0x98, 0x33, 0xCB, 0x66, 0x6C, 0x5E, 0xD8,
+ 0x2E, 0x61, 0xB9, 0xE9, 0x98, 0xF4, 0xB0, 0xC4,
+ 0x28, 0x7C, 0xEE, 0x56, 0xC3, 0xCC, 0x9B, 0xCD
+ },
+ {
+ 0x89, 0x75, 0xB0, 0x57, 0x7F, 0xD3, 0x55, 0x66,
+ 0xD7, 0x50, 0xB3, 0x62, 0xB0, 0x89, 0x7A, 0x26,
+ 0xC3, 0x99, 0x13, 0x6D, 0xF0, 0x7B, 0xAB, 0xAB,
+ 0xBD, 0xE6, 0x20, 0x3F, 0xF2, 0x95, 0x4E, 0xD4
+ },
+ {
+ 0x21, 0xFE, 0x0C, 0xEB, 0x00, 0x52, 0xBE, 0x7F,
+ 0xB0, 0xF0, 0x04, 0x18, 0x7C, 0xAC, 0xD7, 0xDE,
+ 0x67, 0xFA, 0x6E, 0xB0, 0x93, 0x8D, 0x92, 0x76,
+ 0x77, 0xF2, 0x39, 0x8C, 0x13, 0x23, 0x17, 0xA8
+ },
+ {
+ 0x2E, 0xF7, 0x3F, 0x3C, 0x26, 0xF1, 0x2D, 0x93,
+ 0x88, 0x9F, 0x3C, 0x78, 0xB6, 0xA6, 0x6C, 0x1D,
+ 0x52, 0xB6, 0x49, 0xDC, 0x9E, 0x85, 0x6E, 0x2C,
+ 0x17, 0x2E, 0xA7, 0xC5, 0x8A, 0xC2, 0xB5, 0xE3
+ },
+ {
+ 0x38, 0x8A, 0x3C, 0xD5, 0x6D, 0x73, 0x86, 0x7A,
+ 0xBB, 0x5F, 0x84, 0x01, 0x49, 0x2B, 0x6E, 0x26,
+ 0x81, 0xEB, 0x69, 0x85, 0x1E, 0x76, 0x7F, 0xD8,
+ 0x42, 0x10, 0xA5, 0x60, 0x76, 0xFB, 0x3D, 0xD3
+ },
+ {
+ 0xAF, 0x53, 0x3E, 0x02, 0x2F, 0xC9, 0x43, 0x9E,
+ 0x4E, 0x3C, 0xB8, 0x38, 0xEC, 0xD1, 0x86, 0x92,
+ 0x23, 0x2A, 0xDF, 0x6F, 0xE9, 0x83, 0x95, 0x26,
+ 0xD3, 0xC3, 0xDD, 0x1B, 0x71, 0x91, 0x0B, 0x1A
+ },
+ {
+ 0x75, 0x1C, 0x09, 0xD4, 0x1A, 0x93, 0x43, 0x88,
+ 0x2A, 0x81, 0xCD, 0x13, 0xEE, 0x40, 0x81, 0x8D,
+ 0x12, 0xEB, 0x44, 0xC6, 0xC7, 0xF4, 0x0D, 0xF1,
+ 0x6E, 0x4A, 0xEA, 0x8F, 0xAB, 0x91, 0x97, 0x2A
+ },
+ {
+ 0x5B, 0x73, 0xDD, 0xB6, 0x8D, 0x9D, 0x2B, 0x0A,
+ 0xA2, 0x65, 0xA0, 0x79, 0x88, 0xD6, 0xB8, 0x8A,
+ 0xE9, 0xAA, 0xC5, 0x82, 0xAF, 0x83, 0x03, 0x2F,
+ 0x8A, 0x9B, 0x21, 0xA2, 0xE1, 0xB7, 0xBF, 0x18
+ },
+ {
+ 0x3D, 0xA2, 0x91, 0x26, 0xC7, 0xC5, 0xD7, 0xF4,
+ 0x3E, 0x64, 0x24, 0x2A, 0x79, 0xFE, 0xAA, 0x4E,
+ 0xF3, 0x45, 0x9C, 0xDE, 0xCC, 0xC8, 0x98, 0xED,
+ 0x59, 0xA9, 0x7F, 0x6E, 0xC9, 0x3B, 0x9D, 0xAB
+ },
+ {
+ 0x56, 0x6D, 0xC9, 0x20, 0x29, 0x3D, 0xA5, 0xCB,
+ 0x4F, 0xE0, 0xAA, 0x8A, 0xBD, 0xA8, 0xBB, 0xF5,
+ 0x6F, 0x55, 0x23, 0x13, 0xBF, 0xF1, 0x90, 0x46,
+ 0x64, 0x1E, 0x36, 0x15, 0xC1, 0xE3, 0xED, 0x3F
+ },
+ {
+ 0x41, 0x15, 0xBE, 0xA0, 0x2F, 0x73, 0xF9, 0x7F,
+ 0x62, 0x9E, 0x5C, 0x55, 0x90, 0x72, 0x0C, 0x01,
+ 0xE7, 0xE4, 0x49, 0xAE, 0x2A, 0x66, 0x97, 0xD4,
+ 0xD2, 0x78, 0x33, 0x21, 0x30, 0x36, 0x92, 0xF9
+ },
+ {
+ 0x4C, 0xE0, 0x8F, 0x47, 0x62, 0x46, 0x8A, 0x76,
+ 0x70, 0x01, 0x21, 0x64, 0x87, 0x8D, 0x68, 0x34,
+ 0x0C, 0x52, 0xA3, 0x5E, 0x66, 0xC1, 0x88, 0x4D,
+ 0x5C, 0x86, 0x48, 0x89, 0xAB, 0xC9, 0x66, 0x77
+ },
+ {
+ 0x81, 0xEA, 0x0B, 0x78, 0x04, 0x12, 0x4E, 0x0C,
+ 0x22, 0xEA, 0x5F, 0xC7, 0x11, 0x04, 0xA2, 0xAF,
+ 0xCB, 0x52, 0xA1, 0xFA, 0x81, 0x6F, 0x3E, 0xCB,
+ 0x7D, 0xCB, 0x5D, 0x9D, 0xEA, 0x17, 0x86, 0xD0
+ },
+ {
+ 0xFE, 0x36, 0x27, 0x33, 0xB0, 0x5F, 0x6B, 0xED,
+ 0xAF, 0x93, 0x79, 0xD7, 0xF7, 0x93, 0x6E, 0xDE,
+ 0x20, 0x9B, 0x1F, 0x83, 0x23, 0xC3, 0x92, 0x25,
+ 0x49, 0xD9, 0xE7, 0x36, 0x81, 0xB5, 0xDB, 0x7B
+ },
+ {
+ 0xEF, 0xF3, 0x7D, 0x30, 0xDF, 0xD2, 0x03, 0x59,
+ 0xBE, 0x4E, 0x73, 0xFD, 0xF4, 0x0D, 0x27, 0x73,
+ 0x4B, 0x3D, 0xF9, 0x0A, 0x97, 0xA5, 0x5E, 0xD7,
+ 0x45, 0x29, 0x72, 0x94, 0xCA, 0x85, 0xD0, 0x9F
+ },
+ {
+ 0x17, 0x2F, 0xFC, 0x67, 0x15, 0x3D, 0x12, 0xE0,
+ 0xCA, 0x76, 0xA8, 0xB6, 0xCD, 0x5D, 0x47, 0x31,
+ 0x88, 0x5B, 0x39, 0xCE, 0x0C, 0xAC, 0x93, 0xA8,
+ 0x97, 0x2A, 0x18, 0x00, 0x6C, 0x8B, 0x8B, 0xAF
+ },
+ {
+ 0xC4, 0x79, 0x57, 0xF1, 0xCC, 0x88, 0xE8, 0x3E,
+ 0xF9, 0x44, 0x58, 0x39, 0x70, 0x9A, 0x48, 0x0A,
+ 0x03, 0x6B, 0xED, 0x5F, 0x88, 0xAC, 0x0F, 0xCC,
+ 0x8E, 0x1E, 0x70, 0x3F, 0xFA, 0xAC, 0x13, 0x2C
+ },
+ {
+ 0x30, 0xF3, 0x54, 0x83, 0x70, 0xCF, 0xDC, 0xED,
+ 0xA5, 0xC3, 0x7B, 0x56, 0x9B, 0x61, 0x75, 0xE7,
+ 0x99, 0xEE, 0xF1, 0xA6, 0x2A, 0xAA, 0x94, 0x32,
+ 0x45, 0xAE, 0x76, 0x69, 0xC2, 0x27, 0xA7, 0xB5
+ },
+ {
+ 0xC9, 0x5D, 0xCB, 0x3C, 0xF1, 0xF2, 0x7D, 0x0E,
+ 0xEF, 0x2F, 0x25, 0xD2, 0x41, 0x38, 0x70, 0x90,
+ 0x4A, 0x87, 0x7C, 0x4A, 0x56, 0xC2, 0xDE, 0x1E,
+ 0x83, 0xE2, 0xBC, 0x2A, 0xE2, 0xE4, 0x68, 0x21
+ },
+ {
+ 0xD5, 0xD0, 0xB5, 0xD7, 0x05, 0x43, 0x4C, 0xD4,
+ 0x6B, 0x18, 0x57, 0x49, 0xF6, 0x6B, 0xFB, 0x58,
+ 0x36, 0xDC, 0xDF, 0x6E, 0xE5, 0x49, 0xA2, 0xB7,
+ 0xA4, 0xAE, 0xE7, 0xF5, 0x80, 0x07, 0xCA, 0xAF
+ },
+ {
+ 0xBB, 0xC1, 0x24, 0xA7, 0x12, 0xF1, 0x5D, 0x07,
+ 0xC3, 0x00, 0xE0, 0x5B, 0x66, 0x83, 0x89, 0xA4,
+ 0x39, 0xC9, 0x17, 0x77, 0xF7, 0x21, 0xF8, 0x32,
+ 0x0C, 0x1C, 0x90, 0x78, 0x06, 0x6D, 0x2C, 0x7E
+ },
+ {
+ 0xA4, 0x51, 0xB4, 0x8C, 0x35, 0xA6, 0xC7, 0x85,
+ 0x4C, 0xFA, 0xAE, 0x60, 0x26, 0x2E, 0x76, 0x99,
+ 0x08, 0x16, 0x38, 0x2A, 0xC0, 0x66, 0x7E, 0x5A,
+ 0x5C, 0x9E, 0x1B, 0x46, 0xC4, 0x34, 0x2D, 0xDF
+ },
+ {
+ 0xB0, 0xD1, 0x50, 0xFB, 0x55, 0xE7, 0x78, 0xD0,
+ 0x11, 0x47, 0xF0, 0xB5, 0xD8, 0x9D, 0x99, 0xEC,
+ 0xB2, 0x0F, 0xF0, 0x7E, 0x5E, 0x67, 0x60, 0xD6,
+ 0xB6, 0x45, 0xEB, 0x5B, 0x65, 0x4C, 0x62, 0x2B
+ },
+ {
+ 0x34, 0xF7, 0x37, 0xC0, 0xAB, 0x21, 0x99, 0x51,
+ 0xEE, 0xE8, 0x9A, 0x9F, 0x8D, 0xAC, 0x29, 0x9C,
+ 0x9D, 0x4C, 0x38, 0xF3, 0x3F, 0xA4, 0x94, 0xC5,
+ 0xC6, 0xEE, 0xFC, 0x92, 0xB6, 0xDB, 0x08, 0xBC
+ },
+ {
+ 0x1A, 0x62, 0xCC, 0x3A, 0x00, 0x80, 0x0D, 0xCB,
+ 0xD9, 0x98, 0x91, 0x08, 0x0C, 0x1E, 0x09, 0x84,
+ 0x58, 0x19, 0x3A, 0x8C, 0xC9, 0xF9, 0x70, 0xEA,
+ 0x99, 0xFB, 0xEF, 0xF0, 0x03, 0x18, 0xC2, 0x89
+ },
+ {
+ 0xCF, 0xCE, 0x55, 0xEB, 0xAF, 0xC8, 0x40, 0xD7,
+ 0xAE, 0x48, 0x28, 0x1C, 0x7F, 0xD5, 0x7E, 0xC8,
+ 0xB4, 0x82, 0xD4, 0xB7, 0x04, 0x43, 0x74, 0x95,
+ 0x49, 0x5A, 0xC4, 0x14, 0xCF, 0x4A, 0x37, 0x4B
+ },
+ {
+ 0x67, 0x46, 0xFA, 0xCF, 0x71, 0x14, 0x6D, 0x99,
+ 0x9D, 0xAB, 0xD0, 0x5D, 0x09, 0x3A, 0xE5, 0x86,
+ 0x64, 0x8D, 0x1E, 0xE2, 0x8E, 0x72, 0x61, 0x7B,
+ 0x99, 0xD0, 0xF0, 0x08, 0x6E, 0x1E, 0x45, 0xBF
+ },
+ {
+ 0x57, 0x1C, 0xED, 0x28, 0x3B, 0x3F, 0x23, 0xB4,
+ 0xE7, 0x50, 0xBF, 0x12, 0xA2, 0xCA, 0xF1, 0x78,
+ 0x18, 0x47, 0xBD, 0x89, 0x0E, 0x43, 0x60, 0x3C,
+ 0xDC, 0x59, 0x76, 0x10, 0x2B, 0x7B, 0xB1, 0x1B
+ },
+ {
+ 0xCF, 0xCB, 0x76, 0x5B, 0x04, 0x8E, 0x35, 0x02,
+ 0x2C, 0x5D, 0x08, 0x9D, 0x26, 0xE8, 0x5A, 0x36,
+ 0xB0, 0x05, 0xA2, 0xB8, 0x04, 0x93, 0xD0, 0x3A,
+ 0x14, 0x4E, 0x09, 0xF4, 0x09, 0xB6, 0xAF, 0xD1
+ },
+ {
+ 0x40, 0x50, 0xC7, 0xA2, 0x77, 0x05, 0xBB, 0x27,
+ 0xF4, 0x20, 0x89, 0xB2, 0x99, 0xF3, 0xCB, 0xE5,
+ 0x05, 0x4E, 0xAD, 0x68, 0x72, 0x7E, 0x8E, 0xF9,
+ 0x31, 0x8C, 0xE6, 0xF2, 0x5C, 0xD6, 0xF3, 0x1D
+ },
+ {
+ 0x18, 0x40, 0x70, 0xBD, 0x5D, 0x26, 0x5F, 0xBD,
+ 0xC1, 0x42, 0xCD, 0x1C, 0x5C, 0xD0, 0xD7, 0xE4,
+ 0x14, 0xE7, 0x03, 0x69, 0xA2, 0x66, 0xD6, 0x27,
+ 0xC8, 0xFB, 0xA8, 0x4F, 0xA5, 0xE8, 0x4C, 0x34
+ },
+ {
+ 0x9E, 0xDD, 0xA9, 0xA4, 0x44, 0x39, 0x02, 0xA9,
+ 0x58, 0x8C, 0x0D, 0x0C, 0xCC, 0x62, 0xB9, 0x30,
+ 0x21, 0x84, 0x79, 0xA6, 0x84, 0x1E, 0x6F, 0xE7,
+ 0xD4, 0x30, 0x03, 0xF0, 0x4B, 0x1F, 0xD6, 0x43
+ },
+ {
+ 0xE4, 0x12, 0xFE, 0xEF, 0x79, 0x08, 0x32, 0x4A,
+ 0x6D, 0xA1, 0x84, 0x16, 0x29, 0xF3, 0x5D, 0x3D,
+ 0x35, 0x86, 0x42, 0x01, 0x93, 0x10, 0xEC, 0x57,
+ 0xC6, 0x14, 0x83, 0x6B, 0x63, 0xD3, 0x07, 0x63
+ },
+ {
+ 0x1A, 0x2B, 0x8E, 0xDF, 0xF3, 0xF9, 0xAC, 0xC1,
+ 0x55, 0x4F, 0xCB, 0xAE, 0x3C, 0xF1, 0xD6, 0x29,
+ 0x8C, 0x64, 0x62, 0xE2, 0x2E, 0x5E, 0xB0, 0x25,
+ 0x96, 0x84, 0xF8, 0x35, 0x01, 0x2B, 0xD1, 0x3F
+ },
+ {
+ 0x28, 0x8C, 0x4A, 0xD9, 0xB9, 0x40, 0x97, 0x62,
+ 0xEA, 0x07, 0xC2, 0x4A, 0x41, 0xF0, 0x4F, 0x69,
+ 0xA7, 0xD7, 0x4B, 0xEE, 0x2D, 0x95, 0x43, 0x53,
+ 0x74, 0xBD, 0xE9, 0x46, 0xD7, 0x24, 0x1C, 0x7B
+ },
+ {
+ 0x80, 0x56, 0x91, 0xBB, 0x28, 0x67, 0x48, 0xCF,
+ 0xB5, 0x91, 0xD3, 0xAE, 0xBE, 0x7E, 0x6F, 0x4E,
+ 0x4D, 0xC6, 0xE2, 0x80, 0x8C, 0x65, 0x14, 0x3C,
+ 0xC0, 0x04, 0xE4, 0xEB, 0x6F, 0xD0, 0x9D, 0x43
+ },
+ {
+ 0xD4, 0xAC, 0x8D, 0x3A, 0x0A, 0xFC, 0x6C, 0xFA,
+ 0x7B, 0x46, 0x0A, 0xE3, 0x00, 0x1B, 0xAE, 0xB3,
+ 0x6D, 0xAD, 0xB3, 0x7D, 0xA0, 0x7D, 0x2E, 0x8A,
+ 0xC9, 0x18, 0x22, 0xDF, 0x34, 0x8A, 0xED, 0x3D
+ },
+ {
+ 0xC3, 0x76, 0x61, 0x70, 0x14, 0xD2, 0x01, 0x58,
+ 0xBC, 0xED, 0x3D, 0x3B, 0xA5, 0x52, 0xB6, 0xEC,
+ 0xCF, 0x84, 0xE6, 0x2A, 0xA3, 0xEB, 0x65, 0x0E,
+ 0x90, 0x02, 0x9C, 0x84, 0xD1, 0x3E, 0xEA, 0x69
+ },
+ {
+ 0xC4, 0x1F, 0x09, 0xF4, 0x3C, 0xEC, 0xAE, 0x72,
+ 0x93, 0xD6, 0x00, 0x7C, 0xA0, 0xA3, 0x57, 0x08,
+ 0x7D, 0x5A, 0xE5, 0x9B, 0xE5, 0x00, 0xC1, 0xCD,
+ 0x5B, 0x28, 0x9E, 0xE8, 0x10, 0xC7, 0xB0, 0x82
+ },
+ {
+ 0x03, 0xD1, 0xCE, 0xD1, 0xFB, 0xA5, 0xC3, 0x91,
+ 0x55, 0xC4, 0x4B, 0x77, 0x65, 0xCB, 0x76, 0x0C,
+ 0x78, 0x70, 0x8D, 0xCF, 0xC8, 0x0B, 0x0B, 0xD8,
+ 0xAD, 0xE3, 0xA5, 0x6D, 0xA8, 0x83, 0x0B, 0x29
+ },
+ {
+ 0x09, 0xBD, 0xE6, 0xF1, 0x52, 0x21, 0x8D, 0xC9,
+ 0x2C, 0x41, 0xD7, 0xF4, 0x53, 0x87, 0xE6, 0x3E,
+ 0x58, 0x69, 0xD8, 0x07, 0xEC, 0x70, 0xB8, 0x21,
+ 0x40, 0x5D, 0xBD, 0x88, 0x4B, 0x7F, 0xCF, 0x4B
+ },
+ {
+ 0x71, 0xC9, 0x03, 0x6E, 0x18, 0x17, 0x9B, 0x90,
+ 0xB3, 0x7D, 0x39, 0xE9, 0xF0, 0x5E, 0xB8, 0x9C,
+ 0xC5, 0xFC, 0x34, 0x1F, 0xD7, 0xC4, 0x77, 0xD0,
+ 0xD7, 0x49, 0x32, 0x85, 0xFA, 0xCA, 0x08, 0xA4
+ },
+ {
+ 0x59, 0x16, 0x83, 0x3E, 0xBB, 0x05, 0xCD, 0x91,
+ 0x9C, 0xA7, 0xFE, 0x83, 0xB6, 0x92, 0xD3, 0x20,
+ 0x5B, 0xEF, 0x72, 0x39, 0x2B, 0x2C, 0xF6, 0xBB,
+ 0x0A, 0x6D, 0x43, 0xF9, 0x94, 0xF9, 0x5F, 0x11
+ },
+ {
+ 0xF6, 0x3A, 0xAB, 0x3E, 0xC6, 0x41, 0xB3, 0xB0,
+ 0x24, 0x96, 0x4C, 0x2B, 0x43, 0x7C, 0x04, 0xF6,
+ 0x04, 0x3C, 0x4C, 0x7E, 0x02, 0x79, 0x23, 0x99,
+ 0x95, 0x40, 0x19, 0x58, 0xF8, 0x6B, 0xBE, 0x54
+ },
+ {
+ 0xF1, 0x72, 0xB1, 0x80, 0xBF, 0xB0, 0x97, 0x40,
+ 0x49, 0x31, 0x20, 0xB6, 0x32, 0x6C, 0xBD, 0xC5,
+ 0x61, 0xE4, 0x77, 0xDE, 0xF9, 0xBB, 0xCF, 0xD2,
+ 0x8C, 0xC8, 0xC1, 0xC5, 0xE3, 0x37, 0x9A, 0x31
+ },
+ {
+ 0xCB, 0x9B, 0x89, 0xCC, 0x18, 0x38, 0x1D, 0xD9,
+ 0x14, 0x1A, 0xDE, 0x58, 0x86, 0x54, 0xD4, 0xE6,
+ 0xA2, 0x31, 0xD5, 0xBF, 0x49, 0xD4, 0xD5, 0x9A,
+ 0xC2, 0x7D, 0x86, 0x9C, 0xBE, 0x10, 0x0C, 0xF3
+ },
+ {
+ 0x7B, 0xD8, 0x81, 0x50, 0x46, 0xFD, 0xD8, 0x10,
+ 0xA9, 0x23, 0xE1, 0x98, 0x4A, 0xAE, 0xBD, 0xCD,
+ 0xF8, 0x4D, 0x87, 0xC8, 0x99, 0x2D, 0x68, 0xB5,
+ 0xEE, 0xB4, 0x60, 0xF9, 0x3E, 0xB3, 0xC8, 0xD7
+ },
+ {
+ 0x60, 0x7B, 0xE6, 0x68, 0x62, 0xFD, 0x08, 0xEE,
+ 0x5B, 0x19, 0xFA, 0xCA, 0xC0, 0x9D, 0xFD, 0xBC,
+ 0xD4, 0x0C, 0x31, 0x21, 0x01, 0xD6, 0x6E, 0x6E,
+ 0xBD, 0x2B, 0x84, 0x1F, 0x1B, 0x9A, 0x93, 0x25
+ },
+ {
+ 0x9F, 0xE0, 0x3B, 0xBE, 0x69, 0xAB, 0x18, 0x34,
+ 0xF5, 0x21, 0x9B, 0x0D, 0xA8, 0x8A, 0x08, 0xB3,
+ 0x0A, 0x66, 0xC5, 0x91, 0x3F, 0x01, 0x51, 0x96,
+ 0x3C, 0x36, 0x05, 0x60, 0xDB, 0x03, 0x87, 0xB3
+ },
+ {
+ 0x90, 0xA8, 0x35, 0x85, 0x71, 0x7B, 0x75, 0xF0,
+ 0xE9, 0xB7, 0x25, 0xE0, 0x55, 0xEE, 0xEE, 0xB9,
+ 0xE7, 0xA0, 0x28, 0xEA, 0x7E, 0x6C, 0xBC, 0x07,
+ 0xB2, 0x09, 0x17, 0xEC, 0x03, 0x63, 0xE3, 0x8C
+ },
+ {
+ 0x33, 0x6E, 0xA0, 0x53, 0x0F, 0x4A, 0x74, 0x69,
+ 0x12, 0x6E, 0x02, 0x18, 0x58, 0x7E, 0xBB, 0xDE,
+ 0x33, 0x58, 0xA0, 0xB3, 0x1C, 0x29, 0xD2, 0x00,
+ 0xF7, 0xDC, 0x7E, 0xB1, 0x5C, 0x6A, 0xAD, 0xD8
+ },
+ {
+ 0xA7, 0x9E, 0x76, 0xDC, 0x0A, 0xBC, 0xA4, 0x39,
+ 0x6F, 0x07, 0x47, 0xCD, 0x7B, 0x74, 0x8D, 0xF9,
+ 0x13, 0x00, 0x76, 0x26, 0xB1, 0xD6, 0x59, 0xDA,
+ 0x0C, 0x1F, 0x78, 0xB9, 0x30, 0x3D, 0x01, 0xA3
+ },
+ {
+ 0x44, 0xE7, 0x8A, 0x77, 0x37, 0x56, 0xE0, 0x95,
+ 0x15, 0x19, 0x50, 0x4D, 0x70, 0x38, 0xD2, 0x8D,
+ 0x02, 0x13, 0xA3, 0x7E, 0x0C, 0xE3, 0x75, 0x37,
+ 0x17, 0x57, 0xBC, 0x99, 0x63, 0x11, 0xE3, 0xB8
+ },
+ {
+ 0x77, 0xAC, 0x01, 0x2A, 0x3F, 0x75, 0x4D, 0xCF,
+ 0xEA, 0xB5, 0xEB, 0x99, 0x6B, 0xE9, 0xCD, 0x2D,
+ 0x1F, 0x96, 0x11, 0x1B, 0x6E, 0x49, 0xF3, 0x99,
+ 0x4D, 0xF1, 0x81, 0xF2, 0x85, 0x69, 0xD8, 0x25
+ },
+ {
+ 0xCE, 0x5A, 0x10, 0xDB, 0x6F, 0xCC, 0xDA, 0xF1,
+ 0x40, 0xAA, 0xA4, 0xDE, 0xD6, 0x25, 0x0A, 0x9C,
+ 0x06, 0xE9, 0x22, 0x2B, 0xC9, 0xF9, 0xF3, 0x65,
+ 0x8A, 0x4A, 0xFF, 0x93, 0x5F, 0x2B, 0x9F, 0x3A
+ },
+ {
+ 0xEC, 0xC2, 0x03, 0xA7, 0xFE, 0x2B, 0xE4, 0xAB,
+ 0xD5, 0x5B, 0xB5, 0x3E, 0x6E, 0x67, 0x35, 0x72,
+ 0xE0, 0x07, 0x8D, 0xA8, 0xCD, 0x37, 0x5E, 0xF4,
+ 0x30, 0xCC, 0x97, 0xF9, 0xF8, 0x00, 0x83, 0xAF
+ },
+ {
+ 0x14, 0xA5, 0x18, 0x6D, 0xE9, 0xD7, 0xA1, 0x8B,
+ 0x04, 0x12, 0xB8, 0x56, 0x3E, 0x51, 0xCC, 0x54,
+ 0x33, 0x84, 0x0B, 0x4A, 0x12, 0x9A, 0x8F, 0xF9,
+ 0x63, 0xB3, 0x3A, 0x3C, 0x4A, 0xFE, 0x8E, 0xBB
+ },
+ {
+ 0x13, 0xF8, 0xEF, 0x95, 0xCB, 0x86, 0xE6, 0xA6,
+ 0x38, 0x93, 0x1C, 0x8E, 0x10, 0x76, 0x73, 0xEB,
+ 0x76, 0xBA, 0x10, 0xD7, 0xC2, 0xCD, 0x70, 0xB9,
+ 0xD9, 0x92, 0x0B, 0xBE, 0xED, 0x92, 0x94, 0x09
+ },
+ {
+ 0x0B, 0x33, 0x8F, 0x4E, 0xE1, 0x2F, 0x2D, 0xFC,
+ 0xB7, 0x87, 0x13, 0x37, 0x79, 0x41, 0xE0, 0xB0,
+ 0x63, 0x21, 0x52, 0x58, 0x1D, 0x13, 0x32, 0x51,
+ 0x6E, 0x4A, 0x2C, 0xAB, 0x19, 0x42, 0xCC, 0xA4
+ },
+ {
+ 0xEA, 0xAB, 0x0E, 0xC3, 0x7B, 0x3B, 0x8A, 0xB7,
+ 0x96, 0xE9, 0xF5, 0x72, 0x38, 0xDE, 0x14, 0xA2,
+ 0x64, 0xA0, 0x76, 0xF3, 0x88, 0x7D, 0x86, 0xE2,
+ 0x9B, 0xB5, 0x90, 0x6D, 0xB5, 0xA0, 0x0E, 0x02
+ },
+ {
+ 0x23, 0xCB, 0x68, 0xB8, 0xC0, 0xE6, 0xDC, 0x26,
+ 0xDC, 0x27, 0x76, 0x6D, 0xDC, 0x0A, 0x13, 0xA9,
+ 0x94, 0x38, 0xFD, 0x55, 0x61, 0x7A, 0xA4, 0x09,
+ 0x5D, 0x8F, 0x96, 0x97, 0x20, 0xC8, 0x72, 0xDF
+ },
+ {
+ 0x09, 0x1D, 0x8E, 0xE3, 0x0D, 0x6F, 0x29, 0x68,
+ 0xD4, 0x6B, 0x68, 0x7D, 0xD6, 0x52, 0x92, 0x66,
+ 0x57, 0x42, 0xDE, 0x0B, 0xB8, 0x3D, 0xCC, 0x00,
+ 0x04, 0xC7, 0x2C, 0xE1, 0x00, 0x07, 0xA5, 0x49
+ },
+ {
+ 0x7F, 0x50, 0x7A, 0xBC, 0x6D, 0x19, 0xBA, 0x00,
+ 0xC0, 0x65, 0xA8, 0x76, 0xEC, 0x56, 0x57, 0x86,
+ 0x88, 0x82, 0xD1, 0x8A, 0x22, 0x1B, 0xC4, 0x6C,
+ 0x7A, 0x69, 0x12, 0x54, 0x1F, 0x5B, 0xC7, 0xBA
+ },
+ {
+ 0xA0, 0x60, 0x7C, 0x24, 0xE1, 0x4E, 0x8C, 0x22,
+ 0x3D, 0xB0, 0xD7, 0x0B, 0x4D, 0x30, 0xEE, 0x88,
+ 0x01, 0x4D, 0x60, 0x3F, 0x43, 0x7E, 0x9E, 0x02,
+ 0xAA, 0x7D, 0xAF, 0xA3, 0xCD, 0xFB, 0xAD, 0x94
+ },
+ {
+ 0xDD, 0xBF, 0xEA, 0x75, 0xCC, 0x46, 0x78, 0x82,
+ 0xEB, 0x34, 0x83, 0xCE, 0x5E, 0x2E, 0x75, 0x6A,
+ 0x4F, 0x47, 0x01, 0xB7, 0x6B, 0x44, 0x55, 0x19,
+ 0xE8, 0x9F, 0x22, 0xD6, 0x0F, 0xA8, 0x6E, 0x06
+ },
+ {
+ 0x0C, 0x31, 0x1F, 0x38, 0xC3, 0x5A, 0x4F, 0xB9,
+ 0x0D, 0x65, 0x1C, 0x28, 0x9D, 0x48, 0x68, 0x56,
+ 0xCD, 0x14, 0x13, 0xDF, 0x9B, 0x06, 0x77, 0xF5,
+ 0x3E, 0xCE, 0x2C, 0xD9, 0xE4, 0x77, 0xC6, 0x0A
+ },
+ {
+ 0x46, 0xA7, 0x3A, 0x8D, 0xD3, 0xE7, 0x0F, 0x59,
+ 0xD3, 0x94, 0x2C, 0x01, 0xDF, 0x59, 0x9D, 0xEF,
+ 0x78, 0x3C, 0x9D, 0xA8, 0x2F, 0xD8, 0x32, 0x22,
+ 0xCD, 0x66, 0x2B, 0x53, 0xDC, 0xE7, 0xDB, 0xDF
+ },
+ {
+ 0xAD, 0x03, 0x8F, 0xF9, 0xB1, 0x4D, 0xE8, 0x4A,
+ 0x80, 0x1E, 0x4E, 0x62, 0x1C, 0xE5, 0xDF, 0x02,
+ 0x9D, 0xD9, 0x35, 0x20, 0xD0, 0xC2, 0xFA, 0x38,
+ 0xBF, 0xF1, 0x76, 0xA8, 0xB1, 0xD1, 0x69, 0x8C
+ },
+ {
+ 0xAB, 0x70, 0xC5, 0xDF, 0xBD, 0x1E, 0xA8, 0x17,
+ 0xFE, 0xD0, 0xCD, 0x06, 0x72, 0x93, 0xAB, 0xF3,
+ 0x19, 0xE5, 0xD7, 0x90, 0x1C, 0x21, 0x41, 0xD5,
+ 0xD9, 0x9B, 0x23, 0xF0, 0x3A, 0x38, 0xE7, 0x48
+ },
+ {
+ 0x1F, 0xFF, 0xDA, 0x67, 0x93, 0x2B, 0x73, 0xC8,
+ 0xEC, 0xAF, 0x00, 0x9A, 0x34, 0x91, 0xA0, 0x26,
+ 0x95, 0x3B, 0xAB, 0xFE, 0x1F, 0x66, 0x3B, 0x06,
+ 0x97, 0xC3, 0xC4, 0xAE, 0x8B, 0x2E, 0x7D, 0xCB
+ },
+ {
+ 0xB0, 0xD2, 0xCC, 0x19, 0x47, 0x2D, 0xD5, 0x7F,
+ 0x2B, 0x17, 0xEF, 0xC0, 0x3C, 0x8D, 0x58, 0xC2,
+ 0x28, 0x3D, 0xBB, 0x19, 0xDA, 0x57, 0x2F, 0x77,
+ 0x55, 0x85, 0x5A, 0xA9, 0x79, 0x43, 0x17, 0xA0
+ },
+ {
+ 0xA0, 0xD1, 0x9A, 0x6E, 0xE3, 0x39, 0x79, 0xC3,
+ 0x25, 0x51, 0x0E, 0x27, 0x66, 0x22, 0xDF, 0x41,
+ 0xF7, 0x15, 0x83, 0xD0, 0x75, 0x01, 0xB8, 0x70,
+ 0x71, 0x12, 0x9A, 0x0A, 0xD9, 0x47, 0x32, 0xA5
+ },
+ {
+ 0x72, 0x46, 0x42, 0xA7, 0x03, 0x2D, 0x10, 0x62,
+ 0xB8, 0x9E, 0x52, 0xBE, 0xA3, 0x4B, 0x75, 0xDF,
+ 0x7D, 0x8F, 0xE7, 0x72, 0xD9, 0xFE, 0x3C, 0x93,
+ 0xDD, 0xF3, 0xC4, 0x54, 0x5A, 0xB5, 0xA9, 0x9B
+ },
+ {
+ 0xAD, 0xE5, 0xEA, 0xA7, 0xE6, 0x1F, 0x67, 0x2D,
+ 0x58, 0x7E, 0xA0, 0x3D, 0xAE, 0x7D, 0x7B, 0x55,
+ 0x22, 0x9C, 0x01, 0xD0, 0x6B, 0xC0, 0xA5, 0x70,
+ 0x14, 0x36, 0xCB, 0xD1, 0x83, 0x66, 0xA6, 0x26
+ },
+ {
+ 0x01, 0x3B, 0x31, 0xEB, 0xD2, 0x28, 0xFC, 0xDD,
+ 0xA5, 0x1F, 0xAB, 0xB0, 0x3B, 0xB0, 0x2D, 0x60,
+ 0xAC, 0x20, 0xCA, 0x21, 0x5A, 0xAF, 0xA8, 0x3B,
+ 0xDD, 0x85, 0x5E, 0x37, 0x55, 0xA3, 0x5F, 0x0B
+ },
+ {
+ 0x33, 0x2E, 0xD4, 0x0B, 0xB1, 0x0D, 0xDE, 0x3C,
+ 0x95, 0x4A, 0x75, 0xD7, 0xB8, 0x99, 0x9D, 0x4B,
+ 0x26, 0xA1, 0xC0, 0x63, 0xC1, 0xDC, 0x6E, 0x32,
+ 0xC1, 0xD9, 0x1B, 0xAB, 0x7B, 0xBB, 0x7D, 0x16
+ },
+ {
+ 0xC7, 0xA1, 0x97, 0xB3, 0xA0, 0x5B, 0x56, 0x6B,
+ 0xCC, 0x9F, 0xAC, 0xD2, 0x0E, 0x44, 0x1D, 0x6F,
+ 0x6C, 0x28, 0x60, 0xAC, 0x96, 0x51, 0xCD, 0x51,
+ 0xD6, 0xB9, 0xD2, 0xCD, 0xEE, 0xEA, 0x03, 0x90
+ },
+ {
+ 0xBD, 0x9C, 0xF6, 0x4E, 0xA8, 0x95, 0x3C, 0x03,
+ 0x71, 0x08, 0xE6, 0xF6, 0x54, 0x91, 0x4F, 0x39,
+ 0x58, 0xB6, 0x8E, 0x29, 0xC1, 0x67, 0x00, 0xDC,
+ 0x18, 0x4D, 0x94, 0xA2, 0x17, 0x08, 0xFF, 0x60
+ },
+ {
+ 0x88, 0x35, 0xB0, 0xAC, 0x02, 0x11, 0x51, 0xDF,
+ 0x71, 0x64, 0x74, 0xCE, 0x27, 0xCE, 0x4D, 0x3C,
+ 0x15, 0xF0, 0xB2, 0xDA, 0xB4, 0x80, 0x03, 0xCF,
+ 0x3F, 0x3E, 0xFD, 0x09, 0x45, 0x10, 0x6B, 0x9A
+ },
+ {
+ 0x3B, 0xFE, 0xFA, 0x33, 0x01, 0xAA, 0x55, 0xC0,
+ 0x80, 0x19, 0x0C, 0xFF, 0xDA, 0x8E, 0xAE, 0x51,
+ 0xD9, 0xAF, 0x48, 0x8B, 0x4C, 0x1F, 0x24, 0xC3,
+ 0xD9, 0xA7, 0x52, 0x42, 0xFD, 0x8E, 0xA0, 0x1D
+ },
+ {
+ 0x08, 0x28, 0x4D, 0x14, 0x99, 0x3C, 0xD4, 0x7D,
+ 0x53, 0xEB, 0xAE, 0xCF, 0x0D, 0xF0, 0x47, 0x8C,
+ 0xC1, 0x82, 0xC8, 0x9C, 0x00, 0xE1, 0x85, 0x9C,
+ 0x84, 0x85, 0x16, 0x86, 0xDD, 0xF2, 0xC1, 0xB7
+ },
+ {
+ 0x1E, 0xD7, 0xEF, 0x9F, 0x04, 0xC2, 0xAC, 0x8D,
+ 0xB6, 0xA8, 0x64, 0xDB, 0x13, 0x10, 0x87, 0xF2,
+ 0x70, 0x65, 0x09, 0x8E, 0x69, 0xC3, 0xFE, 0x78,
+ 0x71, 0x8D, 0x9B, 0x94, 0x7F, 0x4A, 0x39, 0xD0
+ },
+ {
+ 0xC1, 0x61, 0xF2, 0xDC, 0xD5, 0x7E, 0x9C, 0x14,
+ 0x39, 0xB3, 0x1A, 0x9D, 0xD4, 0x3D, 0x8F, 0x3D,
+ 0x7D, 0xD8, 0xF0, 0xEB, 0x7C, 0xFA, 0xC6, 0xFB,
+ 0x25, 0xA0, 0xF2, 0x8E, 0x30, 0x6F, 0x06, 0x61
+ },
+ {
+ 0xC0, 0x19, 0x69, 0xAD, 0x34, 0xC5, 0x2C, 0xAF,
+ 0x3D, 0xC4, 0xD8, 0x0D, 0x19, 0x73, 0x5C, 0x29,
+ 0x73, 0x1A, 0xC6, 0xE7, 0xA9, 0x20, 0x85, 0xAB,
+ 0x92, 0x50, 0xC4, 0x8D, 0xEA, 0x48, 0xA3, 0xFC
+ },
+ {
+ 0x17, 0x20, 0xB3, 0x65, 0x56, 0x19, 0xD2, 0xA5,
+ 0x2B, 0x35, 0x21, 0xAE, 0x0E, 0x49, 0xE3, 0x45,
+ 0xCB, 0x33, 0x89, 0xEB, 0xD6, 0x20, 0x8A, 0xCA,
+ 0xF9, 0xF1, 0x3F, 0xDA, 0xCC, 0xA8, 0xBE, 0x49
+ },
+ {
+ 0x75, 0x62, 0x88, 0x36, 0x1C, 0x83, 0xE2, 0x4C,
+ 0x61, 0x7C, 0xF9, 0x5C, 0x90, 0x5B, 0x22, 0xD0,
+ 0x17, 0xCD, 0xC8, 0x6F, 0x0B, 0xF1, 0xD6, 0x58,
+ 0xF4, 0x75, 0x6C, 0x73, 0x79, 0x87, 0x3B, 0x7F
+ },
+ {
+ 0xE7, 0xD0, 0xED, 0xA3, 0x45, 0x26, 0x93, 0xB7,
+ 0x52, 0xAB, 0xCD, 0xA1, 0xB5, 0x5E, 0x27, 0x6F,
+ 0x82, 0x69, 0x8F, 0x5F, 0x16, 0x05, 0x40, 0x3E,
+ 0xFF, 0x83, 0x0B, 0xEA, 0x00, 0x71, 0xA3, 0x94
+ },
+ {
+ 0x2C, 0x82, 0xEC, 0xAA, 0x6B, 0x84, 0x80, 0x3E,
+ 0x04, 0x4A, 0xF6, 0x31, 0x18, 0xAF, 0xE5, 0x44,
+ 0x68, 0x7C, 0xB6, 0xE6, 0xC7, 0xDF, 0x49, 0xED,
+ 0x76, 0x2D, 0xFD, 0x7C, 0x86, 0x93, 0xA1, 0xBC
+ },
+ {
+ 0x61, 0x36, 0xCB, 0xF4, 0xB4, 0x41, 0x05, 0x6F,
+ 0xA1, 0xE2, 0x72, 0x24, 0x98, 0x12, 0x5D, 0x6D,
+ 0xED, 0x45, 0xE1, 0x7B, 0x52, 0x14, 0x39, 0x59,
+ 0xC7, 0xF4, 0xD4, 0xE3, 0x95, 0x21, 0x8A, 0xC2
+ },
+ {
+ 0x72, 0x1D, 0x32, 0x45, 0xAA, 0xFE, 0xF2, 0x7F,
+ 0x6A, 0x62, 0x4F, 0x47, 0x95, 0x4B, 0x6C, 0x25,
+ 0x50, 0x79, 0x52, 0x6F, 0xFA, 0x25, 0xE9, 0xFF,
+ 0x77, 0xE5, 0xDC, 0xFF, 0x47, 0x3B, 0x15, 0x97
+ },
+ {
+ 0x9D, 0xD2, 0xFB, 0xD8, 0xCE, 0xF1, 0x6C, 0x35,
+ 0x3C, 0x0A, 0xC2, 0x11, 0x91, 0xD5, 0x09, 0xEB,
+ 0x28, 0xDD, 0x9E, 0x3E, 0x0D, 0x8C, 0xEA, 0x5D,
+ 0x26, 0xCA, 0x83, 0x93, 0x93, 0x85, 0x1C, 0x3A
+ },
+ {
+ 0xB2, 0x39, 0x4C, 0xEA, 0xCD, 0xEB, 0xF2, 0x1B,
+ 0xF9, 0xDF, 0x2C, 0xED, 0x98, 0xE5, 0x8F, 0x1C,
+ 0x3A, 0x4B, 0xBB, 0xFF, 0x66, 0x0D, 0xD9, 0x00,
+ 0xF6, 0x22, 0x02, 0xD6, 0x78, 0x5C, 0xC4, 0x6E
+ },
+ {
+ 0x57, 0x08, 0x9F, 0x22, 0x27, 0x49, 0xAD, 0x78,
+ 0x71, 0x76, 0x5F, 0x06, 0x2B, 0x11, 0x4F, 0x43,
+ 0xBA, 0x20, 0xEC, 0x56, 0x42, 0x2A, 0x8B, 0x1E,
+ 0x3F, 0x87, 0x19, 0x2C, 0x0E, 0xA7, 0x18, 0xC6
+ },
+ {
+ 0xE4, 0x9A, 0x94, 0x59, 0x96, 0x1C, 0xD3, 0x3C,
+ 0xDF, 0x4A, 0xAE, 0x1B, 0x10, 0x78, 0xA5, 0xDE,
+ 0xA7, 0xC0, 0x40, 0xE0, 0xFE, 0xA3, 0x40, 0xC9,
+ 0x3A, 0x72, 0x48, 0x72, 0xFC, 0x4A, 0xF8, 0x06
+ },
+ {
+ 0xED, 0xE6, 0x7F, 0x72, 0x0E, 0xFF, 0xD2, 0xCA,
+ 0x9C, 0x88, 0x99, 0x41, 0x52, 0xD0, 0x20, 0x1D,
+ 0xEE, 0x6B, 0x0A, 0x2D, 0x2C, 0x07, 0x7A, 0xCA,
+ 0x6D, 0xAE, 0x29, 0xF7, 0x3F, 0x8B, 0x63, 0x09
+ },
+ {
+ 0xE0, 0xF4, 0x34, 0xBF, 0x22, 0xE3, 0x08, 0x80,
+ 0x39, 0xC2, 0x1F, 0x71, 0x9F, 0xFC, 0x67, 0xF0,
+ 0xF2, 0xCB, 0x5E, 0x98, 0xA7, 0xA0, 0x19, 0x4C,
+ 0x76, 0xE9, 0x6B, 0xF4, 0xE8, 0xE1, 0x7E, 0x61
+ },
+ {
+ 0x27, 0x7C, 0x04, 0xE2, 0x85, 0x34, 0x84, 0xA4,
+ 0xEB, 0xA9, 0x10, 0xAD, 0x33, 0x6D, 0x01, 0xB4,
+ 0x77, 0xB6, 0x7C, 0xC2, 0x00, 0xC5, 0x9F, 0x3C,
+ 0x8D, 0x77, 0xEE, 0xF8, 0x49, 0x4F, 0x29, 0xCD
+ },
+ {
+ 0x15, 0x6D, 0x57, 0x47, 0xD0, 0xC9, 0x9C, 0x7F,
+ 0x27, 0x09, 0x7D, 0x7B, 0x7E, 0x00, 0x2B, 0x2E,
+ 0x18, 0x5C, 0xB7, 0x2D, 0x8D, 0xD7, 0xEB, 0x42,
+ 0x4A, 0x03, 0x21, 0x52, 0x81, 0x61, 0x21, 0x9F
+ },
+ {
+ 0x20, 0xDD, 0xD1, 0xED, 0x9B, 0x1C, 0xA8, 0x03,
+ 0x94, 0x6D, 0x64, 0xA8, 0x3A, 0xE4, 0x65, 0x9D,
+ 0xA6, 0x7F, 0xBA, 0x7A, 0x1A, 0x3E, 0xDD, 0xB1,
+ 0xE1, 0x03, 0xC0, 0xF5, 0xE0, 0x3E, 0x3A, 0x2C
+ },
+ {
+ 0xF0, 0xAF, 0x60, 0x4D, 0x3D, 0xAB, 0xBF, 0x9A,
+ 0x0F, 0x2A, 0x7D, 0x3D, 0xDA, 0x6B, 0xD3, 0x8B,
+ 0xBA, 0x72, 0xC6, 0xD0, 0x9B, 0xE4, 0x94, 0xFC,
+ 0xEF, 0x71, 0x3F, 0xF1, 0x01, 0x89, 0xB6, 0xE6
+ },
+ {
+ 0x98, 0x02, 0xBB, 0x87, 0xDE, 0xF4, 0xCC, 0x10,
+ 0xC4, 0xA5, 0xFD, 0x49, 0xAA, 0x58, 0xDF, 0xE2,
+ 0xF3, 0xFD, 0xDB, 0x46, 0xB4, 0x70, 0x88, 0x14,
+ 0xEA, 0xD8, 0x1D, 0x23, 0xBA, 0x95, 0x13, 0x9B
+ },
+ {
+ 0x4F, 0x8C, 0xE1, 0xE5, 0x1D, 0x2F, 0xE7, 0xF2,
+ 0x40, 0x43, 0xA9, 0x04, 0xD8, 0x98, 0xEB, 0xFC,
+ 0x91, 0x97, 0x54, 0x18, 0x75, 0x34, 0x13, 0xAA,
+ 0x09, 0x9B, 0x79, 0x5E, 0xCB, 0x35, 0xCE, 0xDB
+ },
+ {
+ 0xBD, 0xDC, 0x65, 0x14, 0xD7, 0xEE, 0x6A, 0xCE,
+ 0x0A, 0x4A, 0xC1, 0xD0, 0xE0, 0x68, 0x11, 0x22,
+ 0x88, 0xCB, 0xCF, 0x56, 0x04, 0x54, 0x64, 0x27,
+ 0x05, 0x63, 0x01, 0x77, 0xCB, 0xA6, 0x08, 0xBD
+ },
+ {
+ 0xD6, 0x35, 0x99, 0x4F, 0x62, 0x91, 0x51, 0x7B,
+ 0x02, 0x81, 0xFF, 0xDD, 0x49, 0x6A, 0xFA, 0x86,
+ 0x27, 0x12, 0xE5, 0xB3, 0xC4, 0xE5, 0x2E, 0x4C,
+ 0xD5, 0xFD, 0xAE, 0x8C, 0x0E, 0x72, 0xFB, 0x08
+ },
+ {
+ 0x87, 0x8D, 0x9C, 0xA6, 0x00, 0xCF, 0x87, 0xE7,
+ 0x69, 0xCC, 0x30, 0x5C, 0x1B, 0x35, 0x25, 0x51,
+ 0x86, 0x61, 0x5A, 0x73, 0xA0, 0xDA, 0x61, 0x3B,
+ 0x5F, 0x1C, 0x98, 0xDB, 0xF8, 0x12, 0x83, 0xEA
+ },
+ {
+ 0xA6, 0x4E, 0xBE, 0x5D, 0xC1, 0x85, 0xDE, 0x9F,
+ 0xDD, 0xE7, 0x60, 0x7B, 0x69, 0x98, 0x70, 0x2E,
+ 0xB2, 0x34, 0x56, 0x18, 0x49, 0x57, 0x30, 0x7D,
+ 0x2F, 0xA7, 0x2E, 0x87, 0xA4, 0x77, 0x02, 0xD6
+ },
+ {
+ 0xCE, 0x50, 0xEA, 0xB7, 0xB5, 0xEB, 0x52, 0xBD,
+ 0xC9, 0xAD, 0x8E, 0x5A, 0x48, 0x0A, 0xB7, 0x80,
+ 0xCA, 0x93, 0x20, 0xE4, 0x43, 0x60, 0xB1, 0xFE,
+ 0x37, 0xE0, 0x3F, 0x2F, 0x7A, 0xD7, 0xDE, 0x01
+ },
+ {
+ 0xEE, 0xDD, 0xB7, 0xC0, 0xDB, 0x6E, 0x30, 0xAB,
+ 0xE6, 0x6D, 0x79, 0xE3, 0x27, 0x51, 0x1E, 0x61,
+ 0xFC, 0xEB, 0xBC, 0x29, 0xF1, 0x59, 0xB4, 0x0A,
+ 0x86, 0xB0, 0x46, 0xEC, 0xF0, 0x51, 0x38, 0x23
+ },
+ {
+ 0x78, 0x7F, 0xC9, 0x34, 0x40, 0xC1, 0xEC, 0x96,
+ 0xB5, 0xAD, 0x01, 0xC1, 0x6C, 0xF7, 0x79, 0x16,
+ 0xA1, 0x40, 0x5F, 0x94, 0x26, 0x35, 0x6E, 0xC9,
+ 0x21, 0xD8, 0xDF, 0xF3, 0xEA, 0x63, 0xB7, 0xE0
+ },
+ {
+ 0x7F, 0x0D, 0x5E, 0xAB, 0x47, 0xEE, 0xFD, 0xA6,
+ 0x96, 0xC0, 0xBF, 0x0F, 0xBF, 0x86, 0xAB, 0x21,
+ 0x6F, 0xCE, 0x46, 0x1E, 0x93, 0x03, 0xAB, 0xA6,
+ 0xAC, 0x37, 0x41, 0x20, 0xE8, 0x90, 0xE8, 0xDF
+ },
+ {
+ 0xB6, 0x80, 0x04, 0xB4, 0x2F, 0x14, 0xAD, 0x02,
+ 0x9F, 0x4C, 0x2E, 0x03, 0xB1, 0xD5, 0xEB, 0x76,
+ 0xD5, 0x71, 0x60, 0xE2, 0x64, 0x76, 0xD2, 0x11,
+ 0x31, 0xBE, 0xF2, 0x0A, 0xDA, 0x7D, 0x27, 0xF4
+ },
+ {
+ 0xB0, 0xC4, 0xEB, 0x18, 0xAE, 0x25, 0x0B, 0x51,
+ 0xA4, 0x13, 0x82, 0xEA, 0xD9, 0x2D, 0x0D, 0xC7,
+ 0x45, 0x5F, 0x93, 0x79, 0xFC, 0x98, 0x84, 0x42,
+ 0x8E, 0x47, 0x70, 0x60, 0x8D, 0xB0, 0xFA, 0xEC
+ },
+ {
+ 0xF9, 0x2B, 0x7A, 0x87, 0x0C, 0x05, 0x9F, 0x4D,
+ 0x46, 0x46, 0x4C, 0x82, 0x4E, 0xC9, 0x63, 0x55,
+ 0x14, 0x0B, 0xDC, 0xE6, 0x81, 0x32, 0x2C, 0xC3,
+ 0xA9, 0x92, 0xFF, 0x10, 0x3E, 0x3F, 0xEA, 0x52
+ },
+ {
+ 0x53, 0x64, 0x31, 0x26, 0x14, 0x81, 0x33, 0x98,
+ 0xCC, 0x52, 0x5D, 0x4C, 0x4E, 0x14, 0x6E, 0xDE,
+ 0xB3, 0x71, 0x26, 0x5F, 0xBA, 0x19, 0x13, 0x3A,
+ 0x2C, 0x3D, 0x21, 0x59, 0x29, 0x8A, 0x17, 0x42
+ },
+ {
+ 0xF6, 0x62, 0x0E, 0x68, 0xD3, 0x7F, 0xB2, 0xAF,
+ 0x50, 0x00, 0xFC, 0x28, 0xE2, 0x3B, 0x83, 0x22,
+ 0x97, 0xEC, 0xD8, 0xBC, 0xE9, 0x9E, 0x8B, 0xE4,
+ 0xD0, 0x4E, 0x85, 0x30, 0x9E, 0x3D, 0x33, 0x74
+ },
+ {
+ 0x53, 0x16, 0xA2, 0x79, 0x69, 0xD7, 0xFE, 0x04,
+ 0xFF, 0x27, 0xB2, 0x83, 0x96, 0x1B, 0xFF, 0xC3,
+ 0xBF, 0x5D, 0xFB, 0x32, 0xFB, 0x6A, 0x89, 0xD1,
+ 0x01, 0xC6, 0xC3, 0xB1, 0x93, 0x7C, 0x28, 0x71
+ },
+ {
+ 0x81, 0xD1, 0x66, 0x4F, 0xDF, 0x3C, 0xB3, 0x3C,
+ 0x24, 0xEE, 0xBA, 0xC0, 0xBD, 0x64, 0x24, 0x4B,
+ 0x77, 0xC4, 0xAB, 0xEA, 0x90, 0xBB, 0xE8, 0xB5,
+ 0xEE, 0x0B, 0x2A, 0xAF, 0xCF, 0x2D, 0x6A, 0x53
+ },
+ {
+ 0x34, 0x57, 0x82, 0xF2, 0x95, 0xB0, 0x88, 0x03,
+ 0x52, 0xE9, 0x24, 0xA0, 0x46, 0x7B, 0x5F, 0xBC,
+ 0x3E, 0x8F, 0x3B, 0xFB, 0xC3, 0xC7, 0xE4, 0x8B,
+ 0x67, 0x09, 0x1F, 0xB5, 0xE8, 0x0A, 0x94, 0x42
+ },
+ {
+ 0x79, 0x41, 0x11, 0xEA, 0x6C, 0xD6, 0x5E, 0x31,
+ 0x1F, 0x74, 0xEE, 0x41, 0xD4, 0x76, 0xCB, 0x63,
+ 0x2C, 0xE1, 0xE4, 0xB0, 0x51, 0xDC, 0x1D, 0x9E,
+ 0x9D, 0x06, 0x1A, 0x19, 0xE1, 0xD0, 0xBB, 0x49
+ },
+ {
+ 0x2A, 0x85, 0xDA, 0xF6, 0x13, 0x88, 0x16, 0xB9,
+ 0x9B, 0xF8, 0xD0, 0x8B, 0xA2, 0x11, 0x4B, 0x7A,
+ 0xB0, 0x79, 0x75, 0xA7, 0x84, 0x20, 0xC1, 0xA3,
+ 0xB0, 0x6A, 0x77, 0x7C, 0x22, 0xDD, 0x8B, 0xCB
+ },
+ {
+ 0x89, 0xB0, 0xD5, 0xF2, 0x89, 0xEC, 0x16, 0x40,
+ 0x1A, 0x06, 0x9A, 0x96, 0x0D, 0x0B, 0x09, 0x3E,
+ 0x62, 0x5D, 0xA3, 0xCF, 0x41, 0xEE, 0x29, 0xB5,
+ 0x9B, 0x93, 0x0C, 0x58, 0x20, 0x14, 0x54, 0x55
+ },
+ {
+ 0xD0, 0xFD, 0xCB, 0x54, 0x39, 0x43, 0xFC, 0x27,
+ 0xD2, 0x08, 0x64, 0xF5, 0x21, 0x81, 0x47, 0x1B,
+ 0x94, 0x2C, 0xC7, 0x7C, 0xA6, 0x75, 0xBC, 0xB3,
+ 0x0D, 0xF3, 0x1D, 0x35, 0x8E, 0xF7, 0xB1, 0xEB
+ },
+ {
+ 0xB1, 0x7E, 0xA8, 0xD7, 0x70, 0x63, 0xC7, 0x09,
+ 0xD4, 0xDC, 0x6B, 0x87, 0x94, 0x13, 0xC3, 0x43,
+ 0xE3, 0x79, 0x0E, 0x9E, 0x62, 0xCA, 0x85, 0xB7,
+ 0x90, 0x0B, 0x08, 0x6F, 0x6B, 0x75, 0xC6, 0x72
+ },
+ {
+ 0xE7, 0x1A, 0x3E, 0x2C, 0x27, 0x4D, 0xB8, 0x42,
+ 0xD9, 0x21, 0x14, 0xF2, 0x17, 0xE2, 0xC0, 0xEA,
+ 0xC8, 0xB4, 0x50, 0x93, 0xFD, 0xFD, 0x9D, 0xF4,
+ 0xCA, 0x71, 0x62, 0x39, 0x48, 0x62, 0xD5, 0x01
+ },
+ {
+ 0xC0, 0x47, 0x67, 0x59, 0xAB, 0x7A, 0xA3, 0x33,
+ 0x23, 0x4F, 0x6B, 0x44, 0xF5, 0xFD, 0x85, 0x83,
+ 0x90, 0xEC, 0x23, 0x69, 0x4C, 0x62, 0x2C, 0xB9,
+ 0x86, 0xE7, 0x69, 0xC7, 0x8E, 0xDD, 0x73, 0x3E
+ },
+ {
+ 0x9A, 0xB8, 0xEA, 0xBB, 0x14, 0x16, 0x43, 0x4D,
+ 0x85, 0x39, 0x13, 0x41, 0xD5, 0x69, 0x93, 0xC5,
+ 0x54, 0x58, 0x16, 0x7D, 0x44, 0x18, 0xB1, 0x9A,
+ 0x0F, 0x2A, 0xD8, 0xB7, 0x9A, 0x83, 0xA7, 0x5B
+ },
+ {
+ 0x79, 0x92, 0xD0, 0xBB, 0xB1, 0x5E, 0x23, 0x82,
+ 0x6F, 0x44, 0x3E, 0x00, 0x50, 0x5D, 0x68, 0xD3,
+ 0xED, 0x73, 0x72, 0x99, 0x5A, 0x5C, 0x3E, 0x49,
+ 0x86, 0x54, 0x10, 0x2F, 0xBC, 0xD0, 0x96, 0x4E
+ },
+ {
+ 0xC0, 0x21, 0xB3, 0x00, 0x85, 0x15, 0x14, 0x35,
+ 0xDF, 0x33, 0xB0, 0x07, 0xCC, 0xEC, 0xC6, 0x9D,
+ 0xF1, 0x26, 0x9F, 0x39, 0xBA, 0x25, 0x09, 0x2B,
+ 0xED, 0x59, 0xD9, 0x32, 0xAC, 0x0F, 0xDC, 0x28
+ },
+ {
+ 0x91, 0xA2, 0x5E, 0xC0, 0xEC, 0x0D, 0x9A, 0x56,
+ 0x7F, 0x89, 0xC4, 0xBF, 0xE1, 0xA6, 0x5A, 0x0E,
+ 0x43, 0x2D, 0x07, 0x06, 0x4B, 0x41, 0x90, 0xE2,
+ 0x7D, 0xFB, 0x81, 0x90, 0x1F, 0xD3, 0x13, 0x9B
+ },
+ {
+ 0x59, 0x50, 0xD3, 0x9A, 0x23, 0xE1, 0x54, 0x5F,
+ 0x30, 0x12, 0x70, 0xAA, 0x1A, 0x12, 0xF2, 0xE6,
+ 0xC4, 0x53, 0x77, 0x6E, 0x4D, 0x63, 0x55, 0xDE,
+ 0x42, 0x5C, 0xC1, 0x53, 0xF9, 0x81, 0x88, 0x67
+ },
+ {
+ 0xD7, 0x9F, 0x14, 0x72, 0x0C, 0x61, 0x0A, 0xF1,
+ 0x79, 0xA3, 0x76, 0x5D, 0x4B, 0x7C, 0x09, 0x68,
+ 0xF9, 0x77, 0x96, 0x2D, 0xBF, 0x65, 0x5B, 0x52,
+ 0x12, 0x72, 0xB6, 0xF1, 0xE1, 0x94, 0x48, 0x8E
+ },
+ {
+ 0xE9, 0x53, 0x1B, 0xFC, 0x8B, 0x02, 0x99, 0x5A,
+ 0xEA, 0xA7, 0x5B, 0xA2, 0x70, 0x31, 0xFA, 0xDB,
+ 0xCB, 0xF4, 0xA0, 0xDA, 0xB8, 0x96, 0x1D, 0x92,
+ 0x96, 0xCD, 0x7E, 0x84, 0xD2, 0x5D, 0x60, 0x06
+ },
+ {
+ 0x34, 0xE9, 0xC2, 0x6A, 0x01, 0xD7, 0xF1, 0x61,
+ 0x81, 0xB4, 0x54, 0xA9, 0xD1, 0x62, 0x3C, 0x23,
+ 0x3C, 0xB9, 0x9D, 0x31, 0xC6, 0x94, 0x65, 0x6E,
+ 0x94, 0x13, 0xAC, 0xA3, 0xE9, 0x18, 0x69, 0x2F
+ },
+ {
+ 0xD9, 0xD7, 0x42, 0x2F, 0x43, 0x7B, 0xD4, 0x39,
+ 0xDD, 0xD4, 0xD8, 0x83, 0xDA, 0xE2, 0xA0, 0x83,
+ 0x50, 0x17, 0x34, 0x14, 0xBE, 0x78, 0x15, 0x51,
+ 0x33, 0xFF, 0xF1, 0x96, 0x4C, 0x3D, 0x79, 0x72
+ },
+ {
+ 0x4A, 0xEE, 0x0C, 0x7A, 0xAF, 0x07, 0x54, 0x14,
+ 0xFF, 0x17, 0x93, 0xEA, 0xD7, 0xEA, 0xCA, 0x60,
+ 0x17, 0x75, 0xC6, 0x15, 0xDB, 0xD6, 0x0B, 0x64,
+ 0x0B, 0x0A, 0x9F, 0x0C, 0xE5, 0x05, 0xD4, 0x35
+ },
+ {
+ 0x6B, 0xFD, 0xD1, 0x54, 0x59, 0xC8, 0x3B, 0x99,
+ 0xF0, 0x96, 0xBF, 0xB4, 0x9E, 0xE8, 0x7B, 0x06,
+ 0x3D, 0x69, 0xC1, 0x97, 0x4C, 0x69, 0x28, 0xAC,
+ 0xFC, 0xFB, 0x40, 0x99, 0xF8, 0xC4, 0xEF, 0x67
+ },
+ {
+ 0x9F, 0xD1, 0xC4, 0x08, 0xFD, 0x75, 0xC3, 0x36,
+ 0x19, 0x3A, 0x2A, 0x14, 0xD9, 0x4F, 0x6A, 0xF5,
+ 0xAD, 0xF0, 0x50, 0xB8, 0x03, 0x87, 0xB4, 0xB0,
+ 0x10, 0xFB, 0x29, 0xF4, 0xCC, 0x72, 0x70, 0x7C
+ },
+ {
+ 0x13, 0xC8, 0x84, 0x80, 0xA5, 0xD0, 0x0D, 0x6C,
+ 0x8C, 0x7A, 0xD2, 0x11, 0x0D, 0x76, 0xA8, 0x2D,
+ 0x9B, 0x70, 0xF4, 0xFA, 0x66, 0x96, 0xD4, 0xE5,
+ 0xDD, 0x42, 0xA0, 0x66, 0xDC, 0xAF, 0x99, 0x20
+ },
+ {
+ 0x82, 0x0E, 0x72, 0x5E, 0xE2, 0x5F, 0xE8, 0xFD,
+ 0x3A, 0x8D, 0x5A, 0xBE, 0x4C, 0x46, 0xC3, 0xBA,
+ 0x88, 0x9D, 0xE6, 0xFA, 0x91, 0x91, 0xAA, 0x22,
+ 0xBA, 0x67, 0xD5, 0x70, 0x54, 0x21, 0x54, 0x2B
+ },
+ {
+ 0x32, 0xD9, 0x3A, 0x0E, 0xB0, 0x2F, 0x42, 0xFB,
+ 0xBC, 0xAF, 0x2B, 0xAD, 0x00, 0x85, 0xB2, 0x82,
+ 0xE4, 0x60, 0x46, 0xA4, 0xDF, 0x7A, 0xD1, 0x06,
+ 0x57, 0xC9, 0xD6, 0x47, 0x63, 0x75, 0xB9, 0x3E
+ },
+ {
+ 0xAD, 0xC5, 0x18, 0x79, 0x05, 0xB1, 0x66, 0x9C,
+ 0xD8, 0xEC, 0x9C, 0x72, 0x1E, 0x19, 0x53, 0x78,
+ 0x6B, 0x9D, 0x89, 0xA9, 0xBA, 0xE3, 0x07, 0x80,
+ 0xF1, 0xE1, 0xEA, 0xB2, 0x4A, 0x00, 0x52, 0x3C
+ },
+ {
+ 0xE9, 0x07, 0x56, 0xFF, 0x7F, 0x9A, 0xD8, 0x10,
+ 0xB2, 0x39, 0xA1, 0x0C, 0xED, 0x2C, 0xF9, 0xB2,
+ 0x28, 0x43, 0x54, 0xC1, 0xF8, 0xC7, 0xE0, 0xAC,
+ 0xCC, 0x24, 0x61, 0xDC, 0x79, 0x6D, 0x6E, 0x89
+ },
+ {
+ 0x12, 0x51, 0xF7, 0x6E, 0x56, 0x97, 0x84, 0x81,
+ 0x87, 0x53, 0x59, 0x80, 0x1D, 0xB5, 0x89, 0xA0,
+ 0xB2, 0x2F, 0x86, 0xD8, 0xD6, 0x34, 0xDC, 0x04,
+ 0x50, 0x6F, 0x32, 0x2E, 0xD7, 0x8F, 0x17, 0xE8
+ },
+ {
+ 0x3A, 0xFA, 0x89, 0x9F, 0xD9, 0x80, 0xE7, 0x3E,
+ 0xCB, 0x7F, 0x4D, 0x8B, 0x8F, 0x29, 0x1D, 0xC9,
+ 0xAF, 0x79, 0x6B, 0xC6, 0x5D, 0x27, 0xF9, 0x74,
+ 0xC6, 0xF1, 0x93, 0xC9, 0x19, 0x1A, 0x09, 0xFD
+ },
+ {
+ 0xAA, 0x30, 0x5B, 0xE2, 0x6E, 0x5D, 0xED, 0xDC,
+ 0x3C, 0x10, 0x10, 0xCB, 0xC2, 0x13, 0xF9, 0x5F,
+ 0x05, 0x1C, 0x78, 0x5C, 0x5B, 0x43, 0x1E, 0x6A,
+ 0x7C, 0xD0, 0x48, 0xF1, 0x61, 0x78, 0x75, 0x28
+ },
+ {
+ 0x8E, 0xA1, 0x88, 0x4F, 0xF3, 0x2E, 0x9D, 0x10,
+ 0xF0, 0x39, 0xB4, 0x07, 0xD0, 0xD4, 0x4E, 0x7E,
+ 0x67, 0x0A, 0xBD, 0x88, 0x4A, 0xEE, 0xE0, 0xFB,
+ 0x75, 0x7A, 0xE9, 0x4E, 0xAA, 0x97, 0x37, 0x3D
+ },
+ {
+ 0xD4, 0x82, 0xB2, 0x15, 0x5D, 0x4D, 0xEC, 0x6B,
+ 0x47, 0x36, 0xA1, 0xF1, 0x61, 0x7B, 0x53, 0xAA,
+ 0xA3, 0x73, 0x10, 0x27, 0x7D, 0x3F, 0xEF, 0x0C,
+ 0x37, 0xAD, 0x41, 0x76, 0x8F, 0xC2, 0x35, 0xB4
+ },
+ {
+ 0x4D, 0x41, 0x39, 0x71, 0x38, 0x7E, 0x7A, 0x88,
+ 0x98, 0xA8, 0xDC, 0x2A, 0x27, 0x50, 0x07, 0x78,
+ 0x53, 0x9E, 0xA2, 0x14, 0xA2, 0xDF, 0xE9, 0xB3,
+ 0xD7, 0xE8, 0xEB, 0xDC, 0xE5, 0xCF, 0x3D, 0xB3
+ },
+ {
+ 0x69, 0x6E, 0x5D, 0x46, 0xE6, 0xC5, 0x7E, 0x87,
+ 0x96, 0xE4, 0x73, 0x5D, 0x08, 0x91, 0x6E, 0x0B,
+ 0x79, 0x29, 0xB3, 0xCF, 0x29, 0x8C, 0x29, 0x6D,
+ 0x22, 0xE9, 0xD3, 0x01, 0x96, 0x53, 0x37, 0x1C
+ },
+ {
+ 0x1F, 0x56, 0x47, 0xC1, 0xD3, 0xB0, 0x88, 0x22,
+ 0x88, 0x85, 0x86, 0x5C, 0x89, 0x40, 0x90, 0x8B,
+ 0xF4, 0x0D, 0x1A, 0x82, 0x72, 0x82, 0x19, 0x73,
+ 0xB1, 0x60, 0x00, 0x8E, 0x7A, 0x3C, 0xE2, 0xEB
+ },
+ {
+ 0xB6, 0xE7, 0x6C, 0x33, 0x0F, 0x02, 0x1A, 0x5B,
+ 0xDA, 0x65, 0x87, 0x50, 0x10, 0xB0, 0xED, 0xF0,
+ 0x91, 0x26, 0xC0, 0xF5, 0x10, 0xEA, 0x84, 0x90,
+ 0x48, 0x19, 0x20, 0x03, 0xAE, 0xF4, 0xC6, 0x1C
+ },
+ {
+ 0x3C, 0xD9, 0x52, 0xA0, 0xBE, 0xAD, 0xA4, 0x1A,
+ 0xBB, 0x42, 0x4C, 0xE4, 0x7F, 0x94, 0xB4, 0x2B,
+ 0xE6, 0x4E, 0x1F, 0xFB, 0x0F, 0xD0, 0x78, 0x22,
+ 0x76, 0x80, 0x79, 0x46, 0xD0, 0xD0, 0xBC, 0x55
+ },
+ {
+ 0x98, 0xD9, 0x26, 0x77, 0x43, 0x9B, 0x41, 0xB7,
+ 0xBB, 0x51, 0x33, 0x12, 0xAF, 0xB9, 0x2B, 0xCC,
+ 0x8E, 0xE9, 0x68, 0xB2, 0xE3, 0xB2, 0x38, 0xCE,
+ 0xCB, 0x9B, 0x0F, 0x34, 0xC9, 0xBB, 0x63, 0xD0
+ },
+ {
+ 0xEC, 0xBC, 0xA2, 0xCF, 0x08, 0xAE, 0x57, 0xD5,
+ 0x17, 0xAD, 0x16, 0x15, 0x8A, 0x32, 0xBF, 0xA7,
+ 0xDC, 0x03, 0x82, 0xEA, 0xED, 0xA1, 0x28, 0xE9,
+ 0x18, 0x86, 0x73, 0x4C, 0x24, 0xA0, 0xB2, 0x9D
+ },
+ {
+ 0x94, 0x2C, 0xC7, 0xC0, 0xB5, 0x2E, 0x2B, 0x16,
+ 0xA4, 0xB8, 0x9F, 0xA4, 0xFC, 0x7E, 0x0B, 0xF6,
+ 0x09, 0xE2, 0x9A, 0x08, 0xC1, 0xA8, 0x54, 0x34,
+ 0x52, 0xB7, 0x7C, 0x7B, 0xFD, 0x11, 0xBB, 0x28
+ },
+ {
+ 0x8A, 0x06, 0x5D, 0x8B, 0x61, 0xA0, 0xDF, 0xFB,
+ 0x17, 0x0D, 0x56, 0x27, 0x73, 0x5A, 0x76, 0xB0,
+ 0xE9, 0x50, 0x60, 0x37, 0x80, 0x8C, 0xBA, 0x16,
+ 0xC3, 0x45, 0x00, 0x7C, 0x9F, 0x79, 0xCF, 0x8F
+ },
+ {
+ 0x1B, 0x9F, 0xA1, 0x97, 0x14, 0x65, 0x9C, 0x78,
+ 0xFF, 0x41, 0x38, 0x71, 0x84, 0x92, 0x15, 0x36,
+ 0x10, 0x29, 0xAC, 0x80, 0x2B, 0x1C, 0xBC, 0xD5,
+ 0x4E, 0x40, 0x8B, 0xD8, 0x72, 0x87, 0xF8, 0x1F
+ },
+ {
+ 0x8D, 0xAB, 0x07, 0x1B, 0xCD, 0x6C, 0x72, 0x92,
+ 0xA9, 0xEF, 0x72, 0x7B, 0x4A, 0xE0, 0xD8, 0x67,
+ 0x13, 0x30, 0x1D, 0xA8, 0x61, 0x8D, 0x9A, 0x48,
+ 0xAD, 0xCE, 0x55, 0xF3, 0x03, 0xA8, 0x69, 0xA1
+ },
+ {
+ 0x82, 0x53, 0xE3, 0xE7, 0xC7, 0xB6, 0x84, 0xB9,
+ 0xCB, 0x2B, 0xEB, 0x01, 0x4C, 0xE3, 0x30, 0xFF,
+ 0x3D, 0x99, 0xD1, 0x7A, 0xBB, 0xDB, 0xAB, 0xE4,
+ 0xF4, 0xD6, 0x74, 0xDE, 0xD5, 0x3F, 0xFC, 0x6B
+ },
+ {
+ 0xF1, 0x95, 0xF3, 0x21, 0xE9, 0xE3, 0xD6, 0xBD,
+ 0x7D, 0x07, 0x45, 0x04, 0xDD, 0x2A, 0xB0, 0xE6,
+ 0x24, 0x1F, 0x92, 0xE7, 0x84, 0xB1, 0xAA, 0x27,
+ 0x1F, 0xF6, 0x48, 0xB1, 0xCA, 0xB6, 0xD7, 0xF6
+ },
+ {
+ 0x27, 0xE4, 0xCC, 0x72, 0x09, 0x0F, 0x24, 0x12,
+ 0x66, 0x47, 0x6A, 0x7C, 0x09, 0x49, 0x5F, 0x2D,
+ 0xB1, 0x53, 0xD5, 0xBC, 0xBD, 0x76, 0x19, 0x03,
+ 0xEF, 0x79, 0x27, 0x5E, 0xC5, 0x6B, 0x2E, 0xD8
+ },
+ {
+ 0x89, 0x9C, 0x24, 0x05, 0x78, 0x8E, 0x25, 0xB9,
+ 0x9A, 0x18, 0x46, 0x35, 0x5E, 0x64, 0x6D, 0x77,
+ 0xCF, 0x40, 0x00, 0x83, 0x41, 0x5F, 0x7D, 0xC5,
+ 0xAF, 0xE6, 0x9D, 0x6E, 0x17, 0xC0, 0x00, 0x23
+ },
+ {
+ 0xA5, 0x9B, 0x78, 0xC4, 0x90, 0x57, 0x44, 0x07,
+ 0x6B, 0xFE, 0xE8, 0x94, 0xDE, 0x70, 0x7D, 0x4F,
+ 0x12, 0x0B, 0x5C, 0x68, 0x93, 0xEA, 0x04, 0x00,
+ 0x29, 0x7D, 0x0B, 0xB8, 0x34, 0x72, 0x76, 0x32
+ },
+ {
+ 0x59, 0xDC, 0x78, 0xB1, 0x05, 0x64, 0x97, 0x07,
+ 0xA2, 0xBB, 0x44, 0x19, 0xC4, 0x8F, 0x00, 0x54,
+ 0x00, 0xD3, 0x97, 0x3D, 0xE3, 0x73, 0x66, 0x10,
+ 0x23, 0x04, 0x35, 0xB1, 0x04, 0x24, 0xB2, 0x4F
+ },
+ {
+ 0xC0, 0x14, 0x9D, 0x1D, 0x7E, 0x7A, 0x63, 0x53,
+ 0xA6, 0xD9, 0x06, 0xEF, 0xE7, 0x28, 0xF2, 0xF3,
+ 0x29, 0xFE, 0x14, 0xA4, 0x14, 0x9A, 0x3E, 0xA7,
+ 0x76, 0x09, 0xBC, 0x42, 0xB9, 0x75, 0xDD, 0xFA
+ },
+ {
+ 0xA3, 0x2F, 0x24, 0x14, 0x74, 0xA6, 0xC1, 0x69,
+ 0x32, 0xE9, 0x24, 0x3B, 0xE0, 0xCF, 0x09, 0xBC,
+ 0xDC, 0x7E, 0x0C, 0xA0, 0xE7, 0xA6, 0xA1, 0xB9,
+ 0xB1, 0xA0, 0xF0, 0x1E, 0x41, 0x50, 0x23, 0x77
+ },
+ {
+ 0xB2, 0x39, 0xB2, 0xE4, 0xF8, 0x18, 0x41, 0x36,
+ 0x1C, 0x13, 0x39, 0xF6, 0x8E, 0x2C, 0x35, 0x9F,
+ 0x92, 0x9A, 0xF9, 0xAD, 0x9F, 0x34, 0xE0, 0x1A,
+ 0xAB, 0x46, 0x31, 0xAD, 0x6D, 0x55, 0x00, 0xB0
+ },
+ {
+ 0x85, 0xFB, 0x41, 0x9C, 0x70, 0x02, 0xA3, 0xE0,
+ 0xB4, 0xB6, 0xEA, 0x09, 0x3B, 0x4C, 0x1A, 0xC6,
+ 0x93, 0x66, 0x45, 0xB6, 0x5D, 0xAC, 0x5A, 0xC1,
+ 0x5A, 0x85, 0x28, 0xB7, 0xB9, 0x4C, 0x17, 0x54
+ },
+ {
+ 0x96, 0x19, 0x72, 0x06, 0x25, 0xF1, 0x90, 0xB9,
+ 0x3A, 0x3F, 0xAD, 0x18, 0x6A, 0xB3, 0x14, 0x18,
+ 0x96, 0x33, 0xC0, 0xD3, 0xA0, 0x1E, 0x6F, 0x9B,
+ 0xC8, 0xC4, 0xA8, 0xF8, 0x2F, 0x38, 0x3D, 0xBF
+ },
+ {
+ 0x7D, 0x62, 0x0D, 0x90, 0xFE, 0x69, 0xFA, 0x46,
+ 0x9A, 0x65, 0x38, 0x38, 0x89, 0x70, 0xA1, 0xAA,
+ 0x09, 0xBB, 0x48, 0xA2, 0xD5, 0x9B, 0x34, 0x7B,
+ 0x97, 0xE8, 0xCE, 0x71, 0xF4, 0x8C, 0x7F, 0x46
+ },
+ {
+ 0x29, 0x43, 0x83, 0x56, 0x85, 0x96, 0xFB, 0x37,
+ 0xC7, 0x5B, 0xBA, 0xCD, 0x97, 0x9C, 0x5F, 0xF6,
+ 0xF2, 0x0A, 0x55, 0x6B, 0xF8, 0x87, 0x9C, 0xC7,
+ 0x29, 0x24, 0x85, 0x5D, 0xF9, 0xB8, 0x24, 0x0E
+ },
+ {
+ 0x16, 0xB1, 0x8A, 0xB3, 0x14, 0x35, 0x9C, 0x2B,
+ 0x83, 0x3C, 0x1C, 0x69, 0x86, 0xD4, 0x8C, 0x55,
+ 0xA9, 0xFC, 0x97, 0xCD, 0xE9, 0xA3, 0xC1, 0xF1,
+ 0x0A, 0x31, 0x77, 0x14, 0x0F, 0x73, 0xF7, 0x38
+ },
+ {
+ 0x8C, 0xBB, 0xDD, 0x14, 0xBC, 0x33, 0xF0, 0x4C,
+ 0xF4, 0x58, 0x13, 0xE4, 0xA1, 0x53, 0xA2, 0x73,
+ 0xD3, 0x6A, 0xDA, 0xD5, 0xCE, 0x71, 0xF4, 0x99,
+ 0xEE, 0xB8, 0x7F, 0xB8, 0xAC, 0x63, 0xB7, 0x29
+ },
+ {
+ 0x69, 0xC9, 0xA4, 0x98, 0xDB, 0x17, 0x4E, 0xCA,
+ 0xEF, 0xCC, 0x5A, 0x3A, 0xC9, 0xFD, 0xED, 0xF0,
+ 0xF8, 0x13, 0xA5, 0xBE, 0xC7, 0x27, 0xF1, 0xE7,
+ 0x75, 0xBA, 0xBD, 0xEC, 0x77, 0x18, 0x81, 0x6E
+ },
+ {
+ 0xB4, 0x62, 0xC3, 0xBE, 0x40, 0x44, 0x8F, 0x1D,
+ 0x4F, 0x80, 0x62, 0x62, 0x54, 0xE5, 0x35, 0xB0,
+ 0x8B, 0xC9, 0xCD, 0xCF, 0xF5, 0x99, 0xA7, 0x68,
+ 0x57, 0x8D, 0x4B, 0x28, 0x81, 0xA8, 0xE3, 0xF0
+ },
+ {
+ 0x55, 0x3E, 0x9D, 0x9C, 0x5F, 0x36, 0x0A, 0xC0,
+ 0xB7, 0x4A, 0x7D, 0x44, 0xE5, 0xA3, 0x91, 0xDA,
+ 0xD4, 0xCE, 0xD0, 0x3E, 0x0C, 0x24, 0x18, 0x3B,
+ 0x7E, 0x8E, 0xCA, 0xBD, 0xF1, 0x71, 0x5A, 0x64
+ },
+ {
+ 0x7A, 0x7C, 0x55, 0xA5, 0x6F, 0xA9, 0xAE, 0x51,
+ 0xE6, 0x55, 0xE0, 0x19, 0x75, 0xD8, 0xA6, 0xFF,
+ 0x4A, 0xE9, 0xE4, 0xB4, 0x86, 0xFC, 0xBE, 0x4E,
+ 0xAC, 0x04, 0x45, 0x88, 0xF2, 0x45, 0xEB, 0xEA
+ },
+ {
+ 0x2A, 0xFD, 0xF3, 0xC8, 0x2A, 0xBC, 0x48, 0x67,
+ 0xF5, 0xDE, 0x11, 0x12, 0x86, 0xC2, 0xB3, 0xBE,
+ 0x7D, 0x6E, 0x48, 0x65, 0x7B, 0xA9, 0x23, 0xCF,
+ 0xBF, 0x10, 0x1A, 0x6D, 0xFC, 0xF9, 0xDB, 0x9A
+ },
+ {
+ 0x41, 0x03, 0x7D, 0x2E, 0xDC, 0xDC, 0xE0, 0xC4,
+ 0x9B, 0x7F, 0xB4, 0xA6, 0xAA, 0x09, 0x99, 0xCA,
+ 0x66, 0x97, 0x6C, 0x74, 0x83, 0xAF, 0xE6, 0x31,
+ 0xD4, 0xED, 0xA2, 0x83, 0x14, 0x4F, 0x6D, 0xFC
+ },
+ {
+ 0xC4, 0x46, 0x6F, 0x84, 0x97, 0xCA, 0x2E, 0xEB,
+ 0x45, 0x83, 0xA0, 0xB0, 0x8E, 0x9D, 0x9A, 0xC7,
+ 0x43, 0x95, 0x70, 0x9F, 0xDA, 0x10, 0x9D, 0x24,
+ 0xF2, 0xE4, 0x46, 0x21, 0x96, 0x77, 0x9C, 0x5D
+ },
+ {
+ 0x75, 0xF6, 0x09, 0x33, 0x8A, 0xA6, 0x7D, 0x96,
+ 0x9A, 0x2A, 0xE2, 0xA2, 0x36, 0x2B, 0x2D, 0xA9,
+ 0xD7, 0x7C, 0x69, 0x5D, 0xFD, 0x1D, 0xF7, 0x22,
+ 0x4A, 0x69, 0x01, 0xDB, 0x93, 0x2C, 0x33, 0x64
+ },
+ {
+ 0x68, 0x60, 0x6C, 0xEB, 0x98, 0x9D, 0x54, 0x88,
+ 0xFC, 0x7C, 0xF6, 0x49, 0xF3, 0xD7, 0xC2, 0x72,
+ 0xEF, 0x05, 0x5D, 0xA1, 0xA9, 0x3F, 0xAE, 0xCD,
+ 0x55, 0xFE, 0x06, 0xF6, 0x96, 0x70, 0x98, 0xCA
+ },
+ {
+ 0x44, 0x34, 0x6B, 0xDE, 0xB7, 0xE0, 0x52, 0xF6,
+ 0x25, 0x50, 0x48, 0xF0, 0xD9, 0xB4, 0x2C, 0x42,
+ 0x5B, 0xAB, 0x9C, 0x3D, 0xD2, 0x41, 0x68, 0x21,
+ 0x2C, 0x3E, 0xCF, 0x1E, 0xBF, 0x34, 0xE6, 0xAE
+ },
+ {
+ 0x8E, 0x9C, 0xF6, 0xE1, 0xF3, 0x66, 0x47, 0x1F,
+ 0x2A, 0xC7, 0xD2, 0xEE, 0x9B, 0x5E, 0x62, 0x66,
+ 0xFD, 0xA7, 0x1F, 0x8F, 0x2E, 0x41, 0x09, 0xF2,
+ 0x23, 0x7E, 0xD5, 0xF8, 0x81, 0x3F, 0xC7, 0x18
+ },
+ {
+ 0x84, 0xBB, 0xEB, 0x84, 0x06, 0xD2, 0x50, 0x95,
+ 0x1F, 0x8C, 0x1B, 0x3E, 0x86, 0xA7, 0xC0, 0x10,
+ 0x08, 0x29, 0x21, 0x83, 0x3D, 0xFD, 0x95, 0x55,
+ 0xA2, 0xF9, 0x09, 0xB1, 0x08, 0x6E, 0xB4, 0xB8
+ },
+ {
+ 0xEE, 0x66, 0x6F, 0x3E, 0xEF, 0x0F, 0x7E, 0x2A,
+ 0x9C, 0x22, 0x29, 0x58, 0xC9, 0x7E, 0xAF, 0x35,
+ 0xF5, 0x1C, 0xED, 0x39, 0x3D, 0x71, 0x44, 0x85,
+ 0xAB, 0x09, 0xA0, 0x69, 0x34, 0x0F, 0xDF, 0x88
+ },
+ {
+ 0xC1, 0x53, 0xD3, 0x4A, 0x65, 0xC4, 0x7B, 0x4A,
+ 0x62, 0xC5, 0xCA, 0xCF, 0x24, 0x01, 0x09, 0x75,
+ 0xD0, 0x35, 0x6B, 0x2F, 0x32, 0xC8, 0xF5, 0xDA,
+ 0x53, 0x0D, 0x33, 0x88, 0x16, 0xAD, 0x5D, 0xE6
+ },
+ {
+ 0x9F, 0xC5, 0x45, 0x01, 0x09, 0xE1, 0xB7, 0x79,
+ 0xF6, 0xC7, 0xAE, 0x79, 0xD5, 0x6C, 0x27, 0x63,
+ 0x5C, 0x8D, 0xD4, 0x26, 0xC5, 0xA9, 0xD5, 0x4E,
+ 0x25, 0x78, 0xDB, 0x98, 0x9B, 0x8C, 0x3B, 0x4E
+ },
+ {
+ 0xD1, 0x2B, 0xF3, 0x73, 0x2E, 0xF4, 0xAF, 0x5C,
+ 0x22, 0xFA, 0x90, 0x35, 0x6A, 0xF8, 0xFC, 0x50,
+ 0xFC, 0xB4, 0x0F, 0x8F, 0x2E, 0xA5, 0xC8, 0x59,
+ 0x47, 0x37, 0xA3, 0xB3, 0xD5, 0xAB, 0xDB, 0xD7
+ },
+ {
+ 0x11, 0x03, 0x0B, 0x92, 0x89, 0xBB, 0xA5, 0xAF,
+ 0x65, 0x26, 0x06, 0x72, 0xAB, 0x6F, 0xEE, 0x88,
+ 0xB8, 0x74, 0x20, 0xAC, 0xEF, 0x4A, 0x17, 0x89,
+ 0xA2, 0x07, 0x3B, 0x7E, 0xC2, 0xF2, 0xA0, 0x9E
+ },
+ {
+ 0x69, 0xCB, 0x19, 0x2B, 0x84, 0x44, 0x00, 0x5C,
+ 0x8C, 0x0C, 0xEB, 0x12, 0xC8, 0x46, 0x86, 0x07,
+ 0x68, 0x18, 0x8C, 0xDA, 0x0A, 0xEC, 0x27, 0xA9,
+ 0xC8, 0xA5, 0x5C, 0xDE, 0xE2, 0x12, 0x36, 0x32
+ },
+ {
+ 0xDB, 0x44, 0x4C, 0x15, 0x59, 0x7B, 0x5F, 0x1A,
+ 0x03, 0xD1, 0xF9, 0xED, 0xD1, 0x6E, 0x4A, 0x9F,
+ 0x43, 0xA6, 0x67, 0xCC, 0x27, 0x51, 0x75, 0xDF,
+ 0xA2, 0xB7, 0x04, 0xE3, 0xBB, 0x1A, 0x9B, 0x83
+ },
+ {
+ 0x3F, 0xB7, 0x35, 0x06, 0x1A, 0xBC, 0x51, 0x9D,
+ 0xFE, 0x97, 0x9E, 0x54, 0xC1, 0xEE, 0x5B, 0xFA,
+ 0xD0, 0xA9, 0xD8, 0x58, 0xB3, 0x31, 0x5B, 0xAD,
+ 0x34, 0xBD, 0xE9, 0x99, 0xEF, 0xD7, 0x24, 0xDD
+ },
+};
+
+static const uint8_t blake2b_keyed_kat[BLAKE2_KAT_LENGTH][BLAKE2B_512_SIZE] =
+{
+ {
+ 0x10, 0xEB, 0xB6, 0x77, 0x00, 0xB1, 0x86, 0x8E,
+ 0xFB, 0x44, 0x17, 0x98, 0x7A, 0xCF, 0x46, 0x90,
+ 0xAE, 0x9D, 0x97, 0x2F, 0xB7, 0xA5, 0x90, 0xC2,
+ 0xF0, 0x28, 0x71, 0x79, 0x9A, 0xAA, 0x47, 0x86,
+ 0xB5, 0xE9, 0x96, 0xE8, 0xF0, 0xF4, 0xEB, 0x98,
+ 0x1F, 0xC2, 0x14, 0xB0, 0x05, 0xF4, 0x2D, 0x2F,
+ 0xF4, 0x23, 0x34, 0x99, 0x39, 0x16, 0x53, 0xDF,
+ 0x7A, 0xEF, 0xCB, 0xC1, 0x3F, 0xC5, 0x15, 0x68
+ },
+ {
+ 0x96, 0x1F, 0x6D, 0xD1, 0xE4, 0xDD, 0x30, 0xF6,
+ 0x39, 0x01, 0x69, 0x0C, 0x51, 0x2E, 0x78, 0xE4,
+ 0xB4, 0x5E, 0x47, 0x42, 0xED, 0x19, 0x7C, 0x3C,
+ 0x5E, 0x45, 0xC5, 0x49, 0xFD, 0x25, 0xF2, 0xE4,
+ 0x18, 0x7B, 0x0B, 0xC9, 0xFE, 0x30, 0x49, 0x2B,
+ 0x16, 0xB0, 0xD0, 0xBC, 0x4E, 0xF9, 0xB0, 0xF3,
+ 0x4C, 0x70, 0x03, 0xFA, 0xC0, 0x9A, 0x5E, 0xF1,
+ 0x53, 0x2E, 0x69, 0x43, 0x02, 0x34, 0xCE, 0xBD
+ },
+ {
+ 0xDA, 0x2C, 0xFB, 0xE2, 0xD8, 0x40, 0x9A, 0x0F,
+ 0x38, 0x02, 0x61, 0x13, 0x88, 0x4F, 0x84, 0xB5,
+ 0x01, 0x56, 0x37, 0x1A, 0xE3, 0x04, 0xC4, 0x43,
+ 0x01, 0x73, 0xD0, 0x8A, 0x99, 0xD9, 0xFB, 0x1B,
+ 0x98, 0x31, 0x64, 0xA3, 0x77, 0x07, 0x06, 0xD5,
+ 0x37, 0xF4, 0x9E, 0x0C, 0x91, 0x6D, 0x9F, 0x32,
+ 0xB9, 0x5C, 0xC3, 0x7A, 0x95, 0xB9, 0x9D, 0x85,
+ 0x74, 0x36, 0xF0, 0x23, 0x2C, 0x88, 0xA9, 0x65
+ },
+ {
+ 0x33, 0xD0, 0x82, 0x5D, 0xDD, 0xF7, 0xAD, 0xA9,
+ 0x9B, 0x0E, 0x7E, 0x30, 0x71, 0x04, 0xAD, 0x07,
+ 0xCA, 0x9C, 0xFD, 0x96, 0x92, 0x21, 0x4F, 0x15,
+ 0x61, 0x35, 0x63, 0x15, 0xE7, 0x84, 0xF3, 0xE5,
+ 0xA1, 0x7E, 0x36, 0x4A, 0xE9, 0xDB, 0xB1, 0x4C,
+ 0xB2, 0x03, 0x6D, 0xF9, 0x32, 0xB7, 0x7F, 0x4B,
+ 0x29, 0x27, 0x61, 0x36, 0x5F, 0xB3, 0x28, 0xDE,
+ 0x7A, 0xFD, 0xC6, 0xD8, 0x99, 0x8F, 0x5F, 0xC1
+ },
+ {
+ 0xBE, 0xAA, 0x5A, 0x3D, 0x08, 0xF3, 0x80, 0x71,
+ 0x43, 0xCF, 0x62, 0x1D, 0x95, 0xCD, 0x69, 0x05,
+ 0x14, 0xD0, 0xB4, 0x9E, 0xFF, 0xF9, 0xC9, 0x1D,
+ 0x24, 0xB5, 0x92, 0x41, 0xEC, 0x0E, 0xEF, 0xA5,
+ 0xF6, 0x01, 0x96, 0xD4, 0x07, 0x04, 0x8B, 0xBA,
+ 0x8D, 0x21, 0x46, 0x82, 0x8E, 0xBC, 0xB0, 0x48,
+ 0x8D, 0x88, 0x42, 0xFD, 0x56, 0xBB, 0x4F, 0x6D,
+ 0xF8, 0xE1, 0x9C, 0x4B, 0x4D, 0xAA, 0xB8, 0xAC
+ },
+ {
+ 0x09, 0x80, 0x84, 0xB5, 0x1F, 0xD1, 0x3D, 0xEA,
+ 0xE5, 0xF4, 0x32, 0x0D, 0xE9, 0x4A, 0x68, 0x8E,
+ 0xE0, 0x7B, 0xAE, 0xA2, 0x80, 0x04, 0x86, 0x68,
+ 0x9A, 0x86, 0x36, 0x11, 0x7B, 0x46, 0xC1, 0xF4,
+ 0xC1, 0xF6, 0xAF, 0x7F, 0x74, 0xAE, 0x7C, 0x85,
+ 0x76, 0x00, 0x45, 0x6A, 0x58, 0xA3, 0xAF, 0x25,
+ 0x1D, 0xC4, 0x72, 0x3A, 0x64, 0xCC, 0x7C, 0x0A,
+ 0x5A, 0xB6, 0xD9, 0xCA, 0xC9, 0x1C, 0x20, 0xBB
+ },
+ {
+ 0x60, 0x44, 0x54, 0x0D, 0x56, 0x08, 0x53, 0xEB,
+ 0x1C, 0x57, 0xDF, 0x00, 0x77, 0xDD, 0x38, 0x10,
+ 0x94, 0x78, 0x1C, 0xDB, 0x90, 0x73, 0xE5, 0xB1,
+ 0xB3, 0xD3, 0xF6, 0xC7, 0x82, 0x9E, 0x12, 0x06,
+ 0x6B, 0xBA, 0xCA, 0x96, 0xD9, 0x89, 0xA6, 0x90,
+ 0xDE, 0x72, 0xCA, 0x31, 0x33, 0xA8, 0x36, 0x52,
+ 0xBA, 0x28, 0x4A, 0x6D, 0x62, 0x94, 0x2B, 0x27,
+ 0x1F, 0xFA, 0x26, 0x20, 0xC9, 0xE7, 0x5B, 0x1F
+ },
+ {
+ 0x7A, 0x8C, 0xFE, 0x9B, 0x90, 0xF7, 0x5F, 0x7E,
+ 0xCB, 0x3A, 0xCC, 0x05, 0x3A, 0xAE, 0xD6, 0x19,
+ 0x31, 0x12, 0xB6, 0xF6, 0xA4, 0xAE, 0xEB, 0x3F,
+ 0x65, 0xD3, 0xDE, 0x54, 0x19, 0x42, 0xDE, 0xB9,
+ 0xE2, 0x22, 0x81, 0x52, 0xA3, 0xC4, 0xBB, 0xBE,
+ 0x72, 0xFC, 0x3B, 0x12, 0x62, 0x95, 0x28, 0xCF,
+ 0xBB, 0x09, 0xFE, 0x63, 0x0F, 0x04, 0x74, 0x33,
+ 0x9F, 0x54, 0xAB, 0xF4, 0x53, 0xE2, 0xED, 0x52
+ },
+ {
+ 0x38, 0x0B, 0xEA, 0xF6, 0xEA, 0x7C, 0xC9, 0x36,
+ 0x5E, 0x27, 0x0E, 0xF0, 0xE6, 0xF3, 0xA6, 0x4F,
+ 0xB9, 0x02, 0xAC, 0xAE, 0x51, 0xDD, 0x55, 0x12,
+ 0xF8, 0x42, 0x59, 0xAD, 0x2C, 0x91, 0xF4, 0xBC,
+ 0x41, 0x08, 0xDB, 0x73, 0x19, 0x2A, 0x5B, 0xBF,
+ 0xB0, 0xCB, 0xCF, 0x71, 0xE4, 0x6C, 0x3E, 0x21,
+ 0xAE, 0xE1, 0xC5, 0xE8, 0x60, 0xDC, 0x96, 0xE8,
+ 0xEB, 0x0B, 0x7B, 0x84, 0x26, 0xE6, 0xAB, 0xE9
+ },
+ {
+ 0x60, 0xFE, 0x3C, 0x45, 0x35, 0xE1, 0xB5, 0x9D,
+ 0x9A, 0x61, 0xEA, 0x85, 0x00, 0xBF, 0xAC, 0x41,
+ 0xA6, 0x9D, 0xFF, 0xB1, 0xCE, 0xAD, 0xD9, 0xAC,
+ 0xA3, 0x23, 0xE9, 0xA6, 0x25, 0xB6, 0x4D, 0xA5,
+ 0x76, 0x3B, 0xAD, 0x72, 0x26, 0xDA, 0x02, 0xB9,
+ 0xC8, 0xC4, 0xF1, 0xA5, 0xDE, 0x14, 0x0A, 0xC5,
+ 0xA6, 0xC1, 0x12, 0x4E, 0x4F, 0x71, 0x8C, 0xE0,
+ 0xB2, 0x8E, 0xA4, 0x73, 0x93, 0xAA, 0x66, 0x37
+ },
+ {
+ 0x4F, 0xE1, 0x81, 0xF5, 0x4A, 0xD6, 0x3A, 0x29,
+ 0x83, 0xFE, 0xAA, 0xF7, 0x7D, 0x1E, 0x72, 0x35,
+ 0xC2, 0xBE, 0xB1, 0x7F, 0xA3, 0x28, 0xB6, 0xD9,
+ 0x50, 0x5B, 0xDA, 0x32, 0x7D, 0xF1, 0x9F, 0xC3,
+ 0x7F, 0x02, 0xC4, 0xB6, 0xF0, 0x36, 0x8C, 0xE2,
+ 0x31, 0x47, 0x31, 0x3A, 0x8E, 0x57, 0x38, 0xB5,
+ 0xFA, 0x2A, 0x95, 0xB2, 0x9D, 0xE1, 0xC7, 0xF8,
+ 0x26, 0x4E, 0xB7, 0x7B, 0x69, 0xF5, 0x85, 0xCD
+ },
+ {
+ 0xF2, 0x28, 0x77, 0x3C, 0xE3, 0xF3, 0xA4, 0x2B,
+ 0x5F, 0x14, 0x4D, 0x63, 0x23, 0x7A, 0x72, 0xD9,
+ 0x96, 0x93, 0xAD, 0xB8, 0x83, 0x7D, 0x0E, 0x11,
+ 0x2A, 0x8A, 0x0F, 0x8F, 0xFF, 0xF2, 0xC3, 0x62,
+ 0x85, 0x7A, 0xC4, 0x9C, 0x11, 0xEC, 0x74, 0x0D,
+ 0x15, 0x00, 0x74, 0x9D, 0xAC, 0x9B, 0x1F, 0x45,
+ 0x48, 0x10, 0x8B, 0xF3, 0x15, 0x57, 0x94, 0xDC,
+ 0xC9, 0xE4, 0x08, 0x28, 0x49, 0xE2, 0xB8, 0x5B
+ },
+ {
+ 0x96, 0x24, 0x52, 0xA8, 0x45, 0x5C, 0xC5, 0x6C,
+ 0x85, 0x11, 0x31, 0x7E, 0x3B, 0x1F, 0x3B, 0x2C,
+ 0x37, 0xDF, 0x75, 0xF5, 0x88, 0xE9, 0x43, 0x25,
+ 0xFD, 0xD7, 0x70, 0x70, 0x35, 0x9C, 0xF6, 0x3A,
+ 0x9A, 0xE6, 0xE9, 0x30, 0x93, 0x6F, 0xDF, 0x8E,
+ 0x1E, 0x08, 0xFF, 0xCA, 0x44, 0x0C, 0xFB, 0x72,
+ 0xC2, 0x8F, 0x06, 0xD8, 0x9A, 0x21, 0x51, 0xD1,
+ 0xC4, 0x6C, 0xD5, 0xB2, 0x68, 0xEF, 0x85, 0x63
+ },
+ {
+ 0x43, 0xD4, 0x4B, 0xFA, 0x18, 0x76, 0x8C, 0x59,
+ 0x89, 0x6B, 0xF7, 0xED, 0x17, 0x65, 0xCB, 0x2D,
+ 0x14, 0xAF, 0x8C, 0x26, 0x02, 0x66, 0x03, 0x90,
+ 0x99, 0xB2, 0x5A, 0x60, 0x3E, 0x4D, 0xDC, 0x50,
+ 0x39, 0xD6, 0xEF, 0x3A, 0x91, 0x84, 0x7D, 0x10,
+ 0x88, 0xD4, 0x01, 0xC0, 0xC7, 0xE8, 0x47, 0x78,
+ 0x1A, 0x8A, 0x59, 0x0D, 0x33, 0xA3, 0xC6, 0xCB,
+ 0x4D, 0xF0, 0xFA, 0xB1, 0xC2, 0xF2, 0x23, 0x55
+ },
+ {
+ 0xDC, 0xFF, 0xA9, 0xD5, 0x8C, 0x2A, 0x4C, 0xA2,
+ 0xCD, 0xBB, 0x0C, 0x7A, 0xA4, 0xC4, 0xC1, 0xD4,
+ 0x51, 0x65, 0x19, 0x00, 0x89, 0xF4, 0xE9, 0x83,
+ 0xBB, 0x1C, 0x2C, 0xAB, 0x4A, 0xAE, 0xFF, 0x1F,
+ 0xA2, 0xB5, 0xEE, 0x51, 0x6F, 0xEC, 0xD7, 0x80,
+ 0x54, 0x02, 0x40, 0xBF, 0x37, 0xE5, 0x6C, 0x8B,
+ 0xCC, 0xA7, 0xFA, 0xB9, 0x80, 0xE1, 0xE6, 0x1C,
+ 0x94, 0x00, 0xD8, 0xA9, 0xA5, 0xB1, 0x4A, 0xC6
+ },
+ {
+ 0x6F, 0xBF, 0x31, 0xB4, 0x5A, 0xB0, 0xC0, 0xB8,
+ 0xDA, 0xD1, 0xC0, 0xF5, 0xF4, 0x06, 0x13, 0x79,
+ 0x91, 0x2D, 0xDE, 0x5A, 0xA9, 0x22, 0x09, 0x9A,
+ 0x03, 0x0B, 0x72, 0x5C, 0x73, 0x34, 0x6C, 0x52,
+ 0x42, 0x91, 0xAD, 0xEF, 0x89, 0xD2, 0xF6, 0xFD,
+ 0x8D, 0xFC, 0xDA, 0x6D, 0x07, 0xDA, 0xD8, 0x11,
+ 0xA9, 0x31, 0x45, 0x36, 0xC2, 0x91, 0x5E, 0xD4,
+ 0x5D, 0xA3, 0x49, 0x47, 0xE8, 0x3D, 0xE3, 0x4E
+ },
+ {
+ 0xA0, 0xC6, 0x5B, 0xDD, 0xDE, 0x8A, 0xDE, 0xF5,
+ 0x72, 0x82, 0xB0, 0x4B, 0x11, 0xE7, 0xBC, 0x8A,
+ 0xAB, 0x10, 0x5B, 0x99, 0x23, 0x1B, 0x75, 0x0C,
+ 0x02, 0x1F, 0x4A, 0x73, 0x5C, 0xB1, 0xBC, 0xFA,
+ 0xB8, 0x75, 0x53, 0xBB, 0xA3, 0xAB, 0xB0, 0xC3,
+ 0xE6, 0x4A, 0x0B, 0x69, 0x55, 0x28, 0x51, 0x85,
+ 0xA0, 0xBD, 0x35, 0xFB, 0x8C, 0xFD, 0xE5, 0x57,
+ 0x32, 0x9B, 0xEB, 0xB1, 0xF6, 0x29, 0xEE, 0x93
+ },
+ {
+ 0xF9, 0x9D, 0x81, 0x55, 0x50, 0x55, 0x8E, 0x81,
+ 0xEC, 0xA2, 0xF9, 0x67, 0x18, 0xAE, 0xD1, 0x0D,
+ 0x86, 0xF3, 0xF1, 0xCF, 0xB6, 0x75, 0xCC, 0xE0,
+ 0x6B, 0x0E, 0xFF, 0x02, 0xF6, 0x17, 0xC5, 0xA4,
+ 0x2C, 0x5A, 0xA7, 0x60, 0x27, 0x0F, 0x26, 0x79,
+ 0xDA, 0x26, 0x77, 0xC5, 0xAE, 0xB9, 0x4F, 0x11,
+ 0x42, 0x27, 0x7F, 0x21, 0xC7, 0xF7, 0x9F, 0x3C,
+ 0x4F, 0x0C, 0xCE, 0x4E, 0xD8, 0xEE, 0x62, 0xB1
+ },
+ {
+ 0x95, 0x39, 0x1D, 0xA8, 0xFC, 0x7B, 0x91, 0x7A,
+ 0x20, 0x44, 0xB3, 0xD6, 0xF5, 0x37, 0x4E, 0x1C,
+ 0xA0, 0x72, 0xB4, 0x14, 0x54, 0xD5, 0x72, 0xC7,
+ 0x35, 0x6C, 0x05, 0xFD, 0x4B, 0xC1, 0xE0, 0xF4,
+ 0x0B, 0x8B, 0xB8, 0xB4, 0xA9, 0xF6, 0xBC, 0xE9,
+ 0xBE, 0x2C, 0x46, 0x23, 0xC3, 0x99, 0xB0, 0xDC,
+ 0xA0, 0xDA, 0xB0, 0x5C, 0xB7, 0x28, 0x1B, 0x71,
+ 0xA2, 0x1B, 0x0E, 0xBC, 0xD9, 0xE5, 0x56, 0x70
+ },
+ {
+ 0x04, 0xB9, 0xCD, 0x3D, 0x20, 0xD2, 0x21, 0xC0,
+ 0x9A, 0xC8, 0x69, 0x13, 0xD3, 0xDC, 0x63, 0x04,
+ 0x19, 0x89, 0xA9, 0xA1, 0xE6, 0x94, 0xF1, 0xE6,
+ 0x39, 0xA3, 0xBA, 0x7E, 0x45, 0x18, 0x40, 0xF7,
+ 0x50, 0xC2, 0xFC, 0x19, 0x1D, 0x56, 0xAD, 0x61,
+ 0xF2, 0xE7, 0x93, 0x6B, 0xC0, 0xAC, 0x8E, 0x09,
+ 0x4B, 0x60, 0xCA, 0xEE, 0xD8, 0x78, 0xC1, 0x87,
+ 0x99, 0x04, 0x54, 0x02, 0xD6, 0x1C, 0xEA, 0xF9
+ },
+ {
+ 0xEC, 0x0E, 0x0E, 0xF7, 0x07, 0xE4, 0xED, 0x6C,
+ 0x0C, 0x66, 0xF9, 0xE0, 0x89, 0xE4, 0x95, 0x4B,
+ 0x05, 0x80, 0x30, 0xD2, 0xDD, 0x86, 0x39, 0x8F,
+ 0xE8, 0x40, 0x59, 0x63, 0x1F, 0x9E, 0xE5, 0x91,
+ 0xD9, 0xD7, 0x73, 0x75, 0x35, 0x51, 0x49, 0x17,
+ 0x8C, 0x0C, 0xF8, 0xF8, 0xE7, 0xC4, 0x9E, 0xD2,
+ 0xA5, 0xE4, 0xF9, 0x54, 0x88, 0xA2, 0x24, 0x70,
+ 0x67, 0xC2, 0x08, 0x51, 0x0F, 0xAD, 0xC4, 0x4C
+ },
+ {
+ 0x9A, 0x37, 0xCC, 0xE2, 0x73, 0xB7, 0x9C, 0x09,
+ 0x91, 0x36, 0x77, 0x51, 0x0E, 0xAF, 0x76, 0x88,
+ 0xE8, 0x9B, 0x33, 0x14, 0xD3, 0x53, 0x2F, 0xD2,
+ 0x76, 0x4C, 0x39, 0xDE, 0x02, 0x2A, 0x29, 0x45,
+ 0xB5, 0x71, 0x0D, 0x13, 0x51, 0x7A, 0xF8, 0xDD,
+ 0xC0, 0x31, 0x66, 0x24, 0xE7, 0x3B, 0xEC, 0x1C,
+ 0xE6, 0x7D, 0xF1, 0x52, 0x28, 0x30, 0x20, 0x36,
+ 0xF3, 0x30, 0xAB, 0x0C, 0xB4, 0xD2, 0x18, 0xDD
+ },
+ {
+ 0x4C, 0xF9, 0xBB, 0x8F, 0xB3, 0xD4, 0xDE, 0x8B,
+ 0x38, 0xB2, 0xF2, 0x62, 0xD3, 0xC4, 0x0F, 0x46,
+ 0xDF, 0xE7, 0x47, 0xE8, 0xFC, 0x0A, 0x41, 0x4C,
+ 0x19, 0x3D, 0x9F, 0xCF, 0x75, 0x31, 0x06, 0xCE,
+ 0x47, 0xA1, 0x8F, 0x17, 0x2F, 0x12, 0xE8, 0xA2,
+ 0xF1, 0xC2, 0x67, 0x26, 0x54, 0x53, 0x58, 0xE5,
+ 0xEE, 0x28, 0xC9, 0xE2, 0x21, 0x3A, 0x87, 0x87,
+ 0xAA, 0xFB, 0xC5, 0x16, 0xD2, 0x34, 0x31, 0x52
+ },
+ {
+ 0x64, 0xE0, 0xC6, 0x3A, 0xF9, 0xC8, 0x08, 0xFD,
+ 0x89, 0x31, 0x37, 0x12, 0x98, 0x67, 0xFD, 0x91,
+ 0x93, 0x9D, 0x53, 0xF2, 0xAF, 0x04, 0xBE, 0x4F,
+ 0xA2, 0x68, 0x00, 0x61, 0x00, 0x06, 0x9B, 0x2D,
+ 0x69, 0xDA, 0xA5, 0xC5, 0xD8, 0xED, 0x7F, 0xDD,
+ 0xCB, 0x2A, 0x70, 0xEE, 0xEC, 0xDF, 0x2B, 0x10,
+ 0x5D, 0xD4, 0x6A, 0x1E, 0x3B, 0x73, 0x11, 0x72,
+ 0x8F, 0x63, 0x9A, 0xB4, 0x89, 0x32, 0x6B, 0xC9
+ },
+ {
+ 0x5E, 0x9C, 0x93, 0x15, 0x8D, 0x65, 0x9B, 0x2D,
+ 0xEF, 0x06, 0xB0, 0xC3, 0xC7, 0x56, 0x50, 0x45,
+ 0x54, 0x26, 0x62, 0xD6, 0xEE, 0xE8, 0xA9, 0x6A,
+ 0x89, 0xB7, 0x8A, 0xDE, 0x09, 0xFE, 0x8B, 0x3D,
+ 0xCC, 0x09, 0x6D, 0x4F, 0xE4, 0x88, 0x15, 0xD8,
+ 0x8D, 0x8F, 0x82, 0x62, 0x01, 0x56, 0x60, 0x2A,
+ 0xF5, 0x41, 0x95, 0x5E, 0x1F, 0x6C, 0xA3, 0x0D,
+ 0xCE, 0x14, 0xE2, 0x54, 0xC3, 0x26, 0xB8, 0x8F
+ },
+ {
+ 0x77, 0x75, 0xDF, 0xF8, 0x89, 0x45, 0x8D, 0xD1,
+ 0x1A, 0xEF, 0x41, 0x72, 0x76, 0x85, 0x3E, 0x21,
+ 0x33, 0x5E, 0xB8, 0x8E, 0x4D, 0xEC, 0x9C, 0xFB,
+ 0x4E, 0x9E, 0xDB, 0x49, 0x82, 0x00, 0x88, 0x55,
+ 0x1A, 0x2C, 0xA6, 0x03, 0x39, 0xF1, 0x20, 0x66,
+ 0x10, 0x11, 0x69, 0xF0, 0xDF, 0xE8, 0x4B, 0x09,
+ 0x8F, 0xDD, 0xB1, 0x48, 0xD9, 0xDA, 0x6B, 0x3D,
+ 0x61, 0x3D, 0xF2, 0x63, 0x88, 0x9A, 0xD6, 0x4B
+ },
+ {
+ 0xF0, 0xD2, 0x80, 0x5A, 0xFB, 0xB9, 0x1F, 0x74,
+ 0x39, 0x51, 0x35, 0x1A, 0x6D, 0x02, 0x4F, 0x93,
+ 0x53, 0xA2, 0x3C, 0x7C, 0xE1, 0xFC, 0x2B, 0x05,
+ 0x1B, 0x3A, 0x8B, 0x96, 0x8C, 0x23, 0x3F, 0x46,
+ 0xF5, 0x0F, 0x80, 0x6E, 0xCB, 0x15, 0x68, 0xFF,
+ 0xAA, 0x0B, 0x60, 0x66, 0x1E, 0x33, 0x4B, 0x21,
+ 0xDD, 0xE0, 0x4F, 0x8F, 0xA1, 0x55, 0xAC, 0x74,
+ 0x0E, 0xEB, 0x42, 0xE2, 0x0B, 0x60, 0xD7, 0x64
+ },
+ {
+ 0x86, 0xA2, 0xAF, 0x31, 0x6E, 0x7D, 0x77, 0x54,
+ 0x20, 0x1B, 0x94, 0x2E, 0x27, 0x53, 0x64, 0xAC,
+ 0x12, 0xEA, 0x89, 0x62, 0xAB, 0x5B, 0xD8, 0xD7,
+ 0xFB, 0x27, 0x6D, 0xC5, 0xFB, 0xFF, 0xC8, 0xF9,
+ 0xA2, 0x8C, 0xAE, 0x4E, 0x48, 0x67, 0xDF, 0x67,
+ 0x80, 0xD9, 0xB7, 0x25, 0x24, 0x16, 0x09, 0x27,
+ 0xC8, 0x55, 0xDA, 0x5B, 0x60, 0x78, 0xE0, 0xB5,
+ 0x54, 0xAA, 0x91, 0xE3, 0x1C, 0xB9, 0xCA, 0x1D
+ },
+ {
+ 0x10, 0xBD, 0xF0, 0xCA, 0xA0, 0x80, 0x27, 0x05,
+ 0xE7, 0x06, 0x36, 0x9B, 0xAF, 0x8A, 0x3F, 0x79,
+ 0xD7, 0x2C, 0x0A, 0x03, 0xA8, 0x06, 0x75, 0xA7,
+ 0xBB, 0xB0, 0x0B, 0xE3, 0xA4, 0x5E, 0x51, 0x64,
+ 0x24, 0xD1, 0xEE, 0x88, 0xEF, 0xB5, 0x6F, 0x6D,
+ 0x57, 0x77, 0x54, 0x5A, 0xE6, 0xE2, 0x77, 0x65,
+ 0xC3, 0xA8, 0xF5, 0xE4, 0x93, 0xFC, 0x30, 0x89,
+ 0x15, 0x63, 0x89, 0x33, 0xA1, 0xDF, 0xEE, 0x55
+ },
+ {
+ 0xB0, 0x17, 0x81, 0x09, 0x2B, 0x17, 0x48, 0x45,
+ 0x9E, 0x2E, 0x4E, 0xC1, 0x78, 0x69, 0x66, 0x27,
+ 0xBF, 0x4E, 0xBA, 0xFE, 0xBB, 0xA7, 0x74, 0xEC,
+ 0xF0, 0x18, 0xB7, 0x9A, 0x68, 0xAE, 0xB8, 0x49,
+ 0x17, 0xBF, 0x0B, 0x84, 0xBB, 0x79, 0xD1, 0x7B,
+ 0x74, 0x31, 0x51, 0x14, 0x4C, 0xD6, 0x6B, 0x7B,
+ 0x33, 0xA4, 0xB9, 0xE5, 0x2C, 0x76, 0xC4, 0xE1,
+ 0x12, 0x05, 0x0F, 0xF5, 0x38, 0x5B, 0x7F, 0x0B
+ },
+ {
+ 0xC6, 0xDB, 0xC6, 0x1D, 0xEC, 0x6E, 0xAE, 0xAC,
+ 0x81, 0xE3, 0xD5, 0xF7, 0x55, 0x20, 0x3C, 0x8E,
+ 0x22, 0x05, 0x51, 0x53, 0x4A, 0x0B, 0x2F, 0xD1,
+ 0x05, 0xA9, 0x18, 0x89, 0x94, 0x5A, 0x63, 0x85,
+ 0x50, 0x20, 0x4F, 0x44, 0x09, 0x3D, 0xD9, 0x98,
+ 0xC0, 0x76, 0x20, 0x5D, 0xFF, 0xAD, 0x70, 0x3A,
+ 0x0E, 0x5C, 0xD3, 0xC7, 0xF4, 0x38, 0xA7, 0xE6,
+ 0x34, 0xCD, 0x59, 0xFE, 0xDE, 0xDB, 0x53, 0x9E
+ },
+ {
+ 0xEB, 0xA5, 0x1A, 0xCF, 0xFB, 0x4C, 0xEA, 0x31,
+ 0xDB, 0x4B, 0x8D, 0x87, 0xE9, 0xBF, 0x7D, 0xD4,
+ 0x8F, 0xE9, 0x7B, 0x02, 0x53, 0xAE, 0x67, 0xAA,
+ 0x58, 0x0F, 0x9A, 0xC4, 0xA9, 0xD9, 0x41, 0xF2,
+ 0xBE, 0xA5, 0x18, 0xEE, 0x28, 0x68, 0x18, 0xCC,
+ 0x9F, 0x63, 0x3F, 0x2A, 0x3B, 0x9F, 0xB6, 0x8E,
+ 0x59, 0x4B, 0x48, 0xCD, 0xD6, 0xD5, 0x15, 0xBF,
+ 0x1D, 0x52, 0xBA, 0x6C, 0x85, 0xA2, 0x03, 0xA7
+ },
+ {
+ 0x86, 0x22, 0x1F, 0x3A, 0xDA, 0x52, 0x03, 0x7B,
+ 0x72, 0x22, 0x4F, 0x10, 0x5D, 0x79, 0x99, 0x23,
+ 0x1C, 0x5E, 0x55, 0x34, 0xD0, 0x3D, 0xA9, 0xD9,
+ 0xC0, 0xA1, 0x2A, 0xCB, 0x68, 0x46, 0x0C, 0xD3,
+ 0x75, 0xDA, 0xF8, 0xE2, 0x43, 0x86, 0x28, 0x6F,
+ 0x96, 0x68, 0xF7, 0x23, 0x26, 0xDB, 0xF9, 0x9B,
+ 0xA0, 0x94, 0x39, 0x24, 0x37, 0xD3, 0x98, 0xE9,
+ 0x5B, 0xB8, 0x16, 0x1D, 0x71, 0x7F, 0x89, 0x91
+ },
+ {
+ 0x55, 0x95, 0xE0, 0x5C, 0x13, 0xA7, 0xEC, 0x4D,
+ 0xC8, 0xF4, 0x1F, 0xB7, 0x0C, 0xB5, 0x0A, 0x71,
+ 0xBC, 0xE1, 0x7C, 0x02, 0x4F, 0xF6, 0xDE, 0x7A,
+ 0xF6, 0x18, 0xD0, 0xCC, 0x4E, 0x9C, 0x32, 0xD9,
+ 0x57, 0x0D, 0x6D, 0x3E, 0xA4, 0x5B, 0x86, 0x52,
+ 0x54, 0x91, 0x03, 0x0C, 0x0D, 0x8F, 0x2B, 0x18,
+ 0x36, 0xD5, 0x77, 0x8C, 0x1C, 0xE7, 0x35, 0xC1,
+ 0x77, 0x07, 0xDF, 0x36, 0x4D, 0x05, 0x43, 0x47
+ },
+ {
+ 0xCE, 0x0F, 0x4F, 0x6A, 0xCA, 0x89, 0x59, 0x0A,
+ 0x37, 0xFE, 0x03, 0x4D, 0xD7, 0x4D, 0xD5, 0xFA,
+ 0x65, 0xEB, 0x1C, 0xBD, 0x0A, 0x41, 0x50, 0x8A,
+ 0xAD, 0xDC, 0x09, 0x35, 0x1A, 0x3C, 0xEA, 0x6D,
+ 0x18, 0xCB, 0x21, 0x89, 0xC5, 0x4B, 0x70, 0x0C,
+ 0x00, 0x9F, 0x4C, 0xBF, 0x05, 0x21, 0xC7, 0xEA,
+ 0x01, 0xBE, 0x61, 0xC5, 0xAE, 0x09, 0xCB, 0x54,
+ 0xF2, 0x7B, 0xC1, 0xB4, 0x4D, 0x65, 0x8C, 0x82
+ },
+ {
+ 0x7E, 0xE8, 0x0B, 0x06, 0xA2, 0x15, 0xA3, 0xBC,
+ 0xA9, 0x70, 0xC7, 0x7C, 0xDA, 0x87, 0x61, 0x82,
+ 0x2B, 0xC1, 0x03, 0xD4, 0x4F, 0xA4, 0xB3, 0x3F,
+ 0x4D, 0x07, 0xDC, 0xB9, 0x97, 0xE3, 0x6D, 0x55,
+ 0x29, 0x8B, 0xCE, 0xAE, 0x12, 0x24, 0x1B, 0x3F,
+ 0xA0, 0x7F, 0xA6, 0x3B, 0xE5, 0x57, 0x60, 0x68,
+ 0xDA, 0x38, 0x7B, 0x8D, 0x58, 0x59, 0xAE, 0xAB,
+ 0x70, 0x13, 0x69, 0x84, 0x8B, 0x17, 0x6D, 0x42
+ },
+ {
+ 0x94, 0x0A, 0x84, 0xB6, 0xA8, 0x4D, 0x10, 0x9A,
+ 0xAB, 0x20, 0x8C, 0x02, 0x4C, 0x6C, 0xE9, 0x64,
+ 0x76, 0x76, 0xBA, 0x0A, 0xAA, 0x11, 0xF8, 0x6D,
+ 0xBB, 0x70, 0x18, 0xF9, 0xFD, 0x22, 0x20, 0xA6,
+ 0xD9, 0x01, 0xA9, 0x02, 0x7F, 0x9A, 0xBC, 0xF9,
+ 0x35, 0x37, 0x27, 0x27, 0xCB, 0xF0, 0x9E, 0xBD,
+ 0x61, 0xA2, 0xA2, 0xEE, 0xB8, 0x76, 0x53, 0xE8,
+ 0xEC, 0xAD, 0x1B, 0xAB, 0x85, 0xDC, 0x83, 0x27
+ },
+ {
+ 0x20, 0x20, 0xB7, 0x82, 0x64, 0xA8, 0x2D, 0x9F,
+ 0x41, 0x51, 0x14, 0x1A, 0xDB, 0xA8, 0xD4, 0x4B,
+ 0xF2, 0x0C, 0x5E, 0xC0, 0x62, 0xEE, 0xE9, 0xB5,
+ 0x95, 0xA1, 0x1F, 0x9E, 0x84, 0x90, 0x1B, 0xF1,
+ 0x48, 0xF2, 0x98, 0xE0, 0xC9, 0xF8, 0x77, 0x7D,
+ 0xCD, 0xBC, 0x7C, 0xC4, 0x67, 0x0A, 0xAC, 0x35,
+ 0x6C, 0xC2, 0xAD, 0x8C, 0xCB, 0x16, 0x29, 0xF1,
+ 0x6F, 0x6A, 0x76, 0xBC, 0xEF, 0xBE, 0xE7, 0x60
+ },
+ {
+ 0xD1, 0xB8, 0x97, 0xB0, 0xE0, 0x75, 0xBA, 0x68,
+ 0xAB, 0x57, 0x2A, 0xDF, 0x9D, 0x9C, 0x43, 0x66,
+ 0x63, 0xE4, 0x3E, 0xB3, 0xD8, 0xE6, 0x2D, 0x92,
+ 0xFC, 0x49, 0xC9, 0xBE, 0x21, 0x4E, 0x6F, 0x27,
+ 0x87, 0x3F, 0xE2, 0x15, 0xA6, 0x51, 0x70, 0xE6,
+ 0xBE, 0xA9, 0x02, 0x40, 0x8A, 0x25, 0xB4, 0x95,
+ 0x06, 0xF4, 0x7B, 0xAB, 0xD0, 0x7C, 0xEC, 0xF7,
+ 0x11, 0x3E, 0xC1, 0x0C, 0x5D, 0xD3, 0x12, 0x52
+ },
+ {
+ 0xB1, 0x4D, 0x0C, 0x62, 0xAB, 0xFA, 0x46, 0x9A,
+ 0x35, 0x71, 0x77, 0xE5, 0x94, 0xC1, 0x0C, 0x19,
+ 0x42, 0x43, 0xED, 0x20, 0x25, 0xAB, 0x8A, 0xA5,
+ 0xAD, 0x2F, 0xA4, 0x1A, 0xD3, 0x18, 0xE0, 0xFF,
+ 0x48, 0xCD, 0x5E, 0x60, 0xBE, 0xC0, 0x7B, 0x13,
+ 0x63, 0x4A, 0x71, 0x1D, 0x23, 0x26, 0xE4, 0x88,
+ 0xA9, 0x85, 0xF3, 0x1E, 0x31, 0x15, 0x33, 0x99,
+ 0xE7, 0x30, 0x88, 0xEF, 0xC8, 0x6A, 0x5C, 0x55
+ },
+ {
+ 0x41, 0x69, 0xC5, 0xCC, 0x80, 0x8D, 0x26, 0x97,
+ 0xDC, 0x2A, 0x82, 0x43, 0x0D, 0xC2, 0x3E, 0x3C,
+ 0xD3, 0x56, 0xDC, 0x70, 0xA9, 0x45, 0x66, 0x81,
+ 0x05, 0x02, 0xB8, 0xD6, 0x55, 0xB3, 0x9A, 0xBF,
+ 0x9E, 0x7F, 0x90, 0x2F, 0xE7, 0x17, 0xE0, 0x38,
+ 0x92, 0x19, 0x85, 0x9E, 0x19, 0x45, 0xDF, 0x1A,
+ 0xF6, 0xAD, 0xA4, 0x2E, 0x4C, 0xCD, 0xA5, 0x5A,
+ 0x19, 0x7B, 0x71, 0x00, 0xA3, 0x0C, 0x30, 0xA1
+ },
+ {
+ 0x25, 0x8A, 0x4E, 0xDB, 0x11, 0x3D, 0x66, 0xC8,
+ 0x39, 0xC8, 0xB1, 0xC9, 0x1F, 0x15, 0xF3, 0x5A,
+ 0xDE, 0x60, 0x9F, 0x11, 0xCD, 0x7F, 0x86, 0x81,
+ 0xA4, 0x04, 0x5B, 0x9F, 0xEF, 0x7B, 0x0B, 0x24,
+ 0xC8, 0x2C, 0xDA, 0x06, 0xA5, 0xF2, 0x06, 0x7B,
+ 0x36, 0x88, 0x25, 0xE3, 0x91, 0x4E, 0x53, 0xD6,
+ 0x94, 0x8E, 0xDE, 0x92, 0xEF, 0xD6, 0xE8, 0x38,
+ 0x7F, 0xA2, 0xE5, 0x37, 0x23, 0x9B, 0x5B, 0xEE
+ },
+ {
+ 0x79, 0xD2, 0xD8, 0x69, 0x6D, 0x30, 0xF3, 0x0F,
+ 0xB3, 0x46, 0x57, 0x76, 0x11, 0x71, 0xA1, 0x1E,
+ 0x6C, 0x3F, 0x1E, 0x64, 0xCB, 0xE7, 0xBE, 0xBE,
+ 0xE1, 0x59, 0xCB, 0x95, 0xBF, 0xAF, 0x81, 0x2B,
+ 0x4F, 0x41, 0x1E, 0x2F, 0x26, 0xD9, 0xC4, 0x21,
+ 0xDC, 0x2C, 0x28, 0x4A, 0x33, 0x42, 0xD8, 0x23,
+ 0xEC, 0x29, 0x38, 0x49, 0xE4, 0x2D, 0x1E, 0x46,
+ 0xB0, 0xA4, 0xAC, 0x1E, 0x3C, 0x86, 0xAB, 0xAA
+ },
+ {
+ 0x8B, 0x94, 0x36, 0x01, 0x0D, 0xC5, 0xDE, 0xE9,
+ 0x92, 0xAE, 0x38, 0xAE, 0xA9, 0x7F, 0x2C, 0xD6,
+ 0x3B, 0x94, 0x6D, 0x94, 0xFE, 0xDD, 0x2E, 0xC9,
+ 0x67, 0x1D, 0xCD, 0xE3, 0xBD, 0x4C, 0xE9, 0x56,
+ 0x4D, 0x55, 0x5C, 0x66, 0xC1, 0x5B, 0xB2, 0xB9,
+ 0x00, 0xDF, 0x72, 0xED, 0xB6, 0xB8, 0x91, 0xEB,
+ 0xCA, 0xDF, 0xEF, 0xF6, 0x3C, 0x9E, 0xA4, 0x03,
+ 0x6A, 0x99, 0x8B, 0xE7, 0x97, 0x39, 0x81, 0xE7
+ },
+ {
+ 0xC8, 0xF6, 0x8E, 0x69, 0x6E, 0xD2, 0x82, 0x42,
+ 0xBF, 0x99, 0x7F, 0x5B, 0x3B, 0x34, 0x95, 0x95,
+ 0x08, 0xE4, 0x2D, 0x61, 0x38, 0x10, 0xF1, 0xE2,
+ 0xA4, 0x35, 0xC9, 0x6E, 0xD2, 0xFF, 0x56, 0x0C,
+ 0x70, 0x22, 0xF3, 0x61, 0xA9, 0x23, 0x4B, 0x98,
+ 0x37, 0xFE, 0xEE, 0x90, 0xBF, 0x47, 0x92, 0x2E,
+ 0xE0, 0xFD, 0x5F, 0x8D, 0xDF, 0x82, 0x37, 0x18,
+ 0xD8, 0x6D, 0x1E, 0x16, 0xC6, 0x09, 0x00, 0x71
+ },
+ {
+ 0xB0, 0x2D, 0x3E, 0xEE, 0x48, 0x60, 0xD5, 0x86,
+ 0x8B, 0x2C, 0x39, 0xCE, 0x39, 0xBF, 0xE8, 0x10,
+ 0x11, 0x29, 0x05, 0x64, 0xDD, 0x67, 0x8C, 0x85,
+ 0xE8, 0x78, 0x3F, 0x29, 0x30, 0x2D, 0xFC, 0x13,
+ 0x99, 0xBA, 0x95, 0xB6, 0xB5, 0x3C, 0xD9, 0xEB,
+ 0xBF, 0x40, 0x0C, 0xCA, 0x1D, 0xB0, 0xAB, 0x67,
+ 0xE1, 0x9A, 0x32, 0x5F, 0x2D, 0x11, 0x58, 0x12,
+ 0xD2, 0x5D, 0x00, 0x97, 0x8A, 0xD1, 0xBC, 0xA4
+ },
+ {
+ 0x76, 0x93, 0xEA, 0x73, 0xAF, 0x3A, 0xC4, 0xDA,
+ 0xD2, 0x1C, 0xA0, 0xD8, 0xDA, 0x85, 0xB3, 0x11,
+ 0x8A, 0x7D, 0x1C, 0x60, 0x24, 0xCF, 0xAF, 0x55,
+ 0x76, 0x99, 0x86, 0x82, 0x17, 0xBC, 0x0C, 0x2F,
+ 0x44, 0xA1, 0x99, 0xBC, 0x6C, 0x0E, 0xDD, 0x51,
+ 0x97, 0x98, 0xBA, 0x05, 0xBD, 0x5B, 0x1B, 0x44,
+ 0x84, 0x34, 0x6A, 0x47, 0xC2, 0xCA, 0xDF, 0x6B,
+ 0xF3, 0x0B, 0x78, 0x5C, 0xC8, 0x8B, 0x2B, 0xAF
+ },
+ {
+ 0xA0, 0xE5, 0xC1, 0xC0, 0x03, 0x1C, 0x02, 0xE4,
+ 0x8B, 0x7F, 0x09, 0xA5, 0xE8, 0x96, 0xEE, 0x9A,
+ 0xEF, 0x2F, 0x17, 0xFC, 0x9E, 0x18, 0xE9, 0x97,
+ 0xD7, 0xF6, 0xCA, 0xC7, 0xAE, 0x31, 0x64, 0x22,
+ 0xC2, 0xB1, 0xE7, 0x79, 0x84, 0xE5, 0xF3, 0xA7,
+ 0x3C, 0xB4, 0x5D, 0xEE, 0xD5, 0xD3, 0xF8, 0x46,
+ 0x00, 0x10, 0x5E, 0x6E, 0xE3, 0x8F, 0x2D, 0x09,
+ 0x0C, 0x7D, 0x04, 0x42, 0xEA, 0x34, 0xC4, 0x6D
+ },
+ {
+ 0x41, 0xDA, 0xA6, 0xAD, 0xCF, 0xDB, 0x69, 0xF1,
+ 0x44, 0x0C, 0x37, 0xB5, 0x96, 0x44, 0x01, 0x65,
+ 0xC1, 0x5A, 0xDA, 0x59, 0x68, 0x13, 0xE2, 0xE2,
+ 0x2F, 0x06, 0x0F, 0xCD, 0x55, 0x1F, 0x24, 0xDE,
+ 0xE8, 0xE0, 0x4B, 0xA6, 0x89, 0x03, 0x87, 0x88,
+ 0x6C, 0xEE, 0xC4, 0xA7, 0xA0, 0xD7, 0xFC, 0x6B,
+ 0x44, 0x50, 0x63, 0x92, 0xEC, 0x38, 0x22, 0xC0,
+ 0xD8, 0xC1, 0xAC, 0xFC, 0x7D, 0x5A, 0xEB, 0xE8
+ },
+ {
+ 0x14, 0xD4, 0xD4, 0x0D, 0x59, 0x84, 0xD8, 0x4C,
+ 0x5C, 0xF7, 0x52, 0x3B, 0x77, 0x98, 0xB2, 0x54,
+ 0xE2, 0x75, 0xA3, 0xA8, 0xCC, 0x0A, 0x1B, 0xD0,
+ 0x6E, 0xBC, 0x0B, 0xEE, 0x72, 0x68, 0x56, 0xAC,
+ 0xC3, 0xCB, 0xF5, 0x16, 0xFF, 0x66, 0x7C, 0xDA,
+ 0x20, 0x58, 0xAD, 0x5C, 0x34, 0x12, 0x25, 0x44,
+ 0x60, 0xA8, 0x2C, 0x92, 0x18, 0x70, 0x41, 0x36,
+ 0x3C, 0xC7, 0x7A, 0x4D, 0xC2, 0x15, 0xE4, 0x87
+ },
+ {
+ 0xD0, 0xE7, 0xA1, 0xE2, 0xB9, 0xA4, 0x47, 0xFE,
+ 0xE8, 0x3E, 0x22, 0x77, 0xE9, 0xFF, 0x80, 0x10,
+ 0xC2, 0xF3, 0x75, 0xAE, 0x12, 0xFA, 0x7A, 0xAA,
+ 0x8C, 0xA5, 0xA6, 0x31, 0x78, 0x68, 0xA2, 0x6A,
+ 0x36, 0x7A, 0x0B, 0x69, 0xFB, 0xC1, 0xCF, 0x32,
+ 0xA5, 0x5D, 0x34, 0xEB, 0x37, 0x06, 0x63, 0x01,
+ 0x6F, 0x3D, 0x21, 0x10, 0x23, 0x0E, 0xBA, 0x75,
+ 0x40, 0x28, 0xA5, 0x6F, 0x54, 0xAC, 0xF5, 0x7C
+ },
+ {
+ 0xE7, 0x71, 0xAA, 0x8D, 0xB5, 0xA3, 0xE0, 0x43,
+ 0xE8, 0x17, 0x8F, 0x39, 0xA0, 0x85, 0x7B, 0xA0,
+ 0x4A, 0x3F, 0x18, 0xE4, 0xAA, 0x05, 0x74, 0x3C,
+ 0xF8, 0xD2, 0x22, 0xB0, 0xB0, 0x95, 0x82, 0x53,
+ 0x50, 0xBA, 0x42, 0x2F, 0x63, 0x38, 0x2A, 0x23,
+ 0xD9, 0x2E, 0x41, 0x49, 0x07, 0x4E, 0x81, 0x6A,
+ 0x36, 0xC1, 0xCD, 0x28, 0x28, 0x4D, 0x14, 0x62,
+ 0x67, 0x94, 0x0B, 0x31, 0xF8, 0x81, 0x8E, 0xA2
+ },
+ {
+ 0xFE, 0xB4, 0xFD, 0x6F, 0x9E, 0x87, 0xA5, 0x6B,
+ 0xEF, 0x39, 0x8B, 0x32, 0x84, 0xD2, 0xBD, 0xA5,
+ 0xB5, 0xB0, 0xE1, 0x66, 0x58, 0x3A, 0x66, 0xB6,
+ 0x1E, 0x53, 0x84, 0x57, 0xFF, 0x05, 0x84, 0x87,
+ 0x2C, 0x21, 0xA3, 0x29, 0x62, 0xB9, 0x92, 0x8F,
+ 0xFA, 0xB5, 0x8D, 0xE4, 0xAF, 0x2E, 0xDD, 0x4E,
+ 0x15, 0xD8, 0xB3, 0x55, 0x70, 0x52, 0x32, 0x07,
+ 0xFF, 0x4E, 0x2A, 0x5A, 0xA7, 0x75, 0x4C, 0xAA
+ },
+ {
+ 0x46, 0x2F, 0x17, 0xBF, 0x00, 0x5F, 0xB1, 0xC1,
+ 0xB9, 0xE6, 0x71, 0x77, 0x9F, 0x66, 0x52, 0x09,
+ 0xEC, 0x28, 0x73, 0xE3, 0xE4, 0x11, 0xF9, 0x8D,
+ 0xAB, 0xF2, 0x40, 0xA1, 0xD5, 0xEC, 0x3F, 0x95,
+ 0xCE, 0x67, 0x96, 0xB6, 0xFC, 0x23, 0xFE, 0x17,
+ 0x19, 0x03, 0xB5, 0x02, 0x02, 0x34, 0x67, 0xDE,
+ 0xC7, 0x27, 0x3F, 0xF7, 0x48, 0x79, 0xB9, 0x29,
+ 0x67, 0xA2, 0xA4, 0x3A, 0x5A, 0x18, 0x3D, 0x33
+ },
+ {
+ 0xD3, 0x33, 0x81, 0x93, 0xB6, 0x45, 0x53, 0xDB,
+ 0xD3, 0x8D, 0x14, 0x4B, 0xEA, 0x71, 0xC5, 0x91,
+ 0x5B, 0xB1, 0x10, 0xE2, 0xD8, 0x81, 0x80, 0xDB,
+ 0xC5, 0xDB, 0x36, 0x4F, 0xD6, 0x17, 0x1D, 0xF3,
+ 0x17, 0xFC, 0x72, 0x68, 0x83, 0x1B, 0x5A, 0xEF,
+ 0x75, 0xE4, 0x34, 0x2B, 0x2F, 0xAD, 0x87, 0x97,
+ 0xBA, 0x39, 0xED, 0xDC, 0xEF, 0x80, 0xE6, 0xEC,
+ 0x08, 0x15, 0x93, 0x50, 0xB1, 0xAD, 0x69, 0x6D
+ },
+ {
+ 0xE1, 0x59, 0x0D, 0x58, 0x5A, 0x3D, 0x39, 0xF7,
+ 0xCB, 0x59, 0x9A, 0xBD, 0x47, 0x90, 0x70, 0x96,
+ 0x64, 0x09, 0xA6, 0x84, 0x6D, 0x43, 0x77, 0xAC,
+ 0xF4, 0x47, 0x1D, 0x06, 0x5D, 0x5D, 0xB9, 0x41,
+ 0x29, 0xCC, 0x9B, 0xE9, 0x25, 0x73, 0xB0, 0x5E,
+ 0xD2, 0x26, 0xBE, 0x1E, 0x9B, 0x7C, 0xB0, 0xCA,
+ 0xBE, 0x87, 0x91, 0x85, 0x89, 0xF8, 0x0D, 0xAD,
+ 0xD4, 0xEF, 0x5E, 0xF2, 0x5A, 0x93, 0xD2, 0x8E
+ },
+ {
+ 0xF8, 0xF3, 0x72, 0x6A, 0xC5, 0xA2, 0x6C, 0xC8,
+ 0x01, 0x32, 0x49, 0x3A, 0x6F, 0xED, 0xCB, 0x0E,
+ 0x60, 0x76, 0x0C, 0x09, 0xCF, 0xC8, 0x4C, 0xAD,
+ 0x17, 0x81, 0x75, 0x98, 0x68, 0x19, 0x66, 0x5E,
+ 0x76, 0x84, 0x2D, 0x7B, 0x9F, 0xED, 0xF7, 0x6D,
+ 0xDD, 0xEB, 0xF5, 0xD3, 0xF5, 0x6F, 0xAA, 0xAD,
+ 0x44, 0x77, 0x58, 0x7A, 0xF2, 0x16, 0x06, 0xD3,
+ 0x96, 0xAE, 0x57, 0x0D, 0x8E, 0x71, 0x9A, 0xF2
+ },
+ {
+ 0x30, 0x18, 0x60, 0x55, 0xC0, 0x79, 0x49, 0x94,
+ 0x81, 0x83, 0xC8, 0x50, 0xE9, 0xA7, 0x56, 0xCC,
+ 0x09, 0x93, 0x7E, 0x24, 0x7D, 0x9D, 0x92, 0x8E,
+ 0x86, 0x9E, 0x20, 0xBA, 0xFC, 0x3C, 0xD9, 0x72,
+ 0x17, 0x19, 0xD3, 0x4E, 0x04, 0xA0, 0x89, 0x9B,
+ 0x92, 0xC7, 0x36, 0x08, 0x45, 0x50, 0x18, 0x68,
+ 0x86, 0xEF, 0xBA, 0x2E, 0x79, 0x0D, 0x8B, 0xE6,
+ 0xEB, 0xF0, 0x40, 0xB2, 0x09, 0xC4, 0x39, 0xA4
+ },
+ {
+ 0xF3, 0xC4, 0x27, 0x6C, 0xB8, 0x63, 0x63, 0x77,
+ 0x12, 0xC2, 0x41, 0xC4, 0x44, 0xC5, 0xCC, 0x1E,
+ 0x35, 0x54, 0xE0, 0xFD, 0xDB, 0x17, 0x4D, 0x03,
+ 0x58, 0x19, 0xDD, 0x83, 0xEB, 0x70, 0x0B, 0x4C,
+ 0xE8, 0x8D, 0xF3, 0xAB, 0x38, 0x41, 0xBA, 0x02,
+ 0x08, 0x5E, 0x1A, 0x99, 0xB4, 0xE1, 0x73, 0x10,
+ 0xC5, 0x34, 0x10, 0x75, 0xC0, 0x45, 0x8B, 0xA3,
+ 0x76, 0xC9, 0x5A, 0x68, 0x18, 0xFB, 0xB3, 0xE2
+ },
+ {
+ 0x0A, 0xA0, 0x07, 0xC4, 0xDD, 0x9D, 0x58, 0x32,
+ 0x39, 0x30, 0x40, 0xA1, 0x58, 0x3C, 0x93, 0x0B,
+ 0xCA, 0x7D, 0xC5, 0xE7, 0x7E, 0xA5, 0x3A, 0xDD,
+ 0x7E, 0x2B, 0x3F, 0x7C, 0x8E, 0x23, 0x13, 0x68,
+ 0x04, 0x35, 0x20, 0xD4, 0xA3, 0xEF, 0x53, 0xC9,
+ 0x69, 0xB6, 0xBB, 0xFD, 0x02, 0x59, 0x46, 0xF6,
+ 0x32, 0xBD, 0x7F, 0x76, 0x5D, 0x53, 0xC2, 0x10,
+ 0x03, 0xB8, 0xF9, 0x83, 0xF7, 0x5E, 0x2A, 0x6A
+ },
+ {
+ 0x08, 0xE9, 0x46, 0x47, 0x20, 0x53, 0x3B, 0x23,
+ 0xA0, 0x4E, 0xC2, 0x4F, 0x7A, 0xE8, 0xC1, 0x03,
+ 0x14, 0x5F, 0x76, 0x53, 0x87, 0xD7, 0x38, 0x77,
+ 0x7D, 0x3D, 0x34, 0x34, 0x77, 0xFD, 0x1C, 0x58,
+ 0xDB, 0x05, 0x21, 0x42, 0xCA, 0xB7, 0x54, 0xEA,
+ 0x67, 0x43, 0x78, 0xE1, 0x87, 0x66, 0xC5, 0x35,
+ 0x42, 0xF7, 0x19, 0x70, 0x17, 0x1C, 0xC4, 0xF8,
+ 0x16, 0x94, 0x24, 0x6B, 0x71, 0x7D, 0x75, 0x64
+ },
+ {
+ 0xD3, 0x7F, 0xF7, 0xAD, 0x29, 0x79, 0x93, 0xE7,
+ 0xEC, 0x21, 0xE0, 0xF1, 0xB4, 0xB5, 0xAE, 0x71,
+ 0x9C, 0xDC, 0x83, 0xC5, 0xDB, 0x68, 0x75, 0x27,
+ 0xF2, 0x75, 0x16, 0xCB, 0xFF, 0xA8, 0x22, 0x88,
+ 0x8A, 0x68, 0x10, 0xEE, 0x5C, 0x1C, 0xA7, 0xBF,
+ 0xE3, 0x32, 0x11, 0x19, 0xBE, 0x1A, 0xB7, 0xBF,
+ 0xA0, 0xA5, 0x02, 0x67, 0x1C, 0x83, 0x29, 0x49,
+ 0x4D, 0xF7, 0xAD, 0x6F, 0x52, 0x2D, 0x44, 0x0F
+ },
+ {
+ 0xDD, 0x90, 0x42, 0xF6, 0xE4, 0x64, 0xDC, 0xF8,
+ 0x6B, 0x12, 0x62, 0xF6, 0xAC, 0xCF, 0xAF, 0xBD,
+ 0x8C, 0xFD, 0x90, 0x2E, 0xD3, 0xED, 0x89, 0xAB,
+ 0xF7, 0x8F, 0xFA, 0x48, 0x2D, 0xBD, 0xEE, 0xB6,
+ 0x96, 0x98, 0x42, 0x39, 0x4C, 0x9A, 0x11, 0x68,
+ 0xAE, 0x3D, 0x48, 0x1A, 0x01, 0x78, 0x42, 0xF6,
+ 0x60, 0x00, 0x2D, 0x42, 0x44, 0x7C, 0x6B, 0x22,
+ 0xF7, 0xB7, 0x2F, 0x21, 0xAA, 0xE0, 0x21, 0xC9
+ },
+ {
+ 0xBD, 0x96, 0x5B, 0xF3, 0x1E, 0x87, 0xD7, 0x03,
+ 0x27, 0x53, 0x6F, 0x2A, 0x34, 0x1C, 0xEB, 0xC4,
+ 0x76, 0x8E, 0xCA, 0x27, 0x5F, 0xA0, 0x5E, 0xF9,
+ 0x8F, 0x7F, 0x1B, 0x71, 0xA0, 0x35, 0x12, 0x98,
+ 0xDE, 0x00, 0x6F, 0xBA, 0x73, 0xFE, 0x67, 0x33,
+ 0xED, 0x01, 0xD7, 0x58, 0x01, 0xB4, 0xA9, 0x28,
+ 0xE5, 0x42, 0x31, 0xB3, 0x8E, 0x38, 0xC5, 0x62,
+ 0xB2, 0xE3, 0x3E, 0xA1, 0x28, 0x49, 0x92, 0xFA
+ },
+ {
+ 0x65, 0x67, 0x6D, 0x80, 0x06, 0x17, 0x97, 0x2F,
+ 0xBD, 0x87, 0xE4, 0xB9, 0x51, 0x4E, 0x1C, 0x67,
+ 0x40, 0x2B, 0x7A, 0x33, 0x10, 0x96, 0xD3, 0xBF,
+ 0xAC, 0x22, 0xF1, 0xAB, 0xB9, 0x53, 0x74, 0xAB,
+ 0xC9, 0x42, 0xF1, 0x6E, 0x9A, 0xB0, 0xEA, 0xD3,
+ 0x3B, 0x87, 0xC9, 0x19, 0x68, 0xA6, 0xE5, 0x09,
+ 0xE1, 0x19, 0xFF, 0x07, 0x78, 0x7B, 0x3E, 0xF4,
+ 0x83, 0xE1, 0xDC, 0xDC, 0xCF, 0x6E, 0x30, 0x22
+ },
+ {
+ 0x93, 0x9F, 0xA1, 0x89, 0x69, 0x9C, 0x5D, 0x2C,
+ 0x81, 0xDD, 0xD1, 0xFF, 0xC1, 0xFA, 0x20, 0x7C,
+ 0x97, 0x0B, 0x6A, 0x36, 0x85, 0xBB, 0x29, 0xCE,
+ 0x1D, 0x3E, 0x99, 0xD4, 0x2F, 0x2F, 0x74, 0x42,
+ 0xDA, 0x53, 0xE9, 0x5A, 0x72, 0x90, 0x73, 0x14,
+ 0xF4, 0x58, 0x83, 0x99, 0xA3, 0xFF, 0x5B, 0x0A,
+ 0x92, 0xBE, 0xB3, 0xF6, 0xBE, 0x26, 0x94, 0xF9,
+ 0xF8, 0x6E, 0xCF, 0x29, 0x52, 0xD5, 0xB4, 0x1C
+ },
+ {
+ 0xC5, 0x16, 0x54, 0x17, 0x01, 0x86, 0x3F, 0x91,
+ 0x00, 0x5F, 0x31, 0x41, 0x08, 0xCE, 0xEC, 0xE3,
+ 0xC6, 0x43, 0xE0, 0x4F, 0xC8, 0xC4, 0x2F, 0xD2,
+ 0xFF, 0x55, 0x62, 0x20, 0xE6, 0x16, 0xAA, 0xA6,
+ 0xA4, 0x8A, 0xEB, 0x97, 0xA8, 0x4B, 0xAD, 0x74,
+ 0x78, 0x2E, 0x8D, 0xFF, 0x96, 0xA1, 0xA2, 0xFA,
+ 0x94, 0x93, 0x39, 0xD7, 0x22, 0xED, 0xCA, 0xA3,
+ 0x2B, 0x57, 0x06, 0x70, 0x41, 0xDF, 0x88, 0xCC
+ },
+ {
+ 0x98, 0x7F, 0xD6, 0xE0, 0xD6, 0x85, 0x7C, 0x55,
+ 0x3E, 0xAE, 0xBB, 0x3D, 0x34, 0x97, 0x0A, 0x2C,
+ 0x2F, 0x6E, 0x89, 0xA3, 0x54, 0x8F, 0x49, 0x25,
+ 0x21, 0x72, 0x2B, 0x80, 0xA1, 0xC2, 0x1A, 0x15,
+ 0x38, 0x92, 0x34, 0x6D, 0x2C, 0xBA, 0x64, 0x44,
+ 0x21, 0x2D, 0x56, 0xDA, 0x9A, 0x26, 0xE3, 0x24,
+ 0xDC, 0xCB, 0xC0, 0xDC, 0xDE, 0x85, 0xD4, 0xD2,
+ 0xEE, 0x43, 0x99, 0xEE, 0xC5, 0xA6, 0x4E, 0x8F
+ },
+ {
+ 0xAE, 0x56, 0xDE, 0xB1, 0xC2, 0x32, 0x8D, 0x9C,
+ 0x40, 0x17, 0x70, 0x6B, 0xCE, 0x6E, 0x99, 0xD4,
+ 0x13, 0x49, 0x05, 0x3B, 0xA9, 0xD3, 0x36, 0xD6,
+ 0x77, 0xC4, 0xC2, 0x7D, 0x9F, 0xD5, 0x0A, 0xE6,
+ 0xAE, 0xE1, 0x7E, 0x85, 0x31, 0x54, 0xE1, 0xF4,
+ 0xFE, 0x76, 0x72, 0x34, 0x6D, 0xA2, 0xEA, 0xA3,
+ 0x1E, 0xEA, 0x53, 0xFC, 0xF2, 0x4A, 0x22, 0x80,
+ 0x4F, 0x11, 0xD0, 0x3D, 0xA6, 0xAB, 0xFC, 0x2B
+ },
+ {
+ 0x49, 0xD6, 0xA6, 0x08, 0xC9, 0xBD, 0xE4, 0x49,
+ 0x18, 0x70, 0x49, 0x85, 0x72, 0xAC, 0x31, 0xAA,
+ 0xC3, 0xFA, 0x40, 0x93, 0x8B, 0x38, 0xA7, 0x81,
+ 0x8F, 0x72, 0x38, 0x3E, 0xB0, 0x40, 0xAD, 0x39,
+ 0x53, 0x2B, 0xC0, 0x65, 0x71, 0xE1, 0x3D, 0x76,
+ 0x7E, 0x69, 0x45, 0xAB, 0x77, 0xC0, 0xBD, 0xC3,
+ 0xB0, 0x28, 0x42, 0x53, 0x34, 0x3F, 0x9F, 0x6C,
+ 0x12, 0x44, 0xEB, 0xF2, 0xFF, 0x0D, 0xF8, 0x66
+ },
+ {
+ 0xDA, 0x58, 0x2A, 0xD8, 0xC5, 0x37, 0x0B, 0x44,
+ 0x69, 0xAF, 0x86, 0x2A, 0xA6, 0x46, 0x7A, 0x22,
+ 0x93, 0xB2, 0xB2, 0x8B, 0xD8, 0x0A, 0xE0, 0xE9,
+ 0x1F, 0x42, 0x5A, 0xD3, 0xD4, 0x72, 0x49, 0xFD,
+ 0xF9, 0x88, 0x25, 0xCC, 0x86, 0xF1, 0x40, 0x28,
+ 0xC3, 0x30, 0x8C, 0x98, 0x04, 0xC7, 0x8B, 0xFE,
+ 0xEE, 0xEE, 0x46, 0x14, 0x44, 0xCE, 0x24, 0x36,
+ 0x87, 0xE1, 0xA5, 0x05, 0x22, 0x45, 0x6A, 0x1D
+ },
+ {
+ 0xD5, 0x26, 0x6A, 0xA3, 0x33, 0x11, 0x94, 0xAE,
+ 0xF8, 0x52, 0xEE, 0xD8, 0x6D, 0x7B, 0x5B, 0x26,
+ 0x33, 0xA0, 0xAF, 0x1C, 0x73, 0x59, 0x06, 0xF2,
+ 0xE1, 0x32, 0x79, 0xF1, 0x49, 0x31, 0xA9, 0xFC,
+ 0x3B, 0x0E, 0xAC, 0x5C, 0xE9, 0x24, 0x52, 0x73,
+ 0xBD, 0x1A, 0xA9, 0x29, 0x05, 0xAB, 0xE1, 0x62,
+ 0x78, 0xEF, 0x7E, 0xFD, 0x47, 0x69, 0x47, 0x89,
+ 0xA7, 0x28, 0x3B, 0x77, 0xDA, 0x3C, 0x70, 0xF8
+ },
+ {
+ 0x29, 0x62, 0x73, 0x4C, 0x28, 0x25, 0x21, 0x86,
+ 0xA9, 0xA1, 0x11, 0x1C, 0x73, 0x2A, 0xD4, 0xDE,
+ 0x45, 0x06, 0xD4, 0xB4, 0x48, 0x09, 0x16, 0x30,
+ 0x3E, 0xB7, 0x99, 0x1D, 0x65, 0x9C, 0xCD, 0xA0,
+ 0x7A, 0x99, 0x11, 0x91, 0x4B, 0xC7, 0x5C, 0x41,
+ 0x8A, 0xB7, 0xA4, 0x54, 0x17, 0x57, 0xAD, 0x05,
+ 0x47, 0x96, 0xE2, 0x67, 0x97, 0xFE, 0xAF, 0x36,
+ 0xE9, 0xF6, 0xAD, 0x43, 0xF1, 0x4B, 0x35, 0xA4
+ },
+ {
+ 0xE8, 0xB7, 0x9E, 0xC5, 0xD0, 0x6E, 0x11, 0x1B,
+ 0xDF, 0xAF, 0xD7, 0x1E, 0x9F, 0x57, 0x60, 0xF0,
+ 0x0A, 0xC8, 0xAC, 0x5D, 0x8B, 0xF7, 0x68, 0xF9,
+ 0xFF, 0x6F, 0x08, 0xB8, 0xF0, 0x26, 0x09, 0x6B,
+ 0x1C, 0xC3, 0xA4, 0xC9, 0x73, 0x33, 0x30, 0x19,
+ 0xF1, 0xE3, 0x55, 0x3E, 0x77, 0xDA, 0x3F, 0x98,
+ 0xCB, 0x9F, 0x54, 0x2E, 0x0A, 0x90, 0xE5, 0xF8,
+ 0xA9, 0x40, 0xCC, 0x58, 0xE5, 0x98, 0x44, 0xB3
+ },
+ {
+ 0xDF, 0xB3, 0x20, 0xC4, 0x4F, 0x9D, 0x41, 0xD1,
+ 0xEF, 0xDC, 0xC0, 0x15, 0xF0, 0x8D, 0xD5, 0x53,
+ 0x9E, 0x52, 0x6E, 0x39, 0xC8, 0x7D, 0x50, 0x9A,
+ 0xE6, 0x81, 0x2A, 0x96, 0x9E, 0x54, 0x31, 0xBF,
+ 0x4F, 0xA7, 0xD9, 0x1F, 0xFD, 0x03, 0xB9, 0x81,
+ 0xE0, 0xD5, 0x44, 0xCF, 0x72, 0xD7, 0xB1, 0xC0,
+ 0x37, 0x4F, 0x88, 0x01, 0x48, 0x2E, 0x6D, 0xEA,
+ 0x2E, 0xF9, 0x03, 0x87, 0x7E, 0xBA, 0x67, 0x5E
+ },
+ {
+ 0xD8, 0x86, 0x75, 0x11, 0x8F, 0xDB, 0x55, 0xA5,
+ 0xFB, 0x36, 0x5A, 0xC2, 0xAF, 0x1D, 0x21, 0x7B,
+ 0xF5, 0x26, 0xCE, 0x1E, 0xE9, 0xC9, 0x4B, 0x2F,
+ 0x00, 0x90, 0xB2, 0xC5, 0x8A, 0x06, 0xCA, 0x58,
+ 0x18, 0x7D, 0x7F, 0xE5, 0x7C, 0x7B, 0xED, 0x9D,
+ 0x26, 0xFC, 0xA0, 0x67, 0xB4, 0x11, 0x0E, 0xEF,
+ 0xCD, 0x9A, 0x0A, 0x34, 0x5D, 0xE8, 0x72, 0xAB,
+ 0xE2, 0x0D, 0xE3, 0x68, 0x00, 0x1B, 0x07, 0x45
+ },
+ {
+ 0xB8, 0x93, 0xF2, 0xFC, 0x41, 0xF7, 0xB0, 0xDD,
+ 0x6E, 0x2F, 0x6A, 0xA2, 0xE0, 0x37, 0x0C, 0x0C,
+ 0xFF, 0x7D, 0xF0, 0x9E, 0x3A, 0xCF, 0xCC, 0x0E,
+ 0x92, 0x0B, 0x6E, 0x6F, 0xAD, 0x0E, 0xF7, 0x47,
+ 0xC4, 0x06, 0x68, 0x41, 0x7D, 0x34, 0x2B, 0x80,
+ 0xD2, 0x35, 0x1E, 0x8C, 0x17, 0x5F, 0x20, 0x89,
+ 0x7A, 0x06, 0x2E, 0x97, 0x65, 0xE6, 0xC6, 0x7B,
+ 0x53, 0x9B, 0x6B, 0xA8, 0xB9, 0x17, 0x05, 0x45
+ },
+ {
+ 0x6C, 0x67, 0xEC, 0x56, 0x97, 0xAC, 0xCD, 0x23,
+ 0x5C, 0x59, 0xB4, 0x86, 0xD7, 0xB7, 0x0B, 0xAE,
+ 0xED, 0xCB, 0xD4, 0xAA, 0x64, 0xEB, 0xD4, 0xEE,
+ 0xF3, 0xC7, 0xEA, 0xC1, 0x89, 0x56, 0x1A, 0x72,
+ 0x62, 0x50, 0xAE, 0xC4, 0xD4, 0x8C, 0xAD, 0xCA,
+ 0xFB, 0xBE, 0x2C, 0xE3, 0xC1, 0x6C, 0xE2, 0xD6,
+ 0x91, 0xA8, 0xCC, 0xE0, 0x6E, 0x88, 0x79, 0x55,
+ 0x6D, 0x44, 0x83, 0xED, 0x71, 0x65, 0xC0, 0x63
+ },
+ {
+ 0xF1, 0xAA, 0x2B, 0x04, 0x4F, 0x8F, 0x0C, 0x63,
+ 0x8A, 0x3F, 0x36, 0x2E, 0x67, 0x7B, 0x5D, 0x89,
+ 0x1D, 0x6F, 0xD2, 0xAB, 0x07, 0x65, 0xF6, 0xEE,
+ 0x1E, 0x49, 0x87, 0xDE, 0x05, 0x7E, 0xAD, 0x35,
+ 0x78, 0x83, 0xD9, 0xB4, 0x05, 0xB9, 0xD6, 0x09,
+ 0xEE, 0xA1, 0xB8, 0x69, 0xD9, 0x7F, 0xB1, 0x6D,
+ 0x9B, 0x51, 0x01, 0x7C, 0x55, 0x3F, 0x3B, 0x93,
+ 0xC0, 0xA1, 0xE0, 0xF1, 0x29, 0x6F, 0xED, 0xCD
+ },
+ {
+ 0xCB, 0xAA, 0x25, 0x95, 0x72, 0xD4, 0xAE, 0xBF,
+ 0xC1, 0x91, 0x7A, 0xCD, 0xDC, 0x58, 0x2B, 0x9F,
+ 0x8D, 0xFA, 0xA9, 0x28, 0xA1, 0x98, 0xCA, 0x7A,
+ 0xCD, 0x0F, 0x2A, 0xA7, 0x6A, 0x13, 0x4A, 0x90,
+ 0x25, 0x2E, 0x62, 0x98, 0xA6, 0x5B, 0x08, 0x18,
+ 0x6A, 0x35, 0x0D, 0x5B, 0x76, 0x26, 0x69, 0x9F,
+ 0x8C, 0xB7, 0x21, 0xA3, 0xEA, 0x59, 0x21, 0xB7,
+ 0x53, 0xAE, 0x3A, 0x2D, 0xCE, 0x24, 0xBA, 0x3A
+ },
+ {
+ 0xFA, 0x15, 0x49, 0xC9, 0x79, 0x6C, 0xD4, 0xD3,
+ 0x03, 0xDC, 0xF4, 0x52, 0xC1, 0xFB, 0xD5, 0x74,
+ 0x4F, 0xD9, 0xB9, 0xB4, 0x70, 0x03, 0xD9, 0x20,
+ 0xB9, 0x2D, 0xE3, 0x48, 0x39, 0xD0, 0x7E, 0xF2,
+ 0xA2, 0x9D, 0xED, 0x68, 0xF6, 0xFC, 0x9E, 0x6C,
+ 0x45, 0xE0, 0x71, 0xA2, 0xE4, 0x8B, 0xD5, 0x0C,
+ 0x50, 0x84, 0xE9, 0x6B, 0x65, 0x7D, 0xD0, 0x40,
+ 0x40, 0x45, 0xA1, 0xDD, 0xEF, 0xE2, 0x82, 0xED
+ },
+ {
+ 0x5C, 0xF2, 0xAC, 0x89, 0x7A, 0xB4, 0x44, 0xDC,
+ 0xB5, 0xC8, 0xD8, 0x7C, 0x49, 0x5D, 0xBD, 0xB3,
+ 0x4E, 0x18, 0x38, 0xB6, 0xB6, 0x29, 0x42, 0x7C,
+ 0xAA, 0x51, 0x70, 0x2A, 0xD0, 0xF9, 0x68, 0x85,
+ 0x25, 0xF1, 0x3B, 0xEC, 0x50, 0x3A, 0x3C, 0x3A,
+ 0x2C, 0x80, 0xA6, 0x5E, 0x0B, 0x57, 0x15, 0xE8,
+ 0xAF, 0xAB, 0x00, 0xFF, 0xA5, 0x6E, 0xC4, 0x55,
+ 0xA4, 0x9A, 0x1A, 0xD3, 0x0A, 0xA2, 0x4F, 0xCD
+ },
+ {
+ 0x9A, 0xAF, 0x80, 0x20, 0x7B, 0xAC, 0xE1, 0x7B,
+ 0xB7, 0xAB, 0x14, 0x57, 0x57, 0xD5, 0x69, 0x6B,
+ 0xDE, 0x32, 0x40, 0x6E, 0xF2, 0x2B, 0x44, 0x29,
+ 0x2E, 0xF6, 0x5D, 0x45, 0x19, 0xC3, 0xBB, 0x2A,
+ 0xD4, 0x1A, 0x59, 0xB6, 0x2C, 0xC3, 0xE9, 0x4B,
+ 0x6F, 0xA9, 0x6D, 0x32, 0xA7, 0xFA, 0xAD, 0xAE,
+ 0x28, 0xAF, 0x7D, 0x35, 0x09, 0x72, 0x19, 0xAA,
+ 0x3F, 0xD8, 0xCD, 0xA3, 0x1E, 0x40, 0xC2, 0x75
+ },
+ {
+ 0xAF, 0x88, 0xB1, 0x63, 0x40, 0x2C, 0x86, 0x74,
+ 0x5C, 0xB6, 0x50, 0xC2, 0x98, 0x8F, 0xB9, 0x52,
+ 0x11, 0xB9, 0x4B, 0x03, 0xEF, 0x29, 0x0E, 0xED,
+ 0x96, 0x62, 0x03, 0x42, 0x41, 0xFD, 0x51, 0xCF,
+ 0x39, 0x8F, 0x80, 0x73, 0xE3, 0x69, 0x35, 0x4C,
+ 0x43, 0xEA, 0xE1, 0x05, 0x2F, 0x9B, 0x63, 0xB0,
+ 0x81, 0x91, 0xCA, 0xA1, 0x38, 0xAA, 0x54, 0xFE,
+ 0xA8, 0x89, 0xCC, 0x70, 0x24, 0x23, 0x68, 0x97
+ },
+ {
+ 0x48, 0xFA, 0x7D, 0x64, 0xE1, 0xCE, 0xEE, 0x27,
+ 0xB9, 0x86, 0x4D, 0xB5, 0xAD, 0xA4, 0xB5, 0x3D,
+ 0x00, 0xC9, 0xBC, 0x76, 0x26, 0x55, 0x58, 0x13,
+ 0xD3, 0xCD, 0x67, 0x30, 0xAB, 0x3C, 0xC0, 0x6F,
+ 0xF3, 0x42, 0xD7, 0x27, 0x90, 0x5E, 0x33, 0x17,
+ 0x1B, 0xDE, 0x6E, 0x84, 0x76, 0xE7, 0x7F, 0xB1,
+ 0x72, 0x08, 0x61, 0xE9, 0x4B, 0x73, 0xA2, 0xC5,
+ 0x38, 0xD2, 0x54, 0x74, 0x62, 0x85, 0xF4, 0x30
+ },
+ {
+ 0x0E, 0x6F, 0xD9, 0x7A, 0x85, 0xE9, 0x04, 0xF8,
+ 0x7B, 0xFE, 0x85, 0xBB, 0xEB, 0x34, 0xF6, 0x9E,
+ 0x1F, 0x18, 0x10, 0x5C, 0xF4, 0xED, 0x4F, 0x87,
+ 0xAE, 0xC3, 0x6C, 0x6E, 0x8B, 0x5F, 0x68, 0xBD,
+ 0x2A, 0x6F, 0x3D, 0xC8, 0xA9, 0xEC, 0xB2, 0xB6,
+ 0x1D, 0xB4, 0xEE, 0xDB, 0x6B, 0x2E, 0xA1, 0x0B,
+ 0xF9, 0xCB, 0x02, 0x51, 0xFB, 0x0F, 0x8B, 0x34,
+ 0x4A, 0xBF, 0x7F, 0x36, 0x6B, 0x6D, 0xE5, 0xAB
+ },
+ {
+ 0x06, 0x62, 0x2D, 0xA5, 0x78, 0x71, 0x76, 0x28,
+ 0x7F, 0xDC, 0x8F, 0xED, 0x44, 0x0B, 0xAD, 0x18,
+ 0x7D, 0x83, 0x00, 0x99, 0xC9, 0x4E, 0x6D, 0x04,
+ 0xC8, 0xE9, 0xC9, 0x54, 0xCD, 0xA7, 0x0C, 0x8B,
+ 0xB9, 0xE1, 0xFC, 0x4A, 0x6D, 0x0B, 0xAA, 0x83,
+ 0x1B, 0x9B, 0x78, 0xEF, 0x66, 0x48, 0x68, 0x1A,
+ 0x48, 0x67, 0xA1, 0x1D, 0xA9, 0x3E, 0xE3, 0x6E,
+ 0x5E, 0x6A, 0x37, 0xD8, 0x7F, 0xC6, 0x3F, 0x6F
+ },
+ {
+ 0x1D, 0xA6, 0x77, 0x2B, 0x58, 0xFA, 0xBF, 0x9C,
+ 0x61, 0xF6, 0x8D, 0x41, 0x2C, 0x82, 0xF1, 0x82,
+ 0xC0, 0x23, 0x6D, 0x7D, 0x57, 0x5E, 0xF0, 0xB5,
+ 0x8D, 0xD2, 0x24, 0x58, 0xD6, 0x43, 0xCD, 0x1D,
+ 0xFC, 0x93, 0xB0, 0x38, 0x71, 0xC3, 0x16, 0xD8,
+ 0x43, 0x0D, 0x31, 0x29, 0x95, 0xD4, 0x19, 0x7F,
+ 0x08, 0x74, 0xC9, 0x91, 0x72, 0xBA, 0x00, 0x4A,
+ 0x01, 0xEE, 0x29, 0x5A, 0xBA, 0xC2, 0x4E, 0x46
+ },
+ {
+ 0x3C, 0xD2, 0xD9, 0x32, 0x0B, 0x7B, 0x1D, 0x5F,
+ 0xB9, 0xAA, 0xB9, 0x51, 0xA7, 0x60, 0x23, 0xFA,
+ 0x66, 0x7B, 0xE1, 0x4A, 0x91, 0x24, 0xE3, 0x94,
+ 0x51, 0x39, 0x18, 0xA3, 0xF4, 0x40, 0x96, 0xAE,
+ 0x49, 0x04, 0xBA, 0x0F, 0xFC, 0x15, 0x0B, 0x63,
+ 0xBC, 0x7A, 0xB1, 0xEE, 0xB9, 0xA6, 0xE2, 0x57,
+ 0xE5, 0xC8, 0xF0, 0x00, 0xA7, 0x03, 0x94, 0xA5,
+ 0xAF, 0xD8, 0x42, 0x71, 0x5D, 0xE1, 0x5F, 0x29
+ },
+ {
+ 0x04, 0xCD, 0xC1, 0x4F, 0x74, 0x34, 0xE0, 0xB4,
+ 0xBE, 0x70, 0xCB, 0x41, 0xDB, 0x4C, 0x77, 0x9A,
+ 0x88, 0xEA, 0xEF, 0x6A, 0xCC, 0xEB, 0xCB, 0x41,
+ 0xF2, 0xD4, 0x2F, 0xFF, 0xE7, 0xF3, 0x2A, 0x8E,
+ 0x28, 0x1B, 0x5C, 0x10, 0x3A, 0x27, 0x02, 0x1D,
+ 0x0D, 0x08, 0x36, 0x22, 0x50, 0x75, 0x3C, 0xDF,
+ 0x70, 0x29, 0x21, 0x95, 0xA5, 0x3A, 0x48, 0x72,
+ 0x8C, 0xEB, 0x58, 0x44, 0xC2, 0xD9, 0x8B, 0xAB
+ },
+ {
+ 0x90, 0x71, 0xB7, 0xA8, 0xA0, 0x75, 0xD0, 0x09,
+ 0x5B, 0x8F, 0xB3, 0xAE, 0x51, 0x13, 0x78, 0x57,
+ 0x35, 0xAB, 0x98, 0xE2, 0xB5, 0x2F, 0xAF, 0x91,
+ 0xD5, 0xB8, 0x9E, 0x44, 0xAA, 0xC5, 0xB5, 0xD4,
+ 0xEB, 0xBF, 0x91, 0x22, 0x3B, 0x0F, 0xF4, 0xC7,
+ 0x19, 0x05, 0xDA, 0x55, 0x34, 0x2E, 0x64, 0x65,
+ 0x5D, 0x6E, 0xF8, 0xC8, 0x9A, 0x47, 0x68, 0xC3,
+ 0xF9, 0x3A, 0x6D, 0xC0, 0x36, 0x6B, 0x5B, 0xC8
+ },
+ {
+ 0xEB, 0xB3, 0x02, 0x40, 0xDD, 0x96, 0xC7, 0xBC,
+ 0x8D, 0x0A, 0xBE, 0x49, 0xAA, 0x4E, 0xDC, 0xBB,
+ 0x4A, 0xFD, 0xC5, 0x1F, 0xF9, 0xAA, 0xF7, 0x20,
+ 0xD3, 0xF9, 0xE7, 0xFB, 0xB0, 0xF9, 0xC6, 0xD6,
+ 0x57, 0x13, 0x50, 0x50, 0x17, 0x69, 0xFC, 0x4E,
+ 0xBD, 0x0B, 0x21, 0x41, 0x24, 0x7F, 0xF4, 0x00,
+ 0xD4, 0xFD, 0x4B, 0xE4, 0x14, 0xED, 0xF3, 0x77,
+ 0x57, 0xBB, 0x90, 0xA3, 0x2A, 0xC5, 0xC6, 0x5A
+ },
+ {
+ 0x85, 0x32, 0xC5, 0x8B, 0xF3, 0xC8, 0x01, 0x5D,
+ 0x9D, 0x1C, 0xBE, 0x00, 0xEE, 0xF1, 0xF5, 0x08,
+ 0x2F, 0x8F, 0x36, 0x32, 0xFB, 0xE9, 0xF1, 0xED,
+ 0x4F, 0x9D, 0xFB, 0x1F, 0xA7, 0x9E, 0x82, 0x83,
+ 0x06, 0x6D, 0x77, 0xC4, 0x4C, 0x4A, 0xF9, 0x43,
+ 0xD7, 0x6B, 0x30, 0x03, 0x64, 0xAE, 0xCB, 0xD0,
+ 0x64, 0x8C, 0x8A, 0x89, 0x39, 0xBD, 0x20, 0x41,
+ 0x23, 0xF4, 0xB5, 0x62, 0x60, 0x42, 0x2D, 0xEC
+ },
+ {
+ 0xFE, 0x98, 0x46, 0xD6, 0x4F, 0x7C, 0x77, 0x08,
+ 0x69, 0x6F, 0x84, 0x0E, 0x2D, 0x76, 0xCB, 0x44,
+ 0x08, 0xB6, 0x59, 0x5C, 0x2F, 0x81, 0xEC, 0x6A,
+ 0x28, 0xA7, 0xF2, 0xF2, 0x0C, 0xB8, 0x8C, 0xFE,
+ 0x6A, 0xC0, 0xB9, 0xE9, 0xB8, 0x24, 0x4F, 0x08,
+ 0xBD, 0x70, 0x95, 0xC3, 0x50, 0xC1, 0xD0, 0x84,
+ 0x2F, 0x64, 0xFB, 0x01, 0xBB, 0x7F, 0x53, 0x2D,
+ 0xFC, 0xD4, 0x73, 0x71, 0xB0, 0xAE, 0xEB, 0x79
+ },
+ {
+ 0x28, 0xF1, 0x7E, 0xA6, 0xFB, 0x6C, 0x42, 0x09,
+ 0x2D, 0xC2, 0x64, 0x25, 0x7E, 0x29, 0x74, 0x63,
+ 0x21, 0xFB, 0x5B, 0xDA, 0xEA, 0x98, 0x73, 0xC2,
+ 0xA7, 0xFA, 0x9D, 0x8F, 0x53, 0x81, 0x8E, 0x89,
+ 0x9E, 0x16, 0x1B, 0xC7, 0x7D, 0xFE, 0x80, 0x90,
+ 0xAF, 0xD8, 0x2B, 0xF2, 0x26, 0x6C, 0x5C, 0x1B,
+ 0xC9, 0x30, 0xA8, 0xD1, 0x54, 0x76, 0x24, 0x43,
+ 0x9E, 0x66, 0x2E, 0xF6, 0x95, 0xF2, 0x6F, 0x24
+ },
+ {
+ 0xEC, 0x6B, 0x7D, 0x7F, 0x03, 0x0D, 0x48, 0x50,
+ 0xAC, 0xAE, 0x3C, 0xB6, 0x15, 0xC2, 0x1D, 0xD2,
+ 0x52, 0x06, 0xD6, 0x3E, 0x84, 0xD1, 0xDB, 0x8D,
+ 0x95, 0x73, 0x70, 0x73, 0x7B, 0xA0, 0xE9, 0x84,
+ 0x67, 0xEA, 0x0C, 0xE2, 0x74, 0xC6, 0x61, 0x99,
+ 0x90, 0x1E, 0xAE, 0xC1, 0x8A, 0x08, 0x52, 0x57,
+ 0x15, 0xF5, 0x3B, 0xFD, 0xB0, 0xAA, 0xCB, 0x61,
+ 0x3D, 0x34, 0x2E, 0xBD, 0xCE, 0xED, 0xDC, 0x3B
+ },
+ {
+ 0xB4, 0x03, 0xD3, 0x69, 0x1C, 0x03, 0xB0, 0xD3,
+ 0x41, 0x8D, 0xF3, 0x27, 0xD5, 0x86, 0x0D, 0x34,
+ 0xBB, 0xFC, 0xC4, 0x51, 0x9B, 0xFB, 0xCE, 0x36,
+ 0xBF, 0x33, 0xB2, 0x08, 0x38, 0x5F, 0xAD, 0xB9,
+ 0x18, 0x6B, 0xC7, 0x8A, 0x76, 0xC4, 0x89, 0xD8,
+ 0x9F, 0xD5, 0x7E, 0x7D, 0xC7, 0x54, 0x12, 0xD2,
+ 0x3B, 0xCD, 0x1D, 0xAE, 0x84, 0x70, 0xCE, 0x92,
+ 0x74, 0x75, 0x4B, 0xB8, 0x58, 0x5B, 0x13, 0xC5
+ },
+ {
+ 0x31, 0xFC, 0x79, 0x73, 0x8B, 0x87, 0x72, 0xB3,
+ 0xF5, 0x5C, 0xD8, 0x17, 0x88, 0x13, 0xB3, 0xB5,
+ 0x2D, 0x0D, 0xB5, 0xA4, 0x19, 0xD3, 0x0B, 0xA9,
+ 0x49, 0x5C, 0x4B, 0x9D, 0xA0, 0x21, 0x9F, 0xAC,
+ 0x6D, 0xF8, 0xE7, 0xC2, 0x3A, 0x81, 0x15, 0x51,
+ 0xA6, 0x2B, 0x82, 0x7F, 0x25, 0x6E, 0xCD, 0xB8,
+ 0x12, 0x4A, 0xC8, 0xA6, 0x79, 0x2C, 0xCF, 0xEC,
+ 0xC3, 0xB3, 0x01, 0x27, 0x22, 0xE9, 0x44, 0x63
+ },
+ {
+ 0xBB, 0x20, 0x39, 0xEC, 0x28, 0x70, 0x91, 0xBC,
+ 0xC9, 0x64, 0x2F, 0xC9, 0x00, 0x49, 0xE7, 0x37,
+ 0x32, 0xE0, 0x2E, 0x57, 0x7E, 0x28, 0x62, 0xB3,
+ 0x22, 0x16, 0xAE, 0x9B, 0xED, 0xCD, 0x73, 0x0C,
+ 0x4C, 0x28, 0x4E, 0xF3, 0x96, 0x8C, 0x36, 0x8B,
+ 0x7D, 0x37, 0x58, 0x4F, 0x97, 0xBD, 0x4B, 0x4D,
+ 0xC6, 0xEF, 0x61, 0x27, 0xAC, 0xFE, 0x2E, 0x6A,
+ 0xE2, 0x50, 0x91, 0x24, 0xE6, 0x6C, 0x8A, 0xF4
+ },
+ {
+ 0xF5, 0x3D, 0x68, 0xD1, 0x3F, 0x45, 0xED, 0xFC,
+ 0xB9, 0xBD, 0x41, 0x5E, 0x28, 0x31, 0xE9, 0x38,
+ 0x35, 0x0D, 0x53, 0x80, 0xD3, 0x43, 0x22, 0x78,
+ 0xFC, 0x1C, 0x0C, 0x38, 0x1F, 0xCB, 0x7C, 0x65,
+ 0xC8, 0x2D, 0xAF, 0xE0, 0x51, 0xD8, 0xC8, 0xB0,
+ 0xD4, 0x4E, 0x09, 0x74, 0xA0, 0xE5, 0x9E, 0xC7,
+ 0xBF, 0x7E, 0xD0, 0x45, 0x9F, 0x86, 0xE9, 0x6F,
+ 0x32, 0x9F, 0xC7, 0x97, 0x52, 0x51, 0x0F, 0xD3
+ },
+ {
+ 0x8D, 0x56, 0x8C, 0x79, 0x84, 0xF0, 0xEC, 0xDF,
+ 0x76, 0x40, 0xFB, 0xC4, 0x83, 0xB5, 0xD8, 0xC9,
+ 0xF8, 0x66, 0x34, 0xF6, 0xF4, 0x32, 0x91, 0x84,
+ 0x1B, 0x30, 0x9A, 0x35, 0x0A, 0xB9, 0xC1, 0x13,
+ 0x7D, 0x24, 0x06, 0x6B, 0x09, 0xDA, 0x99, 0x44,
+ 0xBA, 0xC5, 0x4D, 0x5B, 0xB6, 0x58, 0x0D, 0x83,
+ 0x60, 0x47, 0xAA, 0xC7, 0x4A, 0xB7, 0x24, 0xB8,
+ 0x87, 0xEB, 0xF9, 0x3D, 0x4B, 0x32, 0xEC, 0xA9
+ },
+ {
+ 0xC0, 0xB6, 0x5C, 0xE5, 0xA9, 0x6F, 0xF7, 0x74,
+ 0xC4, 0x56, 0xCA, 0xC3, 0xB5, 0xF2, 0xC4, 0xCD,
+ 0x35, 0x9B, 0x4F, 0xF5, 0x3E, 0xF9, 0x3A, 0x3D,
+ 0xA0, 0x77, 0x8B, 0xE4, 0x90, 0x0D, 0x1E, 0x8D,
+ 0xA1, 0x60, 0x1E, 0x76, 0x9E, 0x8F, 0x1B, 0x02,
+ 0xD2, 0xA2, 0xF8, 0xC5, 0xB9, 0xFA, 0x10, 0xB4,
+ 0x4F, 0x1C, 0x18, 0x69, 0x85, 0x46, 0x8F, 0xEE,
+ 0xB0, 0x08, 0x73, 0x02, 0x83, 0xA6, 0x65, 0x7D
+ },
+ {
+ 0x49, 0x00, 0xBB, 0xA6, 0xF5, 0xFB, 0x10, 0x3E,
+ 0xCE, 0x8E, 0xC9, 0x6A, 0xDA, 0x13, 0xA5, 0xC3,
+ 0xC8, 0x54, 0x88, 0xE0, 0x55, 0x51, 0xDA, 0x6B,
+ 0x6B, 0x33, 0xD9, 0x88, 0xE6, 0x11, 0xEC, 0x0F,
+ 0xE2, 0xE3, 0xC2, 0xAA, 0x48, 0xEA, 0x6A, 0xE8,
+ 0x98, 0x6A, 0x3A, 0x23, 0x1B, 0x22, 0x3C, 0x5D,
+ 0x27, 0xCE, 0xC2, 0xEA, 0xDD, 0xE9, 0x1C, 0xE0,
+ 0x79, 0x81, 0xEE, 0x65, 0x28, 0x62, 0xD1, 0xE4
+ },
+ {
+ 0xC7, 0xF5, 0xC3, 0x7C, 0x72, 0x85, 0xF9, 0x27,
+ 0xF7, 0x64, 0x43, 0x41, 0x4D, 0x43, 0x57, 0xFF,
+ 0x78, 0x96, 0x47, 0xD7, 0xA0, 0x05, 0xA5, 0xA7,
+ 0x87, 0xE0, 0x3C, 0x34, 0x6B, 0x57, 0xF4, 0x9F,
+ 0x21, 0xB6, 0x4F, 0xA9, 0xCF, 0x4B, 0x7E, 0x45,
+ 0x57, 0x3E, 0x23, 0x04, 0x90, 0x17, 0x56, 0x71,
+ 0x21, 0xA9, 0xC3, 0xD4, 0xB2, 0xB7, 0x3E, 0xC5,
+ 0xE9, 0x41, 0x35, 0x77, 0x52, 0x5D, 0xB4, 0x5A
+ },
+ {
+ 0xEC, 0x70, 0x96, 0x33, 0x07, 0x36, 0xFD, 0xB2,
+ 0xD6, 0x4B, 0x56, 0x53, 0xE7, 0x47, 0x5D, 0xA7,
+ 0x46, 0xC2, 0x3A, 0x46, 0x13, 0xA8, 0x26, 0x87,
+ 0xA2, 0x80, 0x62, 0xD3, 0x23, 0x63, 0x64, 0x28,
+ 0x4A, 0xC0, 0x17, 0x20, 0xFF, 0xB4, 0x06, 0xCF,
+ 0xE2, 0x65, 0xC0, 0xDF, 0x62, 0x6A, 0x18, 0x8C,
+ 0x9E, 0x59, 0x63, 0xAC, 0xE5, 0xD3, 0xD5, 0xBB,
+ 0x36, 0x3E, 0x32, 0xC3, 0x8C, 0x21, 0x90, 0xA6
+ },
+ {
+ 0x82, 0xE7, 0x44, 0xC7, 0x5F, 0x46, 0x49, 0xEC,
+ 0x52, 0xB8, 0x07, 0x71, 0xA7, 0x7D, 0x47, 0x5A,
+ 0x3B, 0xC0, 0x91, 0x98, 0x95, 0x56, 0x96, 0x0E,
+ 0x27, 0x6A, 0x5F, 0x9E, 0xAD, 0x92, 0xA0, 0x3F,
+ 0x71, 0x87, 0x42, 0xCD, 0xCF, 0xEA, 0xEE, 0x5C,
+ 0xB8, 0x5C, 0x44, 0xAF, 0x19, 0x8A, 0xDC, 0x43,
+ 0xA4, 0xA4, 0x28, 0xF5, 0xF0, 0xC2, 0xDD, 0xB0,
+ 0xBE, 0x36, 0x05, 0x9F, 0x06, 0xD7, 0xDF, 0x73
+ },
+ {
+ 0x28, 0x34, 0xB7, 0xA7, 0x17, 0x0F, 0x1F, 0x5B,
+ 0x68, 0x55, 0x9A, 0xB7, 0x8C, 0x10, 0x50, 0xEC,
+ 0x21, 0xC9, 0x19, 0x74, 0x0B, 0x78, 0x4A, 0x90,
+ 0x72, 0xF6, 0xE5, 0xD6, 0x9F, 0x82, 0x8D, 0x70,
+ 0xC9, 0x19, 0xC5, 0x03, 0x9F, 0xB1, 0x48, 0xE3,
+ 0x9E, 0x2C, 0x8A, 0x52, 0x11, 0x83, 0x78, 0xB0,
+ 0x64, 0xCA, 0x8D, 0x50, 0x01, 0xCD, 0x10, 0xA5,
+ 0x47, 0x83, 0x87, 0xB9, 0x66, 0x71, 0x5E, 0xD6
+ },
+ {
+ 0x16, 0xB4, 0xAD, 0xA8, 0x83, 0xF7, 0x2F, 0x85,
+ 0x3B, 0xB7, 0xEF, 0x25, 0x3E, 0xFC, 0xAB, 0x0C,
+ 0x3E, 0x21, 0x61, 0x68, 0x7A, 0xD6, 0x15, 0x43,
+ 0xA0, 0xD2, 0x82, 0x4F, 0x91, 0xC1, 0xF8, 0x13,
+ 0x47, 0xD8, 0x6B, 0xE7, 0x09, 0xB1, 0x69, 0x96,
+ 0xE1, 0x7F, 0x2D, 0xD4, 0x86, 0x92, 0x7B, 0x02,
+ 0x88, 0xAD, 0x38, 0xD1, 0x30, 0x63, 0xC4, 0xA9,
+ 0x67, 0x2C, 0x39, 0x39, 0x7D, 0x37, 0x89, 0xB6
+ },
+ {
+ 0x78, 0xD0, 0x48, 0xF3, 0xA6, 0x9D, 0x8B, 0x54,
+ 0xAE, 0x0E, 0xD6, 0x3A, 0x57, 0x3A, 0xE3, 0x50,
+ 0xD8, 0x9F, 0x7C, 0x6C, 0xF1, 0xF3, 0x68, 0x89,
+ 0x30, 0xDE, 0x89, 0x9A, 0xFA, 0x03, 0x76, 0x97,
+ 0x62, 0x9B, 0x31, 0x4E, 0x5C, 0xD3, 0x03, 0xAA,
+ 0x62, 0xFE, 0xEA, 0x72, 0xA2, 0x5B, 0xF4, 0x2B,
+ 0x30, 0x4B, 0x6C, 0x6B, 0xCB, 0x27, 0xFA, 0xE2,
+ 0x1C, 0x16, 0xD9, 0x25, 0xE1, 0xFB, 0xDA, 0xC3
+ },
+ {
+ 0x0F, 0x74, 0x6A, 0x48, 0x74, 0x92, 0x87, 0xAD,
+ 0xA7, 0x7A, 0x82, 0x96, 0x1F, 0x05, 0xA4, 0xDA,
+ 0x4A, 0xBD, 0xB7, 0xD7, 0x7B, 0x12, 0x20, 0xF8,
+ 0x36, 0xD0, 0x9E, 0xC8, 0x14, 0x35, 0x9C, 0x0E,
+ 0xC0, 0x23, 0x9B, 0x8C, 0x7B, 0x9F, 0xF9, 0xE0,
+ 0x2F, 0x56, 0x9D, 0x1B, 0x30, 0x1E, 0xF6, 0x7C,
+ 0x46, 0x12, 0xD1, 0xDE, 0x4F, 0x73, 0x0F, 0x81,
+ 0xC1, 0x2C, 0x40, 0xCC, 0x06, 0x3C, 0x5C, 0xAA
+ },
+ {
+ 0xF0, 0xFC, 0x85, 0x9D, 0x3B, 0xD1, 0x95, 0xFB,
+ 0xDC, 0x2D, 0x59, 0x1E, 0x4C, 0xDA, 0xC1, 0x51,
+ 0x79, 0xEC, 0x0F, 0x1D, 0xC8, 0x21, 0xC1, 0x1D,
+ 0xF1, 0xF0, 0xC1, 0xD2, 0x6E, 0x62, 0x60, 0xAA,
+ 0xA6, 0x5B, 0x79, 0xFA, 0xFA, 0xCA, 0xFD, 0x7D,
+ 0x3A, 0xD6, 0x1E, 0x60, 0x0F, 0x25, 0x09, 0x05,
+ 0xF5, 0x87, 0x8C, 0x87, 0x45, 0x28, 0x97, 0x64,
+ 0x7A, 0x35, 0xB9, 0x95, 0xBC, 0xAD, 0xC3, 0xA3
+ },
+ {
+ 0x26, 0x20, 0xF6, 0x87, 0xE8, 0x62, 0x5F, 0x6A,
+ 0x41, 0x24, 0x60, 0xB4, 0x2E, 0x2C, 0xEF, 0x67,
+ 0x63, 0x42, 0x08, 0xCE, 0x10, 0xA0, 0xCB, 0xD4,
+ 0xDF, 0xF7, 0x04, 0x4A, 0x41, 0xB7, 0x88, 0x00,
+ 0x77, 0xE9, 0xF8, 0xDC, 0x3B, 0x8D, 0x12, 0x16,
+ 0xD3, 0x37, 0x6A, 0x21, 0xE0, 0x15, 0xB5, 0x8F,
+ 0xB2, 0x79, 0xB5, 0x21, 0xD8, 0x3F, 0x93, 0x88,
+ 0xC7, 0x38, 0x2C, 0x85, 0x05, 0x59, 0x0B, 0x9B
+ },
+ {
+ 0x22, 0x7E, 0x3A, 0xED, 0x8D, 0x2C, 0xB1, 0x0B,
+ 0x91, 0x8F, 0xCB, 0x04, 0xF9, 0xDE, 0x3E, 0x6D,
+ 0x0A, 0x57, 0xE0, 0x84, 0x76, 0xD9, 0x37, 0x59,
+ 0xCD, 0x7B, 0x2E, 0xD5, 0x4A, 0x1C, 0xBF, 0x02,
+ 0x39, 0xC5, 0x28, 0xFB, 0x04, 0xBB, 0xF2, 0x88,
+ 0x25, 0x3E, 0x60, 0x1D, 0x3B, 0xC3, 0x8B, 0x21,
+ 0x79, 0x4A, 0xFE, 0xF9, 0x0B, 0x17, 0x09, 0x4A,
+ 0x18, 0x2C, 0xAC, 0x55, 0x77, 0x45, 0xE7, 0x5F
+ },
+ {
+ 0x1A, 0x92, 0x99, 0x01, 0xB0, 0x9C, 0x25, 0xF2,
+ 0x7D, 0x6B, 0x35, 0xBE, 0x7B, 0x2F, 0x1C, 0x47,
+ 0x45, 0x13, 0x1F, 0xDE, 0xBC, 0xA7, 0xF3, 0xE2,
+ 0x45, 0x19, 0x26, 0x72, 0x04, 0x34, 0xE0, 0xDB,
+ 0x6E, 0x74, 0xFD, 0x69, 0x3A, 0xD2, 0x9B, 0x77,
+ 0x7D, 0xC3, 0x35, 0x5C, 0x59, 0x2A, 0x36, 0x1C,
+ 0x48, 0x73, 0xB0, 0x11, 0x33, 0xA5, 0x7C, 0x2E,
+ 0x3B, 0x70, 0x75, 0xCB, 0xDB, 0x86, 0xF4, 0xFC
+ },
+ {
+ 0x5F, 0xD7, 0x96, 0x8B, 0xC2, 0xFE, 0x34, 0xF2,
+ 0x20, 0xB5, 0xE3, 0xDC, 0x5A, 0xF9, 0x57, 0x17,
+ 0x42, 0xD7, 0x3B, 0x7D, 0x60, 0x81, 0x9F, 0x28,
+ 0x88, 0xB6, 0x29, 0x07, 0x2B, 0x96, 0xA9, 0xD8,
+ 0xAB, 0x2D, 0x91, 0xB8, 0x2D, 0x0A, 0x9A, 0xAB,
+ 0xA6, 0x1B, 0xBD, 0x39, 0x95, 0x81, 0x32, 0xFC,
+ 0xC4, 0x25, 0x70, 0x23, 0xD1, 0xEC, 0xA5, 0x91,
+ 0xB3, 0x05, 0x4E, 0x2D, 0xC8, 0x1C, 0x82, 0x00
+ },
+ {
+ 0xDF, 0xCC, 0xE8, 0xCF, 0x32, 0x87, 0x0C, 0xC6,
+ 0xA5, 0x03, 0xEA, 0xDA, 0xFC, 0x87, 0xFD, 0x6F,
+ 0x78, 0x91, 0x8B, 0x9B, 0x4D, 0x07, 0x37, 0xDB,
+ 0x68, 0x10, 0xBE, 0x99, 0x6B, 0x54, 0x97, 0xE7,
+ 0xE5, 0xCC, 0x80, 0xE3, 0x12, 0xF6, 0x1E, 0x71,
+ 0xFF, 0x3E, 0x96, 0x24, 0x43, 0x60, 0x73, 0x15,
+ 0x64, 0x03, 0xF7, 0x35, 0xF5, 0x6B, 0x0B, 0x01,
+ 0x84, 0x5C, 0x18, 0xF6, 0xCA, 0xF7, 0x72, 0xE6
+ },
+ {
+ 0x02, 0xF7, 0xEF, 0x3A, 0x9C, 0xE0, 0xFF, 0xF9,
+ 0x60, 0xF6, 0x70, 0x32, 0xB2, 0x96, 0xEF, 0xCA,
+ 0x30, 0x61, 0xF4, 0x93, 0x4D, 0x69, 0x07, 0x49,
+ 0xF2, 0xD0, 0x1C, 0x35, 0xC8, 0x1C, 0x14, 0xF3,
+ 0x9A, 0x67, 0xFA, 0x35, 0x0B, 0xC8, 0xA0, 0x35,
+ 0x9B, 0xF1, 0x72, 0x4B, 0xFF, 0xC3, 0xBC, 0xA6,
+ 0xD7, 0xC7, 0xBB, 0xA4, 0x79, 0x1F, 0xD5, 0x22,
+ 0xA3, 0xAD, 0x35, 0x3C, 0x02, 0xEC, 0x5A, 0xA8
+ },
+ {
+ 0x64, 0xBE, 0x5C, 0x6A, 0xBA, 0x65, 0xD5, 0x94,
+ 0x84, 0x4A, 0xE7, 0x8B, 0xB0, 0x22, 0xE5, 0xBE,
+ 0xBE, 0x12, 0x7F, 0xD6, 0xB6, 0xFF, 0xA5, 0xA1,
+ 0x37, 0x03, 0x85, 0x5A, 0xB6, 0x3B, 0x62, 0x4D,
+ 0xCD, 0x1A, 0x36, 0x3F, 0x99, 0x20, 0x3F, 0x63,
+ 0x2E, 0xC3, 0x86, 0xF3, 0xEA, 0x76, 0x7F, 0xC9,
+ 0x92, 0xE8, 0xED, 0x96, 0x86, 0x58, 0x6A, 0xA2,
+ 0x75, 0x55, 0xA8, 0x59, 0x9D, 0x5B, 0x80, 0x8F
+ },
+ {
+ 0xF7, 0x85, 0x85, 0x50, 0x5C, 0x4E, 0xAA, 0x54,
+ 0xA8, 0xB5, 0xBE, 0x70, 0xA6, 0x1E, 0x73, 0x5E,
+ 0x0F, 0xF9, 0x7A, 0xF9, 0x44, 0xDD, 0xB3, 0x00,
+ 0x1E, 0x35, 0xD8, 0x6C, 0x4E, 0x21, 0x99, 0xD9,
+ 0x76, 0x10, 0x4B, 0x6A, 0xE3, 0x17, 0x50, 0xA3,
+ 0x6A, 0x72, 0x6E, 0xD2, 0x85, 0x06, 0x4F, 0x59,
+ 0x81, 0xB5, 0x03, 0x88, 0x9F, 0xEF, 0x82, 0x2F,
+ 0xCD, 0xC2, 0x89, 0x8D, 0xDD, 0xB7, 0x88, 0x9A
+ },
+ {
+ 0xE4, 0xB5, 0x56, 0x60, 0x33, 0x86, 0x95, 0x72,
+ 0xED, 0xFD, 0x87, 0x47, 0x9A, 0x5B, 0xB7, 0x3C,
+ 0x80, 0xE8, 0x75, 0x9B, 0x91, 0x23, 0x28, 0x79,
+ 0xD9, 0x6B, 0x1D, 0xDA, 0x36, 0xC0, 0x12, 0x07,
+ 0x6E, 0xE5, 0xA2, 0xED, 0x7A, 0xE2, 0xDE, 0x63,
+ 0xEF, 0x84, 0x06, 0xA0, 0x6A, 0xEA, 0x82, 0xC1,
+ 0x88, 0x03, 0x1B, 0x56, 0x0B, 0xEA, 0xFB, 0x58,
+ 0x3F, 0xB3, 0xDE, 0x9E, 0x57, 0x95, 0x2A, 0x7E
+ },
+ {
+ 0xE1, 0xB3, 0xE7, 0xED, 0x86, 0x7F, 0x6C, 0x94,
+ 0x84, 0xA2, 0xA9, 0x7F, 0x77, 0x15, 0xF2, 0x5E,
+ 0x25, 0x29, 0x4E, 0x99, 0x2E, 0x41, 0xF6, 0xA7,
+ 0xC1, 0x61, 0xFF, 0xC2, 0xAD, 0xC6, 0xDA, 0xAE,
+ 0xB7, 0x11, 0x31, 0x02, 0xD5, 0xE6, 0x09, 0x02,
+ 0x87, 0xFE, 0x6A, 0xD9, 0x4C, 0xE5, 0xD6, 0xB7,
+ 0x39, 0xC6, 0xCA, 0x24, 0x0B, 0x05, 0xC7, 0x6F,
+ 0xB7, 0x3F, 0x25, 0xDD, 0x02, 0x4B, 0xF9, 0x35
+ },
+ {
+ 0x85, 0xFD, 0x08, 0x5F, 0xDC, 0x12, 0xA0, 0x80,
+ 0x98, 0x3D, 0xF0, 0x7B, 0xD7, 0x01, 0x2B, 0x0D,
+ 0x40, 0x2A, 0x0F, 0x40, 0x43, 0xFC, 0xB2, 0x77,
+ 0x5A, 0xDF, 0x0B, 0xAD, 0x17, 0x4F, 0x9B, 0x08,
+ 0xD1, 0x67, 0x6E, 0x47, 0x69, 0x85, 0x78, 0x5C,
+ 0x0A, 0x5D, 0xCC, 0x41, 0xDB, 0xFF, 0x6D, 0x95,
+ 0xEF, 0x4D, 0x66, 0xA3, 0xFB, 0xDC, 0x4A, 0x74,
+ 0xB8, 0x2B, 0xA5, 0x2D, 0xA0, 0x51, 0x2B, 0x74
+ },
+ {
+ 0xAE, 0xD8, 0xFA, 0x76, 0x4B, 0x0F, 0xBF, 0xF8,
+ 0x21, 0xE0, 0x52, 0x33, 0xD2, 0xF7, 0xB0, 0x90,
+ 0x0E, 0xC4, 0x4D, 0x82, 0x6F, 0x95, 0xE9, 0x3C,
+ 0x34, 0x3C, 0x1B, 0xC3, 0xBA, 0x5A, 0x24, 0x37,
+ 0x4B, 0x1D, 0x61, 0x6E, 0x7E, 0x7A, 0xBA, 0x45,
+ 0x3A, 0x0A, 0xDA, 0x5E, 0x4F, 0xAB, 0x53, 0x82,
+ 0x40, 0x9E, 0x0D, 0x42, 0xCE, 0x9C, 0x2B, 0xC7,
+ 0xFB, 0x39, 0xA9, 0x9C, 0x34, 0x0C, 0x20, 0xF0
+ },
+ {
+ 0x7B, 0xA3, 0xB2, 0xE2, 0x97, 0x23, 0x35, 0x22,
+ 0xEE, 0xB3, 0x43, 0xBD, 0x3E, 0xBC, 0xFD, 0x83,
+ 0x5A, 0x04, 0x00, 0x77, 0x35, 0xE8, 0x7F, 0x0C,
+ 0xA3, 0x00, 0xCB, 0xEE, 0x6D, 0x41, 0x65, 0x65,
+ 0x16, 0x21, 0x71, 0x58, 0x1E, 0x40, 0x20, 0xFF,
+ 0x4C, 0xF1, 0x76, 0x45, 0x0F, 0x12, 0x91, 0xEA,
+ 0x22, 0x85, 0xCB, 0x9E, 0xBF, 0xFE, 0x4C, 0x56,
+ 0x66, 0x06, 0x27, 0x68, 0x51, 0x45, 0x05, 0x1C
+ },
+ {
+ 0xDE, 0x74, 0x8B, 0xCF, 0x89, 0xEC, 0x88, 0x08,
+ 0x47, 0x21, 0xE1, 0x6B, 0x85, 0xF3, 0x0A, 0xDB,
+ 0x1A, 0x61, 0x34, 0xD6, 0x64, 0xB5, 0x84, 0x35,
+ 0x69, 0xBA, 0xBC, 0x5B, 0xBD, 0x1A, 0x15, 0xCA,
+ 0x9B, 0x61, 0x80, 0x3C, 0x90, 0x1A, 0x4F, 0xEF,
+ 0x32, 0x96, 0x5A, 0x17, 0x49, 0xC9, 0xF3, 0xA4,
+ 0xE2, 0x43, 0xE1, 0x73, 0x93, 0x9D, 0xC5, 0xA8,
+ 0xDC, 0x49, 0x5C, 0x67, 0x1A, 0xB5, 0x21, 0x45
+ },
+ {
+ 0xAA, 0xF4, 0xD2, 0xBD, 0xF2, 0x00, 0xA9, 0x19,
+ 0x70, 0x6D, 0x98, 0x42, 0xDC, 0xE1, 0x6C, 0x98,
+ 0x14, 0x0D, 0x34, 0xBC, 0x43, 0x3D, 0xF3, 0x20,
+ 0xAB, 0xA9, 0xBD, 0x42, 0x9E, 0x54, 0x9A, 0xA7,
+ 0xA3, 0x39, 0x76, 0x52, 0xA4, 0xD7, 0x68, 0x27,
+ 0x77, 0x86, 0xCF, 0x99, 0x3C, 0xDE, 0x23, 0x38,
+ 0x67, 0x3E, 0xD2, 0xE6, 0xB6, 0x6C, 0x96, 0x1F,
+ 0xEF, 0xB8, 0x2C, 0xD2, 0x0C, 0x93, 0x33, 0x8F
+ },
+ {
+ 0xC4, 0x08, 0x21, 0x89, 0x68, 0xB7, 0x88, 0xBF,
+ 0x86, 0x4F, 0x09, 0x97, 0xE6, 0xBC, 0x4C, 0x3D,
+ 0xBA, 0x68, 0xB2, 0x76, 0xE2, 0x12, 0x5A, 0x48,
+ 0x43, 0x29, 0x60, 0x52, 0xFF, 0x93, 0xBF, 0x57,
+ 0x67, 0xB8, 0xCD, 0xCE, 0x71, 0x31, 0xF0, 0x87,
+ 0x64, 0x30, 0xC1, 0x16, 0x5F, 0xEC, 0x6C, 0x4F,
+ 0x47, 0xAD, 0xAA, 0x4F, 0xD8, 0xBC, 0xFA, 0xCE,
+ 0xF4, 0x63, 0xB5, 0xD3, 0xD0, 0xFA, 0x61, 0xA0
+ },
+ {
+ 0x76, 0xD2, 0xD8, 0x19, 0xC9, 0x2B, 0xCE, 0x55,
+ 0xFA, 0x8E, 0x09, 0x2A, 0xB1, 0xBF, 0x9B, 0x9E,
+ 0xAB, 0x23, 0x7A, 0x25, 0x26, 0x79, 0x86, 0xCA,
+ 0xCF, 0x2B, 0x8E, 0xE1, 0x4D, 0x21, 0x4D, 0x73,
+ 0x0D, 0xC9, 0xA5, 0xAA, 0x2D, 0x7B, 0x59, 0x6E,
+ 0x86, 0xA1, 0xFD, 0x8F, 0xA0, 0x80, 0x4C, 0x77,
+ 0x40, 0x2D, 0x2F, 0xCD, 0x45, 0x08, 0x36, 0x88,
+ 0xB2, 0x18, 0xB1, 0xCD, 0xFA, 0x0D, 0xCB, 0xCB
+ },
+ {
+ 0x72, 0x06, 0x5E, 0xE4, 0xDD, 0x91, 0xC2, 0xD8,
+ 0x50, 0x9F, 0xA1, 0xFC, 0x28, 0xA3, 0x7C, 0x7F,
+ 0xC9, 0xFA, 0x7D, 0x5B, 0x3F, 0x8A, 0xD3, 0xD0,
+ 0xD7, 0xA2, 0x56, 0x26, 0xB5, 0x7B, 0x1B, 0x44,
+ 0x78, 0x8D, 0x4C, 0xAF, 0x80, 0x62, 0x90, 0x42,
+ 0x5F, 0x98, 0x90, 0xA3, 0xA2, 0xA3, 0x5A, 0x90,
+ 0x5A, 0xB4, 0xB3, 0x7A, 0xCF, 0xD0, 0xDA, 0x6E,
+ 0x45, 0x17, 0xB2, 0x52, 0x5C, 0x96, 0x51, 0xE4
+ },
+ {
+ 0x64, 0x47, 0x5D, 0xFE, 0x76, 0x00, 0xD7, 0x17,
+ 0x1B, 0xEA, 0x0B, 0x39, 0x4E, 0x27, 0xC9, 0xB0,
+ 0x0D, 0x8E, 0x74, 0xDD, 0x1E, 0x41, 0x6A, 0x79,
+ 0x47, 0x36, 0x82, 0xAD, 0x3D, 0xFD, 0xBB, 0x70,
+ 0x66, 0x31, 0x55, 0x80, 0x55, 0xCF, 0xC8, 0xA4,
+ 0x0E, 0x07, 0xBD, 0x01, 0x5A, 0x45, 0x40, 0xDC,
+ 0xDE, 0xA1, 0x58, 0x83, 0xCB, 0xBF, 0x31, 0x41,
+ 0x2D, 0xF1, 0xDE, 0x1C, 0xD4, 0x15, 0x2B, 0x91
+ },
+ {
+ 0x12, 0xCD, 0x16, 0x74, 0xA4, 0x48, 0x8A, 0x5D,
+ 0x7C, 0x2B, 0x31, 0x60, 0xD2, 0xE2, 0xC4, 0xB5,
+ 0x83, 0x71, 0xBE, 0xDA, 0xD7, 0x93, 0x41, 0x8D,
+ 0x6F, 0x19, 0xC6, 0xEE, 0x38, 0x5D, 0x70, 0xB3,
+ 0xE0, 0x67, 0x39, 0x36, 0x9D, 0x4D, 0xF9, 0x10,
+ 0xED, 0xB0, 0xB0, 0xA5, 0x4C, 0xBF, 0xF4, 0x3D,
+ 0x54, 0x54, 0x4C, 0xD3, 0x7A, 0xB3, 0xA0, 0x6C,
+ 0xFA, 0x0A, 0x3D, 0xDA, 0xC8, 0xB6, 0x6C, 0x89
+ },
+ {
+ 0x60, 0x75, 0x69, 0x66, 0x47, 0x9D, 0xED, 0xC6,
+ 0xDD, 0x4B, 0xCF, 0xF8, 0xEA, 0x7D, 0x1D, 0x4C,
+ 0xE4, 0xD4, 0xAF, 0x2E, 0x7B, 0x09, 0x7E, 0x32,
+ 0xE3, 0x76, 0x35, 0x18, 0x44, 0x11, 0x47, 0xCC,
+ 0x12, 0xB3, 0xC0, 0xEE, 0x6D, 0x2E, 0xCA, 0xBF,
+ 0x11, 0x98, 0xCE, 0xC9, 0x2E, 0x86, 0xA3, 0x61,
+ 0x6F, 0xBA, 0x4F, 0x4E, 0x87, 0x2F, 0x58, 0x25,
+ 0x33, 0x0A, 0xDB, 0xB4, 0xC1, 0xDE, 0xE4, 0x44
+ },
+ {
+ 0xA7, 0x80, 0x3B, 0xCB, 0x71, 0xBC, 0x1D, 0x0F,
+ 0x43, 0x83, 0xDD, 0xE1, 0xE0, 0x61, 0x2E, 0x04,
+ 0xF8, 0x72, 0xB7, 0x15, 0xAD, 0x30, 0x81, 0x5C,
+ 0x22, 0x49, 0xCF, 0x34, 0xAB, 0xB8, 0xB0, 0x24,
+ 0x91, 0x5C, 0xB2, 0xFC, 0x9F, 0x4E, 0x7C, 0xC4,
+ 0xC8, 0xCF, 0xD4, 0x5B, 0xE2, 0xD5, 0xA9, 0x1E,
+ 0xAB, 0x09, 0x41, 0xC7, 0xD2, 0x70, 0xE2, 0xDA,
+ 0x4C, 0xA4, 0xA9, 0xF7, 0xAC, 0x68, 0x66, 0x3A
+ },
+ {
+ 0xB8, 0x4E, 0xF6, 0xA7, 0x22, 0x9A, 0x34, 0xA7,
+ 0x50, 0xD9, 0xA9, 0x8E, 0xE2, 0x52, 0x98, 0x71,
+ 0x81, 0x6B, 0x87, 0xFB, 0xE3, 0xBC, 0x45, 0xB4,
+ 0x5F, 0xA5, 0xAE, 0x82, 0xD5, 0x14, 0x15, 0x40,
+ 0x21, 0x11, 0x65, 0xC3, 0xC5, 0xD7, 0xA7, 0x47,
+ 0x6B, 0xA5, 0xA4, 0xAA, 0x06, 0xD6, 0x64, 0x76,
+ 0xF0, 0xD9, 0xDC, 0x49, 0xA3, 0xF1, 0xEE, 0x72,
+ 0xC3, 0xAC, 0xAB, 0xD4, 0x98, 0x96, 0x74, 0x14
+ },
+ {
+ 0xFA, 0xE4, 0xB6, 0xD8, 0xEF, 0xC3, 0xF8, 0xC8,
+ 0xE6, 0x4D, 0x00, 0x1D, 0xAB, 0xEC, 0x3A, 0x21,
+ 0xF5, 0x44, 0xE8, 0x27, 0x14, 0x74, 0x52, 0x51,
+ 0xB2, 0xB4, 0xB3, 0x93, 0xF2, 0xF4, 0x3E, 0x0D,
+ 0xA3, 0xD4, 0x03, 0xC6, 0x4D, 0xB9, 0x5A, 0x2C,
+ 0xB6, 0xE2, 0x3E, 0xBB, 0x7B, 0x9E, 0x94, 0xCD,
+ 0xD5, 0xDD, 0xAC, 0x54, 0xF0, 0x7C, 0x4A, 0x61,
+ 0xBD, 0x3C, 0xB1, 0x0A, 0xA6, 0xF9, 0x3B, 0x49
+ },
+ {
+ 0x34, 0xF7, 0x28, 0x66, 0x05, 0xA1, 0x22, 0x36,
+ 0x95, 0x40, 0x14, 0x1D, 0xED, 0x79, 0xB8, 0x95,
+ 0x72, 0x55, 0xDA, 0x2D, 0x41, 0x55, 0xAB, 0xBF,
+ 0x5A, 0x8D, 0xBB, 0x89, 0xC8, 0xEB, 0x7E, 0xDE,
+ 0x8E, 0xEE, 0xF1, 0xDA, 0xA4, 0x6D, 0xC2, 0x9D,
+ 0x75, 0x1D, 0x04, 0x5D, 0xC3, 0xB1, 0xD6, 0x58,
+ 0xBB, 0x64, 0xB8, 0x0F, 0xF8, 0x58, 0x9E, 0xDD,
+ 0xB3, 0x82, 0x4B, 0x13, 0xDA, 0x23, 0x5A, 0x6B
+ },
+ {
+ 0x3B, 0x3B, 0x48, 0x43, 0x4B, 0xE2, 0x7B, 0x9E,
+ 0xAB, 0xAB, 0xBA, 0x43, 0xBF, 0x6B, 0x35, 0xF1,
+ 0x4B, 0x30, 0xF6, 0xA8, 0x8D, 0xC2, 0xE7, 0x50,
+ 0xC3, 0x58, 0x47, 0x0D, 0x6B, 0x3A, 0xA3, 0xC1,
+ 0x8E, 0x47, 0xDB, 0x40, 0x17, 0xFA, 0x55, 0x10,
+ 0x6D, 0x82, 0x52, 0xF0, 0x16, 0x37, 0x1A, 0x00,
+ 0xF5, 0xF8, 0xB0, 0x70, 0xB7, 0x4B, 0xA5, 0xF2,
+ 0x3C, 0xFF, 0xC5, 0x51, 0x1C, 0x9F, 0x09, 0xF0
+ },
+ {
+ 0xBA, 0x28, 0x9E, 0xBD, 0x65, 0x62, 0xC4, 0x8C,
+ 0x3E, 0x10, 0xA8, 0xAD, 0x6C, 0xE0, 0x2E, 0x73,
+ 0x43, 0x3D, 0x1E, 0x93, 0xD7, 0xC9, 0x27, 0x9D,
+ 0x4D, 0x60, 0xA7, 0xE8, 0x79, 0xEE, 0x11, 0xF4,
+ 0x41, 0xA0, 0x00, 0xF4, 0x8E, 0xD9, 0xF7, 0xC4,
+ 0xED, 0x87, 0xA4, 0x51, 0x36, 0xD7, 0xDC, 0xCD,
+ 0xCA, 0x48, 0x21, 0x09, 0xC7, 0x8A, 0x51, 0x06,
+ 0x2B, 0x3B, 0xA4, 0x04, 0x4A, 0xDA, 0x24, 0x69
+ },
+ {
+ 0x02, 0x29, 0x39, 0xE2, 0x38, 0x6C, 0x5A, 0x37,
+ 0x04, 0x98, 0x56, 0xC8, 0x50, 0xA2, 0xBB, 0x10,
+ 0xA1, 0x3D, 0xFE, 0xA4, 0x21, 0x2B, 0x4C, 0x73,
+ 0x2A, 0x88, 0x40, 0xA9, 0xFF, 0xA5, 0xFA, 0xF5,
+ 0x48, 0x75, 0xC5, 0x44, 0x88, 0x16, 0xB2, 0x78,
+ 0x5A, 0x00, 0x7D, 0xA8, 0xA8, 0xD2, 0xBC, 0x7D,
+ 0x71, 0xA5, 0x4E, 0x4E, 0x65, 0x71, 0xF1, 0x0B,
+ 0x60, 0x0C, 0xBD, 0xB2, 0x5D, 0x13, 0xED, 0xE3
+ },
+ {
+ 0xE6, 0xFE, 0xC1, 0x9D, 0x89, 0xCE, 0x87, 0x17,
+ 0xB1, 0xA0, 0x87, 0x02, 0x46, 0x70, 0xFE, 0x02,
+ 0x6F, 0x6C, 0x7C, 0xBD, 0xA1, 0x1C, 0xAE, 0xF9,
+ 0x59, 0xBB, 0x2D, 0x35, 0x1B, 0xF8, 0x56, 0xF8,
+ 0x05, 0x5D, 0x1C, 0x0E, 0xBD, 0xAA, 0xA9, 0xD1,
+ 0xB1, 0x78, 0x86, 0xFC, 0x2C, 0x56, 0x2B, 0x5E,
+ 0x99, 0x64, 0x2F, 0xC0, 0x64, 0x71, 0x0C, 0x0D,
+ 0x34, 0x88, 0xA0, 0x2B, 0x5E, 0xD7, 0xF6, 0xFD
+ },
+ {
+ 0x94, 0xC9, 0x6F, 0x02, 0xA8, 0xF5, 0x76, 0xAC,
+ 0xA3, 0x2B, 0xA6, 0x1C, 0x2B, 0x20, 0x6F, 0x90,
+ 0x72, 0x85, 0xD9, 0x29, 0x9B, 0x83, 0xAC, 0x17,
+ 0x5C, 0x20, 0x9A, 0x8D, 0x43, 0xD5, 0x3B, 0xFE,
+ 0x68, 0x3D, 0xD1, 0xD8, 0x3E, 0x75, 0x49, 0xCB,
+ 0x90, 0x6C, 0x28, 0xF5, 0x9A, 0xB7, 0xC4, 0x6F,
+ 0x87, 0x51, 0x36, 0x6A, 0x28, 0xC3, 0x9D, 0xD5,
+ 0xFE, 0x26, 0x93, 0xC9, 0x01, 0x96, 0x66, 0xC8
+ },
+ {
+ 0x31, 0xA0, 0xCD, 0x21, 0x5E, 0xBD, 0x2C, 0xB6,
+ 0x1D, 0xE5, 0xB9, 0xED, 0xC9, 0x1E, 0x61, 0x95,
+ 0xE3, 0x1C, 0x59, 0xA5, 0x64, 0x8D, 0x5C, 0x9F,
+ 0x73, 0x7E, 0x12, 0x5B, 0x26, 0x05, 0x70, 0x8F,
+ 0x2E, 0x32, 0x5A, 0xB3, 0x38, 0x1C, 0x8D, 0xCE,
+ 0x1A, 0x3E, 0x95, 0x88, 0x86, 0xF1, 0xEC, 0xDC,
+ 0x60, 0x31, 0x8F, 0x88, 0x2C, 0xFE, 0x20, 0xA2,
+ 0x41, 0x91, 0x35, 0x2E, 0x61, 0x7B, 0x0F, 0x21
+ },
+ {
+ 0x91, 0xAB, 0x50, 0x4A, 0x52, 0x2D, 0xCE, 0x78,
+ 0x77, 0x9F, 0x4C, 0x6C, 0x6B, 0xA2, 0xE6, 0xB6,
+ 0xDB, 0x55, 0x65, 0xC7, 0x6D, 0x3E, 0x7E, 0x7C,
+ 0x92, 0x0C, 0xAF, 0x7F, 0x75, 0x7E, 0xF9, 0xDB,
+ 0x7C, 0x8F, 0xCF, 0x10, 0xE5, 0x7F, 0x03, 0x37,
+ 0x9E, 0xA9, 0xBF, 0x75, 0xEB, 0x59, 0x89, 0x5D,
+ 0x96, 0xE1, 0x49, 0x80, 0x0B, 0x6A, 0xAE, 0x01,
+ 0xDB, 0x77, 0x8B, 0xB9, 0x0A, 0xFB, 0xC9, 0x89
+ },
+ {
+ 0xD8, 0x5C, 0xAB, 0xC6, 0xBD, 0x5B, 0x1A, 0x01,
+ 0xA5, 0xAF, 0xD8, 0xC6, 0x73, 0x47, 0x40, 0xDA,
+ 0x9F, 0xD1, 0xC1, 0xAC, 0xC6, 0xDB, 0x29, 0xBF,
+ 0xC8, 0xA2, 0xE5, 0xB6, 0x68, 0xB0, 0x28, 0xB6,
+ 0xB3, 0x15, 0x4B, 0xFB, 0x87, 0x03, 0xFA, 0x31,
+ 0x80, 0x25, 0x1D, 0x58, 0x9A, 0xD3, 0x80, 0x40,
+ 0xCE, 0xB7, 0x07, 0xC4, 0xBA, 0xD1, 0xB5, 0x34,
+ 0x3C, 0xB4, 0x26, 0xB6, 0x1E, 0xAA, 0x49, 0xC1
+ },
+ {
+ 0xD6, 0x2E, 0xFB, 0xEC, 0x2C, 0xA9, 0xC1, 0xF8,
+ 0xBD, 0x66, 0xCE, 0x8B, 0x3F, 0x6A, 0x89, 0x8C,
+ 0xB3, 0xF7, 0x56, 0x6B, 0xA6, 0x56, 0x8C, 0x61,
+ 0x8A, 0xD1, 0xFE, 0xB2, 0xB6, 0x5B, 0x76, 0xC3,
+ 0xCE, 0x1D, 0xD2, 0x0F, 0x73, 0x95, 0x37, 0x2F,
+ 0xAF, 0x28, 0x42, 0x7F, 0x61, 0xC9, 0x27, 0x80,
+ 0x49, 0xCF, 0x01, 0x40, 0xDF, 0x43, 0x4F, 0x56,
+ 0x33, 0x04, 0x8C, 0x86, 0xB8, 0x1E, 0x03, 0x99
+ },
+ {
+ 0x7C, 0x8F, 0xDC, 0x61, 0x75, 0x43, 0x9E, 0x2C,
+ 0x3D, 0xB1, 0x5B, 0xAF, 0xA7, 0xFB, 0x06, 0x14,
+ 0x3A, 0x6A, 0x23, 0xBC, 0x90, 0xF4, 0x49, 0xE7,
+ 0x9D, 0xEE, 0xF7, 0x3C, 0x3D, 0x49, 0x2A, 0x67,
+ 0x17, 0x15, 0xC1, 0x93, 0xB6, 0xFE, 0xA9, 0xF0,
+ 0x36, 0x05, 0x0B, 0x94, 0x60, 0x69, 0x85, 0x6B,
+ 0x89, 0x7E, 0x08, 0xC0, 0x07, 0x68, 0xF5, 0xEE,
+ 0x5D, 0xDC, 0xF7, 0x0B, 0x7C, 0xD6, 0xD0, 0xE0
+ },
+ {
+ 0x58, 0x60, 0x2E, 0xE7, 0x46, 0x8E, 0x6B, 0xC9,
+ 0xDF, 0x21, 0xBD, 0x51, 0xB2, 0x3C, 0x00, 0x5F,
+ 0x72, 0xD6, 0xCB, 0x01, 0x3F, 0x0A, 0x1B, 0x48,
+ 0xCB, 0xEC, 0x5E, 0xCA, 0x29, 0x92, 0x99, 0xF9,
+ 0x7F, 0x09, 0xF5, 0x4A, 0x9A, 0x01, 0x48, 0x3E,
+ 0xAE, 0xB3, 0x15, 0xA6, 0x47, 0x8B, 0xAD, 0x37,
+ 0xBA, 0x47, 0xCA, 0x13, 0x47, 0xC7, 0xC8, 0xFC,
+ 0x9E, 0x66, 0x95, 0x59, 0x2C, 0x91, 0xD7, 0x23
+ },
+ {
+ 0x27, 0xF5, 0xB7, 0x9E, 0xD2, 0x56, 0xB0, 0x50,
+ 0x99, 0x3D, 0x79, 0x34, 0x96, 0xED, 0xF4, 0x80,
+ 0x7C, 0x1D, 0x85, 0xA7, 0xB0, 0xA6, 0x7C, 0x9C,
+ 0x4F, 0xA9, 0x98, 0x60, 0x75, 0x0B, 0x0A, 0xE6,
+ 0x69, 0x89, 0x67, 0x0A, 0x8F, 0xFD, 0x78, 0x56,
+ 0xD7, 0xCE, 0x41, 0x15, 0x99, 0xE5, 0x8C, 0x4D,
+ 0x77, 0xB2, 0x32, 0xA6, 0x2B, 0xEF, 0x64, 0xD1,
+ 0x52, 0x75, 0xBE, 0x46, 0xA6, 0x82, 0x35, 0xFF
+ },
+ {
+ 0x39, 0x57, 0xA9, 0x76, 0xB9, 0xF1, 0x88, 0x7B,
+ 0xF0, 0x04, 0xA8, 0xDC, 0xA9, 0x42, 0xC9, 0x2D,
+ 0x2B, 0x37, 0xEA, 0x52, 0x60, 0x0F, 0x25, 0xE0,
+ 0xC9, 0xBC, 0x57, 0x07, 0xD0, 0x27, 0x9C, 0x00,
+ 0xC6, 0xE8, 0x5A, 0x83, 0x9B, 0x0D, 0x2D, 0x8E,
+ 0xB5, 0x9C, 0x51, 0xD9, 0x47, 0x88, 0xEB, 0xE6,
+ 0x24, 0x74, 0xA7, 0x91, 0xCA, 0xDF, 0x52, 0xCC,
+ 0xCF, 0x20, 0xF5, 0x07, 0x0B, 0x65, 0x73, 0xFC
+ },
+ {
+ 0xEA, 0xA2, 0x37, 0x6D, 0x55, 0x38, 0x0B, 0xF7,
+ 0x72, 0xEC, 0xCA, 0x9C, 0xB0, 0xAA, 0x46, 0x68,
+ 0xC9, 0x5C, 0x70, 0x71, 0x62, 0xFA, 0x86, 0xD5,
+ 0x18, 0xC8, 0xCE, 0x0C, 0xA9, 0xBF, 0x73, 0x62,
+ 0xB9, 0xF2, 0xA0, 0xAD, 0xC3, 0xFF, 0x59, 0x92,
+ 0x2D, 0xF9, 0x21, 0xB9, 0x45, 0x67, 0xE8, 0x1E,
+ 0x45, 0x2F, 0x6C, 0x1A, 0x07, 0xFC, 0x81, 0x7C,
+ 0xEB, 0xE9, 0x96, 0x04, 0xB3, 0x50, 0x5D, 0x38
+ },
+ {
+ 0xC1, 0xE2, 0xC7, 0x8B, 0x6B, 0x27, 0x34, 0xE2,
+ 0x48, 0x0E, 0xC5, 0x50, 0x43, 0x4C, 0xB5, 0xD6,
+ 0x13, 0x11, 0x1A, 0xDC, 0xC2, 0x1D, 0x47, 0x55,
+ 0x45, 0xC3, 0xB1, 0xB7, 0xE6, 0xFF, 0x12, 0x44,
+ 0x44, 0x76, 0xE5, 0xC0, 0x55, 0x13, 0x2E, 0x22,
+ 0x29, 0xDC, 0x0F, 0x80, 0x70, 0x44, 0xBB, 0x91,
+ 0x9B, 0x1A, 0x56, 0x62, 0xDD, 0x38, 0xA9, 0xEE,
+ 0x65, 0xE2, 0x43, 0xA3, 0x91, 0x1A, 0xED, 0x1A
+ },
+ {
+ 0x8A, 0xB4, 0x87, 0x13, 0x38, 0x9D, 0xD0, 0xFC,
+ 0xF9, 0xF9, 0x65, 0xD3, 0xCE, 0x66, 0xB1, 0xE5,
+ 0x59, 0xA1, 0xF8, 0xC5, 0x87, 0x41, 0xD6, 0x76,
+ 0x83, 0xCD, 0x97, 0x13, 0x54, 0xF4, 0x52, 0xE6,
+ 0x2D, 0x02, 0x07, 0xA6, 0x5E, 0x43, 0x6C, 0x5D,
+ 0x5D, 0x8F, 0x8E, 0xE7, 0x1C, 0x6A, 0xBF, 0xE5,
+ 0x0E, 0x66, 0x90, 0x04, 0xC3, 0x02, 0xB3, 0x1A,
+ 0x7E, 0xA8, 0x31, 0x1D, 0x4A, 0x91, 0x60, 0x51
+ },
+ {
+ 0x24, 0xCE, 0x0A, 0xDD, 0xAA, 0x4C, 0x65, 0x03,
+ 0x8B, 0xD1, 0xB1, 0xC0, 0xF1, 0x45, 0x2A, 0x0B,
+ 0x12, 0x87, 0x77, 0xAA, 0xBC, 0x94, 0xA2, 0x9D,
+ 0xF2, 0xFD, 0x6C, 0x7E, 0x2F, 0x85, 0xF8, 0xAB,
+ 0x9A, 0xC7, 0xEF, 0xF5, 0x16, 0xB0, 0xE0, 0xA8,
+ 0x25, 0xC8, 0x4A, 0x24, 0xCF, 0xE4, 0x92, 0xEA,
+ 0xAD, 0x0A, 0x63, 0x08, 0xE4, 0x6D, 0xD4, 0x2F,
+ 0xE8, 0x33, 0x3A, 0xB9, 0x71, 0xBB, 0x30, 0xCA
+ },
+ {
+ 0x51, 0x54, 0xF9, 0x29, 0xEE, 0x03, 0x04, 0x5B,
+ 0x6B, 0x0C, 0x00, 0x04, 0xFA, 0x77, 0x8E, 0xDE,
+ 0xE1, 0xD1, 0x39, 0x89, 0x32, 0x67, 0xCC, 0x84,
+ 0x82, 0x5A, 0xD7, 0xB3, 0x6C, 0x63, 0xDE, 0x32,
+ 0x79, 0x8E, 0x4A, 0x16, 0x6D, 0x24, 0x68, 0x65,
+ 0x61, 0x35, 0x4F, 0x63, 0xB0, 0x07, 0x09, 0xA1,
+ 0x36, 0x4B, 0x3C, 0x24, 0x1D, 0xE3, 0xFE, 0xBF,
+ 0x07, 0x54, 0x04, 0x58, 0x97, 0x46, 0x7C, 0xD4
+ },
+ {
+ 0xE7, 0x4E, 0x90, 0x79, 0x20, 0xFD, 0x87, 0xBD,
+ 0x5A, 0xD6, 0x36, 0xDD, 0x11, 0x08, 0x5E, 0x50,
+ 0xEE, 0x70, 0x45, 0x9C, 0x44, 0x3E, 0x1C, 0xE5,
+ 0x80, 0x9A, 0xF2, 0xBC, 0x2E, 0xBA, 0x39, 0xF9,
+ 0xE6, 0xD7, 0x12, 0x8E, 0x0E, 0x37, 0x12, 0xC3,
+ 0x16, 0xDA, 0x06, 0xF4, 0x70, 0x5D, 0x78, 0xA4,
+ 0x83, 0x8E, 0x28, 0x12, 0x1D, 0x43, 0x44, 0xA2,
+ 0xC7, 0x9C, 0x5E, 0x0D, 0xB3, 0x07, 0xA6, 0x77
+ },
+ {
+ 0xBF, 0x91, 0xA2, 0x23, 0x34, 0xBA, 0xC2, 0x0F,
+ 0x3F, 0xD8, 0x06, 0x63, 0xB3, 0xCD, 0x06, 0xC4,
+ 0xE8, 0x80, 0x2F, 0x30, 0xE6, 0xB5, 0x9F, 0x90,
+ 0xD3, 0x03, 0x5C, 0xC9, 0x79, 0x8A, 0x21, 0x7E,
+ 0xD5, 0xA3, 0x1A, 0xBB, 0xDA, 0x7F, 0xA6, 0x84,
+ 0x28, 0x27, 0xBD, 0xF2, 0xA7, 0xA1, 0xC2, 0x1F,
+ 0x6F, 0xCF, 0xCC, 0xBB, 0x54, 0xC6, 0xC5, 0x29,
+ 0x26, 0xF3, 0x2D, 0xA8, 0x16, 0x26, 0x9B, 0xE1
+ },
+ {
+ 0xD9, 0xD5, 0xC7, 0x4B, 0xE5, 0x12, 0x1B, 0x0B,
+ 0xD7, 0x42, 0xF2, 0x6B, 0xFF, 0xB8, 0xC8, 0x9F,
+ 0x89, 0x17, 0x1F, 0x3F, 0x93, 0x49, 0x13, 0x49,
+ 0x2B, 0x09, 0x03, 0xC2, 0x71, 0xBB, 0xE2, 0xB3,
+ 0x39, 0x5E, 0xF2, 0x59, 0x66, 0x9B, 0xEF, 0x43,
+ 0xB5, 0x7F, 0x7F, 0xCC, 0x30, 0x27, 0xDB, 0x01,
+ 0x82, 0x3F, 0x6B, 0xAE, 0xE6, 0x6E, 0x4F, 0x9F,
+ 0xEA, 0xD4, 0xD6, 0x72, 0x6C, 0x74, 0x1F, 0xCE
+ },
+ {
+ 0x50, 0xC8, 0xB8, 0xCF, 0x34, 0xCD, 0x87, 0x9F,
+ 0x80, 0xE2, 0xFA, 0xAB, 0x32, 0x30, 0xB0, 0xC0,
+ 0xE1, 0xCC, 0x3E, 0x9D, 0xCA, 0xDE, 0xB1, 0xB9,
+ 0xD9, 0x7A, 0xB9, 0x23, 0x41, 0x5D, 0xD9, 0xA1,
+ 0xFE, 0x38, 0xAD, 0xDD, 0x5C, 0x11, 0x75, 0x6C,
+ 0x67, 0x99, 0x0B, 0x25, 0x6E, 0x95, 0xAD, 0x6D,
+ 0x8F, 0x9F, 0xED, 0xCE, 0x10, 0xBF, 0x1C, 0x90,
+ 0x67, 0x9C, 0xDE, 0x0E, 0xCF, 0x1B, 0xE3, 0x47
+ },
+ {
+ 0x0A, 0x38, 0x6E, 0x7C, 0xD5, 0xDD, 0x9B, 0x77,
+ 0xA0, 0x35, 0xE0, 0x9F, 0xE6, 0xFE, 0xE2, 0xC8,
+ 0xCE, 0x61, 0xB5, 0x38, 0x3C, 0x87, 0xEA, 0x43,
+ 0x20, 0x50, 0x59, 0xC5, 0xE4, 0xCD, 0x4F, 0x44,
+ 0x08, 0x31, 0x9B, 0xB0, 0xA8, 0x23, 0x60, 0xF6,
+ 0xA5, 0x8E, 0x6C, 0x9C, 0xE3, 0xF4, 0x87, 0xC4,
+ 0x46, 0x06, 0x3B, 0xF8, 0x13, 0xBC, 0x6B, 0xA5,
+ 0x35, 0xE1, 0x7F, 0xC1, 0x82, 0x6C, 0xFC, 0x91
+ },
+ {
+ 0x1F, 0x14, 0x59, 0xCB, 0x6B, 0x61, 0xCB, 0xAC,
+ 0x5F, 0x0E, 0xFE, 0x8F, 0xC4, 0x87, 0x53, 0x8F,
+ 0x42, 0x54, 0x89, 0x87, 0xFC, 0xD5, 0x62, 0x21,
+ 0xCF, 0xA7, 0xBE, 0xB2, 0x25, 0x04, 0x76, 0x9E,
+ 0x79, 0x2C, 0x45, 0xAD, 0xFB, 0x1D, 0x6B, 0x3D,
+ 0x60, 0xD7, 0xB7, 0x49, 0xC8, 0xA7, 0x5B, 0x0B,
+ 0xDF, 0x14, 0xE8, 0xEA, 0x72, 0x1B, 0x95, 0xDC,
+ 0xA5, 0x38, 0xCA, 0x6E, 0x25, 0x71, 0x12, 0x09
+ },
+ {
+ 0xE5, 0x8B, 0x38, 0x36, 0xB7, 0xD8, 0xFE, 0xDB,
+ 0xB5, 0x0C, 0xA5, 0x72, 0x5C, 0x65, 0x71, 0xE7,
+ 0x4C, 0x07, 0x85, 0xE9, 0x78, 0x21, 0xDA, 0xB8,
+ 0xB6, 0x29, 0x8C, 0x10, 0xE4, 0xC0, 0x79, 0xD4,
+ 0xA6, 0xCD, 0xF2, 0x2F, 0x0F, 0xED, 0xB5, 0x50,
+ 0x32, 0x92, 0x5C, 0x16, 0x74, 0x81, 0x15, 0xF0,
+ 0x1A, 0x10, 0x5E, 0x77, 0xE0, 0x0C, 0xEE, 0x3D,
+ 0x07, 0x92, 0x4D, 0xC0, 0xD8, 0xF9, 0x06, 0x59
+ },
+ {
+ 0xB9, 0x29, 0xCC, 0x65, 0x05, 0xF0, 0x20, 0x15,
+ 0x86, 0x72, 0xDE, 0xDA, 0x56, 0xD0, 0xDB, 0x08,
+ 0x1A, 0x2E, 0xE3, 0x4C, 0x00, 0xC1, 0x10, 0x00,
+ 0x29, 0xBD, 0xF8, 0xEA, 0x98, 0x03, 0x4F, 0xA4,
+ 0xBF, 0x3E, 0x86, 0x55, 0xEC, 0x69, 0x7F, 0xE3,
+ 0x6F, 0x40, 0x55, 0x3C, 0x5B, 0xB4, 0x68, 0x01,
+ 0x64, 0x4A, 0x62, 0x7D, 0x33, 0x42, 0xF4, 0xFC,
+ 0x92, 0xB6, 0x1F, 0x03, 0x29, 0x0F, 0xB3, 0x81
+ },
+ {
+ 0x72, 0xD3, 0x53, 0x99, 0x4B, 0x49, 0xD3, 0xE0,
+ 0x31, 0x53, 0x92, 0x9A, 0x1E, 0x4D, 0x4F, 0x18,
+ 0x8E, 0xE5, 0x8A, 0xB9, 0xE7, 0x2E, 0xE8, 0xE5,
+ 0x12, 0xF2, 0x9B, 0xC7, 0x73, 0x91, 0x38, 0x19,
+ 0xCE, 0x05, 0x7D, 0xDD, 0x70, 0x02, 0xC0, 0x43,
+ 0x3E, 0xE0, 0xA1, 0x61, 0x14, 0xE3, 0xD1, 0x56,
+ 0xDD, 0x2C, 0x4A, 0x7E, 0x80, 0xEE, 0x53, 0x37,
+ 0x8B, 0x86, 0x70, 0xF2, 0x3E, 0x33, 0xEF, 0x56
+ },
+ {
+ 0xC7, 0x0E, 0xF9, 0xBF, 0xD7, 0x75, 0xD4, 0x08,
+ 0x17, 0x67, 0x37, 0xA0, 0x73, 0x6D, 0x68, 0x51,
+ 0x7C, 0xE1, 0xAA, 0xAD, 0x7E, 0x81, 0xA9, 0x3C,
+ 0x8C, 0x1E, 0xD9, 0x67, 0xEA, 0x21, 0x4F, 0x56,
+ 0xC8, 0xA3, 0x77, 0xB1, 0x76, 0x3E, 0x67, 0x66,
+ 0x15, 0xB6, 0x0F, 0x39, 0x88, 0x24, 0x1E, 0xAE,
+ 0x6E, 0xAB, 0x96, 0x85, 0xA5, 0x12, 0x49, 0x29,
+ 0xD2, 0x81, 0x88, 0xF2, 0x9E, 0xAB, 0x06, 0xF7
+ },
+ {
+ 0xC2, 0x30, 0xF0, 0x80, 0x26, 0x79, 0xCB, 0x33,
+ 0x82, 0x2E, 0xF8, 0xB3, 0xB2, 0x1B, 0xF7, 0xA9,
+ 0xA2, 0x89, 0x42, 0x09, 0x29, 0x01, 0xD7, 0xDA,
+ 0xC3, 0x76, 0x03, 0x00, 0x83, 0x10, 0x26, 0xCF,
+ 0x35, 0x4C, 0x92, 0x32, 0xDF, 0x3E, 0x08, 0x4D,
+ 0x99, 0x03, 0x13, 0x0C, 0x60, 0x1F, 0x63, 0xC1,
+ 0xF4, 0xA4, 0xA4, 0xB8, 0x10, 0x6E, 0x46, 0x8C,
+ 0xD4, 0x43, 0xBB, 0xE5, 0xA7, 0x34, 0xF4, 0x5F
+ },
+ {
+ 0x6F, 0x43, 0x09, 0x4C, 0xAF, 0xB5, 0xEB, 0xF1,
+ 0xF7, 0xA4, 0x93, 0x7E, 0xC5, 0x0F, 0x56, 0xA4,
+ 0xC9, 0xDA, 0x30, 0x3C, 0xBB, 0x55, 0xAC, 0x1F,
+ 0x27, 0xF1, 0xF1, 0x97, 0x6C, 0xD9, 0x6B, 0xED,
+ 0xA9, 0x46, 0x4F, 0x0E, 0x7B, 0x9C, 0x54, 0x62,
+ 0x0B, 0x8A, 0x9F, 0xBA, 0x98, 0x31, 0x64, 0xB8,
+ 0xBE, 0x35, 0x78, 0x42, 0x5A, 0x02, 0x4F, 0x5F,
+ 0xE1, 0x99, 0xC3, 0x63, 0x56, 0xB8, 0x89, 0x72
+ },
+ {
+ 0x37, 0x45, 0x27, 0x3F, 0x4C, 0x38, 0x22, 0x5D,
+ 0xB2, 0x33, 0x73, 0x81, 0x87, 0x1A, 0x0C, 0x6A,
+ 0xAF, 0xD3, 0xAF, 0x9B, 0x01, 0x8C, 0x88, 0xAA,
+ 0x02, 0x02, 0x58, 0x50, 0xA5, 0xDC, 0x3A, 0x42,
+ 0xA1, 0xA3, 0xE0, 0x3E, 0x56, 0xCB, 0xF1, 0xB0,
+ 0x87, 0x6D, 0x63, 0xA4, 0x41, 0xF1, 0xD2, 0x85,
+ 0x6A, 0x39, 0xB8, 0x80, 0x1E, 0xB5, 0xAF, 0x32,
+ 0x52, 0x01, 0xC4, 0x15, 0xD6, 0x5E, 0x97, 0xFE
+ },
+ {
+ 0xC5, 0x0C, 0x44, 0xCC, 0xA3, 0xEC, 0x3E, 0xDA,
+ 0xAE, 0x77, 0x9A, 0x7E, 0x17, 0x94, 0x50, 0xEB,
+ 0xDD, 0xA2, 0xF9, 0x70, 0x67, 0xC6, 0x90, 0xAA,
+ 0x6C, 0x5A, 0x4A, 0xC7, 0xC3, 0x01, 0x39, 0xBB,
+ 0x27, 0xC0, 0xDF, 0x4D, 0xB3, 0x22, 0x0E, 0x63,
+ 0xCB, 0x11, 0x0D, 0x64, 0xF3, 0x7F, 0xFE, 0x07,
+ 0x8D, 0xB7, 0x26, 0x53, 0xE2, 0xDA, 0xAC, 0xF9,
+ 0x3A, 0xE3, 0xF0, 0xA2, 0xD1, 0xA7, 0xEB, 0x2E
+ },
+ {
+ 0x8A, 0xEF, 0x26, 0x3E, 0x38, 0x5C, 0xBC, 0x61,
+ 0xE1, 0x9B, 0x28, 0x91, 0x42, 0x43, 0x26, 0x2A,
+ 0xF5, 0xAF, 0xE8, 0x72, 0x6A, 0xF3, 0xCE, 0x39,
+ 0xA7, 0x9C, 0x27, 0x02, 0x8C, 0xF3, 0xEC, 0xD3,
+ 0xF8, 0xD2, 0xDF, 0xD9, 0xCF, 0xC9, 0xAD, 0x91,
+ 0xB5, 0x8F, 0x6F, 0x20, 0x77, 0x8F, 0xD5, 0xF0,
+ 0x28, 0x94, 0xA3, 0xD9, 0x1C, 0x7D, 0x57, 0xD1,
+ 0xE4, 0xB8, 0x66, 0xA7, 0xF3, 0x64, 0xB6, 0xBE
+ },
+ {
+ 0x28, 0x69, 0x61, 0x41, 0xDE, 0x6E, 0x2D, 0x9B,
+ 0xCB, 0x32, 0x35, 0x57, 0x8A, 0x66, 0x16, 0x6C,
+ 0x14, 0x48, 0xD3, 0xE9, 0x05, 0xA1, 0xB4, 0x82,
+ 0xD4, 0x23, 0xBE, 0x4B, 0xC5, 0x36, 0x9B, 0xC8,
+ 0xC7, 0x4D, 0xAE, 0x0A, 0xCC, 0x9C, 0xC1, 0x23,
+ 0xE1, 0xD8, 0xDD, 0xCE, 0x9F, 0x97, 0x91, 0x7E,
+ 0x8C, 0x01, 0x9C, 0x55, 0x2D, 0xA3, 0x2D, 0x39,
+ 0xD2, 0x21, 0x9B, 0x9A, 0xBF, 0x0F, 0xA8, 0xC8
+ },
+ {
+ 0x2F, 0xB9, 0xEB, 0x20, 0x85, 0x83, 0x01, 0x81,
+ 0x90, 0x3A, 0x9D, 0xAF, 0xE3, 0xDB, 0x42, 0x8E,
+ 0xE1, 0x5B, 0xE7, 0x66, 0x22, 0x24, 0xEF, 0xD6,
+ 0x43, 0x37, 0x1F, 0xB2, 0x56, 0x46, 0xAE, 0xE7,
+ 0x16, 0xE5, 0x31, 0xEC, 0xA6, 0x9B, 0x2B, 0xDC,
+ 0x82, 0x33, 0xF1, 0xA8, 0x08, 0x1F, 0xA4, 0x3D,
+ 0xA1, 0x50, 0x03, 0x02, 0x97, 0x5A, 0x77, 0xF4,
+ 0x2F, 0xA5, 0x92, 0x13, 0x67, 0x10, 0xE9, 0xDC
+ },
+ {
+ 0x66, 0xF9, 0xA7, 0x14, 0x3F, 0x7A, 0x33, 0x14,
+ 0xA6, 0x69, 0xBF, 0x2E, 0x24, 0xBB, 0xB3, 0x50,
+ 0x14, 0x26, 0x1D, 0x63, 0x9F, 0x49, 0x5B, 0x6C,
+ 0x9C, 0x1F, 0x10, 0x4F, 0xE8, 0xE3, 0x20, 0xAC,
+ 0xA6, 0x0D, 0x45, 0x50, 0xD6, 0x9D, 0x52, 0xED,
+ 0xBD, 0x5A, 0x3C, 0xDE, 0xB4, 0x01, 0x4A, 0xE6,
+ 0x5B, 0x1D, 0x87, 0xAA, 0x77, 0x0B, 0x69, 0xAE,
+ 0x5C, 0x15, 0xF4, 0x33, 0x0B, 0x0B, 0x0A, 0xD8
+ },
+ {
+ 0xF4, 0xC4, 0xDD, 0x1D, 0x59, 0x4C, 0x35, 0x65,
+ 0xE3, 0xE2, 0x5C, 0xA4, 0x3D, 0xAD, 0x82, 0xF6,
+ 0x2A, 0xBE, 0xA4, 0x83, 0x5E, 0xD4, 0xCD, 0x81,
+ 0x1B, 0xCD, 0x97, 0x5E, 0x46, 0x27, 0x98, 0x28,
+ 0xD4, 0x4D, 0x4C, 0x62, 0xC3, 0x67, 0x9F, 0x1B,
+ 0x7F, 0x7B, 0x9D, 0xD4, 0x57, 0x1D, 0x7B, 0x49,
+ 0x55, 0x73, 0x47, 0xB8, 0xC5, 0x46, 0x0C, 0xBD,
+ 0xC1, 0xBE, 0xF6, 0x90, 0xFB, 0x2A, 0x08, 0xC0
+ },
+ {
+ 0x8F, 0x1D, 0xC9, 0x64, 0x9C, 0x3A, 0x84, 0x55,
+ 0x1F, 0x8F, 0x6E, 0x91, 0xCA, 0xC6, 0x82, 0x42,
+ 0xA4, 0x3B, 0x1F, 0x8F, 0x32, 0x8E, 0xE9, 0x22,
+ 0x80, 0x25, 0x73, 0x87, 0xFA, 0x75, 0x59, 0xAA,
+ 0x6D, 0xB1, 0x2E, 0x4A, 0xEA, 0xDC, 0x2D, 0x26,
+ 0x09, 0x91, 0x78, 0x74, 0x9C, 0x68, 0x64, 0xB3,
+ 0x57, 0xF3, 0xF8, 0x3B, 0x2F, 0xB3, 0xEF, 0xA8,
+ 0xD2, 0xA8, 0xDB, 0x05, 0x6B, 0xED, 0x6B, 0xCC
+ },
+ {
+ 0x31, 0x39, 0xC1, 0xA7, 0xF9, 0x7A, 0xFD, 0x16,
+ 0x75, 0xD4, 0x60, 0xEB, 0xBC, 0x07, 0xF2, 0x72,
+ 0x8A, 0xA1, 0x50, 0xDF, 0x84, 0x96, 0x24, 0x51,
+ 0x1E, 0xE0, 0x4B, 0x74, 0x3B, 0xA0, 0xA8, 0x33,
+ 0x09, 0x2F, 0x18, 0xC1, 0x2D, 0xC9, 0x1B, 0x4D,
+ 0xD2, 0x43, 0xF3, 0x33, 0x40, 0x2F, 0x59, 0xFE,
+ 0x28, 0xAB, 0xDB, 0xBB, 0xAE, 0x30, 0x1E, 0x7B,
+ 0x65, 0x9C, 0x7A, 0x26, 0xD5, 0xC0, 0xF9, 0x79
+ },
+ {
+ 0x06, 0xF9, 0x4A, 0x29, 0x96, 0x15, 0x8A, 0x81,
+ 0x9F, 0xE3, 0x4C, 0x40, 0xDE, 0x3C, 0xF0, 0x37,
+ 0x9F, 0xD9, 0xFB, 0x85, 0xB3, 0xE3, 0x63, 0xBA,
+ 0x39, 0x26, 0xA0, 0xE7, 0xD9, 0x60, 0xE3, 0xF4,
+ 0xC2, 0xE0, 0xC7, 0x0C, 0x7C, 0xE0, 0xCC, 0xB2,
+ 0xA6, 0x4F, 0xC2, 0x98, 0x69, 0xF6, 0xE7, 0xAB,
+ 0x12, 0xBD, 0x4D, 0x3F, 0x14, 0xFC, 0xE9, 0x43,
+ 0x27, 0x90, 0x27, 0xE7, 0x85, 0xFB, 0x5C, 0x29
+ },
+ {
+ 0xC2, 0x9C, 0x39, 0x9E, 0xF3, 0xEE, 0xE8, 0x96,
+ 0x1E, 0x87, 0x56, 0x5C, 0x1C, 0xE2, 0x63, 0x92,
+ 0x5F, 0xC3, 0xD0, 0xCE, 0x26, 0x7D, 0x13, 0xE4,
+ 0x8D, 0xD9, 0xE7, 0x32, 0xEE, 0x67, 0xB0, 0xF6,
+ 0x9F, 0xAD, 0x56, 0x40, 0x1B, 0x0F, 0x10, 0xFC,
+ 0xAA, 0xC1, 0x19, 0x20, 0x10, 0x46, 0xCC, 0xA2,
+ 0x8C, 0x5B, 0x14, 0xAB, 0xDE, 0xA3, 0x21, 0x2A,
+ 0xE6, 0x55, 0x62, 0xF7, 0xF1, 0x38, 0xDB, 0x3D
+ },
+ {
+ 0x4C, 0xEC, 0x4C, 0x9D, 0xF5, 0x2E, 0xEF, 0x05,
+ 0xC3, 0xF6, 0xFA, 0xAA, 0x97, 0x91, 0xBC, 0x74,
+ 0x45, 0x93, 0x71, 0x83, 0x22, 0x4E, 0xCC, 0x37,
+ 0xA1, 0xE5, 0x8D, 0x01, 0x32, 0xD3, 0x56, 0x17,
+ 0x53, 0x1D, 0x7E, 0x79, 0x5F, 0x52, 0xAF, 0x7B,
+ 0x1E, 0xB9, 0xD1, 0x47, 0xDE, 0x12, 0x92, 0xD3,
+ 0x45, 0xFE, 0x34, 0x18, 0x23, 0xF8, 0xE6, 0xBC,
+ 0x1E, 0x5B, 0xAD, 0xCA, 0x5C, 0x65, 0x61, 0x08
+ },
+ {
+ 0x89, 0x8B, 0xFB, 0xAE, 0x93, 0xB3, 0xE1, 0x8D,
+ 0x00, 0x69, 0x7E, 0xAB, 0x7D, 0x97, 0x04, 0xFA,
+ 0x36, 0xEC, 0x33, 0x9D, 0x07, 0x61, 0x31, 0xCE,
+ 0xFD, 0xF3, 0x0E, 0xDB, 0xE8, 0xD9, 0xCC, 0x81,
+ 0xC3, 0xA8, 0x0B, 0x12, 0x96, 0x59, 0xB1, 0x63,
+ 0xA3, 0x23, 0xBA, 0xB9, 0x79, 0x3D, 0x4F, 0xEE,
+ 0xD9, 0x2D, 0x54, 0xDA, 0xE9, 0x66, 0xC7, 0x75,
+ 0x29, 0x76, 0x4A, 0x09, 0xBE, 0x88, 0xDB, 0x45
+ },
+ {
+ 0xEE, 0x9B, 0xD0, 0x46, 0x9D, 0x3A, 0xAF, 0x4F,
+ 0x14, 0x03, 0x5B, 0xE4, 0x8A, 0x2C, 0x3B, 0x84,
+ 0xD9, 0xB4, 0xB1, 0xFF, 0xF1, 0xD9, 0x45, 0xE1,
+ 0xF1, 0xC1, 0xD3, 0x89, 0x80, 0xA9, 0x51, 0xBE,
+ 0x19, 0x7B, 0x25, 0xFE, 0x22, 0xC7, 0x31, 0xF2,
+ 0x0A, 0xEA, 0xCC, 0x93, 0x0B, 0xA9, 0xC4, 0xA1,
+ 0xF4, 0x76, 0x22, 0x27, 0x61, 0x7A, 0xD3, 0x50,
+ 0xFD, 0xAB, 0xB4, 0xE8, 0x02, 0x73, 0xA0, 0xF4
+ },
+ {
+ 0x3D, 0x4D, 0x31, 0x13, 0x30, 0x05, 0x81, 0xCD,
+ 0x96, 0xAC, 0xBF, 0x09, 0x1C, 0x3D, 0x0F, 0x3C,
+ 0x31, 0x01, 0x38, 0xCD, 0x69, 0x79, 0xE6, 0x02,
+ 0x6C, 0xDE, 0x62, 0x3E, 0x2D, 0xD1, 0xB2, 0x4D,
+ 0x4A, 0x86, 0x38, 0xBE, 0xD1, 0x07, 0x33, 0x44,
+ 0x78, 0x3A, 0xD0, 0x64, 0x9C, 0xC6, 0x30, 0x5C,
+ 0xCE, 0xC0, 0x4B, 0xEB, 0x49, 0xF3, 0x1C, 0x63,
+ 0x30, 0x88, 0xA9, 0x9B, 0x65, 0x13, 0x02, 0x67
+ },
+ {
+ 0x95, 0xC0, 0x59, 0x1A, 0xD9, 0x1F, 0x92, 0x1A,
+ 0xC7, 0xBE, 0x6D, 0x9C, 0xE3, 0x7E, 0x06, 0x63,
+ 0xED, 0x80, 0x11, 0xC1, 0xCF, 0xD6, 0xD0, 0x16,
+ 0x2A, 0x55, 0x72, 0xE9, 0x43, 0x68, 0xBA, 0xC0,
+ 0x20, 0x24, 0x48, 0x5E, 0x6A, 0x39, 0x85, 0x4A,
+ 0xA4, 0x6F, 0xE3, 0x8E, 0x97, 0xD6, 0xC6, 0xB1,
+ 0x94, 0x7C, 0xD2, 0x72, 0xD8, 0x6B, 0x06, 0xBB,
+ 0x5B, 0x2F, 0x78, 0xB9, 0xB6, 0x8D, 0x55, 0x9D
+ },
+ {
+ 0x22, 0x7B, 0x79, 0xDE, 0xD3, 0x68, 0x15, 0x3B,
+ 0xF4, 0x6C, 0x0A, 0x3C, 0xA9, 0x78, 0xBF, 0xDB,
+ 0xEF, 0x31, 0xF3, 0x02, 0x4A, 0x56, 0x65, 0x84,
+ 0x24, 0x68, 0x49, 0x0B, 0x0F, 0xF7, 0x48, 0xAE,
+ 0x04, 0xE7, 0x83, 0x2E, 0xD4, 0xC9, 0xF4, 0x9D,
+ 0xE9, 0xB1, 0x70, 0x67, 0x09, 0xD6, 0x23, 0xE5,
+ 0xC8, 0xC1, 0x5E, 0x3C, 0xAE, 0xCA, 0xE8, 0xD5,
+ 0xE4, 0x33, 0x43, 0x0F, 0xF7, 0x2F, 0x20, 0xEB
+ },
+ {
+ 0x5D, 0x34, 0xF3, 0x95, 0x2F, 0x01, 0x05, 0xEE,
+ 0xF8, 0x8A, 0xE8, 0xB6, 0x4C, 0x6C, 0xE9, 0x5E,
+ 0xBF, 0xAD, 0xE0, 0xE0, 0x2C, 0x69, 0xB0, 0x87,
+ 0x62, 0xA8, 0x71, 0x2D, 0x2E, 0x49, 0x11, 0xAD,
+ 0x3F, 0x94, 0x1F, 0xC4, 0x03, 0x4D, 0xC9, 0xB2,
+ 0xE4, 0x79, 0xFD, 0xBC, 0xD2, 0x79, 0xB9, 0x02,
+ 0xFA, 0xF5, 0xD8, 0x38, 0xBB, 0x2E, 0x0C, 0x64,
+ 0x95, 0xD3, 0x72, 0xB5, 0xB7, 0x02, 0x98, 0x13
+ },
+ {
+ 0x7F, 0x93, 0x9B, 0xF8, 0x35, 0x3A, 0xBC, 0xE4,
+ 0x9E, 0x77, 0xF1, 0x4F, 0x37, 0x50, 0xAF, 0x20,
+ 0xB7, 0xB0, 0x39, 0x02, 0xE1, 0xA1, 0xE7, 0xFB,
+ 0x6A, 0xAF, 0x76, 0xD0, 0x25, 0x9C, 0xD4, 0x01,
+ 0xA8, 0x31, 0x90, 0xF1, 0x56, 0x40, 0xE7, 0x4F,
+ 0x3E, 0x6C, 0x5A, 0x90, 0xE8, 0x39, 0xC7, 0x82,
+ 0x1F, 0x64, 0x74, 0x75, 0x7F, 0x75, 0xC7, 0xBF,
+ 0x90, 0x02, 0x08, 0x4D, 0xDC, 0x7A, 0x62, 0xDC
+ },
+ {
+ 0x06, 0x2B, 0x61, 0xA2, 0xF9, 0xA3, 0x3A, 0x71,
+ 0xD7, 0xD0, 0xA0, 0x61, 0x19, 0x64, 0x4C, 0x70,
+ 0xB0, 0x71, 0x6A, 0x50, 0x4D, 0xE7, 0xE5, 0xE1,
+ 0xBE, 0x49, 0xBD, 0x7B, 0x86, 0xE7, 0xED, 0x68,
+ 0x17, 0x71, 0x4F, 0x9F, 0x0F, 0xC3, 0x13, 0xD0,
+ 0x61, 0x29, 0x59, 0x7E, 0x9A, 0x22, 0x35, 0xEC,
+ 0x85, 0x21, 0xDE, 0x36, 0xF7, 0x29, 0x0A, 0x90,
+ 0xCC, 0xFC, 0x1F, 0xFA, 0x6D, 0x0A, 0xEE, 0x29
+ },
+ {
+ 0xF2, 0x9E, 0x01, 0xEE, 0xAE, 0x64, 0x31, 0x1E,
+ 0xB7, 0xF1, 0xC6, 0x42, 0x2F, 0x94, 0x6B, 0xF7,
+ 0xBE, 0xA3, 0x63, 0x79, 0x52, 0x3E, 0x7B, 0x2B,
+ 0xBA, 0xBA, 0x7D, 0x1D, 0x34, 0xA2, 0x2D, 0x5E,
+ 0xA5, 0xF1, 0xC5, 0xA0, 0x9D, 0x5C, 0xE1, 0xFE,
+ 0x68, 0x2C, 0xCE, 0xD9, 0xA4, 0x79, 0x8D, 0x1A,
+ 0x05, 0xB4, 0x6C, 0xD7, 0x2D, 0xFF, 0x5C, 0x1B,
+ 0x35, 0x54, 0x40, 0xB2, 0xA2, 0xD4, 0x76, 0xBC
+ },
+ {
+ 0xEC, 0x38, 0xCD, 0x3B, 0xBA, 0xB3, 0xEF, 0x35,
+ 0xD7, 0xCB, 0x6D, 0x5C, 0x91, 0x42, 0x98, 0x35,
+ 0x1D, 0x8A, 0x9D, 0xC9, 0x7F, 0xCE, 0xE0, 0x51,
+ 0xA8, 0xA0, 0x2F, 0x58, 0xE3, 0xED, 0x61, 0x84,
+ 0xD0, 0xB7, 0x81, 0x0A, 0x56, 0x15, 0x41, 0x1A,
+ 0xB1, 0xB9, 0x52, 0x09, 0xC3, 0xC8, 0x10, 0x11,
+ 0x4F, 0xDE, 0xB2, 0x24, 0x52, 0x08, 0x4E, 0x77,
+ 0xF3, 0xF8, 0x47, 0xC6, 0xDB, 0xAA, 0xFE, 0x16
+ },
+ {
+ 0xC2, 0xAE, 0xF5, 0xE0, 0xCA, 0x43, 0xE8, 0x26,
+ 0x41, 0x56, 0x5B, 0x8C, 0xB9, 0x43, 0xAA, 0x8B,
+ 0xA5, 0x35, 0x50, 0xCA, 0xEF, 0x79, 0x3B, 0x65,
+ 0x32, 0xFA, 0xFA, 0xD9, 0x4B, 0x81, 0x60, 0x82,
+ 0xF0, 0x11, 0x3A, 0x3E, 0xA2, 0xF6, 0x36, 0x08,
+ 0xAB, 0x40, 0x43, 0x7E, 0xCC, 0x0F, 0x02, 0x29,
+ 0xCB, 0x8F, 0xA2, 0x24, 0xDC, 0xF1, 0xC4, 0x78,
+ 0xA6, 0x7D, 0x9B, 0x64, 0x16, 0x2B, 0x92, 0xD1
+ },
+ {
+ 0x15, 0xF5, 0x34, 0xEF, 0xFF, 0x71, 0x05, 0xCD,
+ 0x1C, 0x25, 0x4D, 0x07, 0x4E, 0x27, 0xD5, 0x89,
+ 0x8B, 0x89, 0x31, 0x3B, 0x7D, 0x36, 0x6D, 0xC2,
+ 0xD7, 0xD8, 0x71, 0x13, 0xFA, 0x7D, 0x53, 0xAA,
+ 0xE1, 0x3F, 0x6D, 0xBA, 0x48, 0x7A, 0xD8, 0x10,
+ 0x3D, 0x5E, 0x85, 0x4C, 0x91, 0xFD, 0xB6, 0xE1,
+ 0xE7, 0x4B, 0x2E, 0xF6, 0xD1, 0x43, 0x17, 0x69,
+ 0xC3, 0x07, 0x67, 0xDD, 0xE0, 0x67, 0xA3, 0x5C
+ },
+ {
+ 0x89, 0xAC, 0xBC, 0xA0, 0xB1, 0x69, 0x89, 0x7A,
+ 0x0A, 0x27, 0x14, 0xC2, 0xDF, 0x8C, 0x95, 0xB5,
+ 0xB7, 0x9C, 0xB6, 0x93, 0x90, 0x14, 0x2B, 0x7D,
+ 0x60, 0x18, 0xBB, 0x3E, 0x30, 0x76, 0xB0, 0x99,
+ 0xB7, 0x9A, 0x96, 0x41, 0x52, 0xA9, 0xD9, 0x12,
+ 0xB1, 0xB8, 0x64, 0x12, 0xB7, 0xE3, 0x72, 0xE9,
+ 0xCE, 0xCA, 0xD7, 0xF2, 0x5D, 0x4C, 0xBA, 0xB8,
+ 0xA3, 0x17, 0xBE, 0x36, 0x49, 0x2A, 0x67, 0xD7
+ },
+ {
+ 0xE3, 0xC0, 0x73, 0x91, 0x90, 0xED, 0x84, 0x9C,
+ 0x9C, 0x96, 0x2F, 0xD9, 0xDB, 0xB5, 0x5E, 0x20,
+ 0x7E, 0x62, 0x4F, 0xCA, 0xC1, 0xEB, 0x41, 0x76,
+ 0x91, 0x51, 0x54, 0x99, 0xEE, 0xA8, 0xD8, 0x26,
+ 0x7B, 0x7E, 0x8F, 0x12, 0x87, 0xA6, 0x36, 0x33,
+ 0xAF, 0x50, 0x11, 0xFD, 0xE8, 0xC4, 0xDD, 0xF5,
+ 0x5B, 0xFD, 0xF7, 0x22, 0xED, 0xF8, 0x88, 0x31,
+ 0x41, 0x4F, 0x2C, 0xFA, 0xED, 0x59, 0xCB, 0x9A
+ },
+ {
+ 0x8D, 0x6C, 0xF8, 0x7C, 0x08, 0x38, 0x0D, 0x2D,
+ 0x15, 0x06, 0xEE, 0xE4, 0x6F, 0xD4, 0x22, 0x2D,
+ 0x21, 0xD8, 0xC0, 0x4E, 0x58, 0x5F, 0xBF, 0xD0,
+ 0x82, 0x69, 0xC9, 0x8F, 0x70, 0x28, 0x33, 0xA1,
+ 0x56, 0x32, 0x6A, 0x07, 0x24, 0x65, 0x64, 0x00,
+ 0xEE, 0x09, 0x35, 0x1D, 0x57, 0xB4, 0x40, 0x17,
+ 0x5E, 0x2A, 0x5D, 0xE9, 0x3C, 0xC5, 0xF8, 0x0D,
+ 0xB6, 0xDA, 0xF8, 0x35, 0x76, 0xCF, 0x75, 0xFA
+ },
+ {
+ 0xDA, 0x24, 0xBE, 0xDE, 0x38, 0x36, 0x66, 0xD5,
+ 0x63, 0xEE, 0xED, 0x37, 0xF6, 0x31, 0x9B, 0xAF,
+ 0x20, 0xD5, 0xC7, 0x5D, 0x16, 0x35, 0xA6, 0xBA,
+ 0x5E, 0xF4, 0xCF, 0xA1, 0xAC, 0x95, 0x48, 0x7E,
+ 0x96, 0xF8, 0xC0, 0x8A, 0xF6, 0x00, 0xAA, 0xB8,
+ 0x7C, 0x98, 0x6E, 0xBA, 0xD4, 0x9F, 0xC7, 0x0A,
+ 0x58, 0xB4, 0x89, 0x0B, 0x9C, 0x87, 0x6E, 0x09,
+ 0x10, 0x16, 0xDA, 0xF4, 0x9E, 0x1D, 0x32, 0x2E
+ },
+ {
+ 0xF9, 0xD1, 0xD1, 0xB1, 0xE8, 0x7E, 0xA7, 0xAE,
+ 0x75, 0x3A, 0x02, 0x97, 0x50, 0xCC, 0x1C, 0xF3,
+ 0xD0, 0x15, 0x7D, 0x41, 0x80, 0x5E, 0x24, 0x5C,
+ 0x56, 0x17, 0xBB, 0x93, 0x4E, 0x73, 0x2F, 0x0A,
+ 0xE3, 0x18, 0x0B, 0x78, 0xE0, 0x5B, 0xFE, 0x76,
+ 0xC7, 0xC3, 0x05, 0x1E, 0x3E, 0x3A, 0xC7, 0x8B,
+ 0x9B, 0x50, 0xC0, 0x51, 0x42, 0x65, 0x7E, 0x1E,
+ 0x03, 0x21, 0x5D, 0x6E, 0xC7, 0xBF, 0xD0, 0xFC
+ },
+ {
+ 0x11, 0xB7, 0xBC, 0x16, 0x68, 0x03, 0x20, 0x48,
+ 0xAA, 0x43, 0x34, 0x3D, 0xE4, 0x76, 0x39, 0x5E,
+ 0x81, 0x4B, 0xBB, 0xC2, 0x23, 0x67, 0x8D, 0xB9,
+ 0x51, 0xA1, 0xB0, 0x3A, 0x02, 0x1E, 0xFA, 0xC9,
+ 0x48, 0xCF, 0xBE, 0x21, 0x5F, 0x97, 0xFE, 0x9A,
+ 0x72, 0xA2, 0xF6, 0xBC, 0x03, 0x9E, 0x39, 0x56,
+ 0xBF, 0xA4, 0x17, 0xC1, 0xA9, 0xF1, 0x0D, 0x6D,
+ 0x7B, 0xA5, 0xD3, 0xD3, 0x2F, 0xF3, 0x23, 0xE5
+ },
+ {
+ 0xB8, 0xD9, 0x00, 0x0E, 0x4F, 0xC2, 0xB0, 0x66,
+ 0xED, 0xB9, 0x1A, 0xFE, 0xE8, 0xE7, 0xEB, 0x0F,
+ 0x24, 0xE3, 0xA2, 0x01, 0xDB, 0x8B, 0x67, 0x93,
+ 0xC0, 0x60, 0x85, 0x81, 0xE6, 0x28, 0xED, 0x0B,
+ 0xCC, 0x4E, 0x5A, 0xA6, 0x78, 0x79, 0x92, 0xA4,
+ 0xBC, 0xC4, 0x4E, 0x28, 0x80, 0x93, 0xE6, 0x3E,
+ 0xE8, 0x3A, 0xBD, 0x0B, 0xC3, 0xEC, 0x6D, 0x09,
+ 0x34, 0xA6, 0x74, 0xA4, 0xDA, 0x13, 0x83, 0x8A
+ },
+ {
+ 0xCE, 0x32, 0x5E, 0x29, 0x4F, 0x9B, 0x67, 0x19,
+ 0xD6, 0xB6, 0x12, 0x78, 0x27, 0x6A, 0xE0, 0x6A,
+ 0x25, 0x64, 0xC0, 0x3B, 0xB0, 0xB7, 0x83, 0xFA,
+ 0xFE, 0x78, 0x5B, 0xDF, 0x89, 0xC7, 0xD5, 0xAC,
+ 0xD8, 0x3E, 0x78, 0x75, 0x6D, 0x30, 0x1B, 0x44,
+ 0x56, 0x99, 0x02, 0x4E, 0xAE, 0xB7, 0x7B, 0x54,
+ 0xD4, 0x77, 0x33, 0x6E, 0xC2, 0xA4, 0xF3, 0x32,
+ 0xF2, 0xB3, 0xF8, 0x87, 0x65, 0xDD, 0xB0, 0xC3
+ },
+ {
+ 0x29, 0xAC, 0xC3, 0x0E, 0x96, 0x03, 0xAE, 0x2F,
+ 0xCC, 0xF9, 0x0B, 0xF9, 0x7E, 0x6C, 0xC4, 0x63,
+ 0xEB, 0xE2, 0x8C, 0x1B, 0x2F, 0x9B, 0x4B, 0x76,
+ 0x5E, 0x70, 0x53, 0x7C, 0x25, 0xC7, 0x02, 0xA2,
+ 0x9D, 0xCB, 0xFB, 0xF1, 0x4C, 0x99, 0xC5, 0x43,
+ 0x45, 0xBA, 0x2B, 0x51, 0xF1, 0x7B, 0x77, 0xB5,
+ 0xF1, 0x5D, 0xB9, 0x2B, 0xBA, 0xD8, 0xFA, 0x95,
+ 0xC4, 0x71, 0xF5, 0xD0, 0x70, 0xA1, 0x37, 0xCC
+ },
+ {
+ 0x33, 0x79, 0xCB, 0xAA, 0xE5, 0x62, 0xA8, 0x7B,
+ 0x4C, 0x04, 0x25, 0x55, 0x0F, 0xFD, 0xD6, 0xBF,
+ 0xE1, 0x20, 0x3F, 0x0D, 0x66, 0x6C, 0xC7, 0xEA,
+ 0x09, 0x5B, 0xE4, 0x07, 0xA5, 0xDF, 0xE6, 0x1E,
+ 0xE9, 0x14, 0x41, 0xCD, 0x51, 0x54, 0xB3, 0xE5,
+ 0x3B, 0x4F, 0x5F, 0xB3, 0x1A, 0xD4, 0xC7, 0xA9,
+ 0xAD, 0x5C, 0x7A, 0xF4, 0xAE, 0x67, 0x9A, 0xA5,
+ 0x1A, 0x54, 0x00, 0x3A, 0x54, 0xCA, 0x6B, 0x2D
+ },
+ {
+ 0x30, 0x95, 0xA3, 0x49, 0xD2, 0x45, 0x70, 0x8C,
+ 0x7C, 0xF5, 0x50, 0x11, 0x87, 0x03, 0xD7, 0x30,
+ 0x2C, 0x27, 0xB6, 0x0A, 0xF5, 0xD4, 0xE6, 0x7F,
+ 0xC9, 0x78, 0xF8, 0xA4, 0xE6, 0x09, 0x53, 0xC7,
+ 0xA0, 0x4F, 0x92, 0xFC, 0xF4, 0x1A, 0xEE, 0x64,
+ 0x32, 0x1C, 0xCB, 0x70, 0x7A, 0x89, 0x58, 0x51,
+ 0x55, 0x2B, 0x1E, 0x37, 0xB0, 0x0B, 0xC5, 0xE6,
+ 0xB7, 0x2F, 0xA5, 0xBC, 0xEF, 0x9E, 0x3F, 0xFF
+ },
+ {
+ 0x07, 0x26, 0x2D, 0x73, 0x8B, 0x09, 0x32, 0x1F,
+ 0x4D, 0xBC, 0xCE, 0xC4, 0xBB, 0x26, 0xF4, 0x8C,
+ 0xB0, 0xF0, 0xED, 0x24, 0x6C, 0xE0, 0xB3, 0x1B,
+ 0x9A, 0x6E, 0x7B, 0xC6, 0x83, 0x04, 0x9F, 0x1F,
+ 0x3E, 0x55, 0x45, 0xF2, 0x8C, 0xE9, 0x32, 0xDD,
+ 0x98, 0x5C, 0x5A, 0xB0, 0xF4, 0x3B, 0xD6, 0xDE,
+ 0x07, 0x70, 0x56, 0x0A, 0xF3, 0x29, 0x06, 0x5E,
+ 0xD2, 0xE4, 0x9D, 0x34, 0x62, 0x4C, 0x2C, 0xBB
+ },
+ {
+ 0xB6, 0x40, 0x5E, 0xCA, 0x8E, 0xE3, 0x31, 0x6C,
+ 0x87, 0x06, 0x1C, 0xC6, 0xEC, 0x18, 0xDB, 0xA5,
+ 0x3E, 0x6C, 0x25, 0x0C, 0x63, 0xBA, 0x1F, 0x3B,
+ 0xAE, 0x9E, 0x55, 0xDD, 0x34, 0x98, 0x03, 0x6A,
+ 0xF0, 0x8C, 0xD2, 0x72, 0xAA, 0x24, 0xD7, 0x13,
+ 0xC6, 0x02, 0x0D, 0x77, 0xAB, 0x2F, 0x39, 0x19,
+ 0xAF, 0x1A, 0x32, 0xF3, 0x07, 0x42, 0x06, 0x18,
+ 0xAB, 0x97, 0xE7, 0x39, 0x53, 0x99, 0x4F, 0xB4
+ },
+ {
+ 0x7E, 0xE6, 0x82, 0xF6, 0x31, 0x48, 0xEE, 0x45,
+ 0xF6, 0xE5, 0x31, 0x5D, 0xA8, 0x1E, 0x5C, 0x6E,
+ 0x55, 0x7C, 0x2C, 0x34, 0x64, 0x1F, 0xC5, 0x09,
+ 0xC7, 0xA5, 0x70, 0x10, 0x88, 0xC3, 0x8A, 0x74,
+ 0x75, 0x61, 0x68, 0xE2, 0xCD, 0x8D, 0x35, 0x1E,
+ 0x88, 0xFD, 0x1A, 0x45, 0x1F, 0x36, 0x0A, 0x01,
+ 0xF5, 0xB2, 0x58, 0x0F, 0x9B, 0x5A, 0x2E, 0x8C,
+ 0xFC, 0x13, 0x8F, 0x3D, 0xD5, 0x9A, 0x3F, 0xFC
+ },
+ {
+ 0x1D, 0x26, 0x3C, 0x17, 0x9D, 0x6B, 0x26, 0x8F,
+ 0x6F, 0xA0, 0x16, 0xF3, 0xA4, 0xF2, 0x9E, 0x94,
+ 0x38, 0x91, 0x12, 0x5E, 0xD8, 0x59, 0x3C, 0x81,
+ 0x25, 0x60, 0x59, 0xF5, 0xA7, 0xB4, 0x4A, 0xF2,
+ 0xDC, 0xB2, 0x03, 0x0D, 0x17, 0x5C, 0x00, 0xE6,
+ 0x2E, 0xCA, 0xF7, 0xEE, 0x96, 0x68, 0x2A, 0xA0,
+ 0x7A, 0xB2, 0x0A, 0x61, 0x10, 0x24, 0xA2, 0x85,
+ 0x32, 0xB1, 0xC2, 0x5B, 0x86, 0x65, 0x79, 0x02
+ },
+ {
+ 0x10, 0x6D, 0x13, 0x2C, 0xBD, 0xB4, 0xCD, 0x25,
+ 0x97, 0x81, 0x28, 0x46, 0xE2, 0xBC, 0x1B, 0xF7,
+ 0x32, 0xFE, 0xC5, 0xF0, 0xA5, 0xF6, 0x5D, 0xBB,
+ 0x39, 0xEC, 0x4E, 0x6D, 0xC6, 0x4A, 0xB2, 0xCE,
+ 0x6D, 0x24, 0x63, 0x0D, 0x0F, 0x15, 0xA8, 0x05,
+ 0xC3, 0x54, 0x00, 0x25, 0xD8, 0x4A, 0xFA, 0x98,
+ 0xE3, 0x67, 0x03, 0xC3, 0xDB, 0xEE, 0x71, 0x3E,
+ 0x72, 0xDD, 0xE8, 0x46, 0x5B, 0xC1, 0xBE, 0x7E
+ },
+ {
+ 0x0E, 0x79, 0x96, 0x82, 0x26, 0x65, 0x06, 0x67,
+ 0xA8, 0xD8, 0x62, 0xEA, 0x8D, 0xA4, 0x89, 0x1A,
+ 0xF5, 0x6A, 0x4E, 0x3A, 0x8B, 0x6D, 0x17, 0x50,
+ 0xE3, 0x94, 0xF0, 0xDE, 0xA7, 0x6D, 0x64, 0x0D,
+ 0x85, 0x07, 0x7B, 0xCE, 0xC2, 0xCC, 0x86, 0x88,
+ 0x6E, 0x50, 0x67, 0x51, 0xB4, 0xF6, 0xA5, 0x83,
+ 0x8F, 0x7F, 0x0B, 0x5F, 0xEF, 0x76, 0x5D, 0x9D,
+ 0xC9, 0x0D, 0xCD, 0xCB, 0xAF, 0x07, 0x9F, 0x08
+ },
+ {
+ 0x52, 0x11, 0x56, 0xA8, 0x2A, 0xB0, 0xC4, 0xE5,
+ 0x66, 0xE5, 0x84, 0x4D, 0x5E, 0x31, 0xAD, 0x9A,
+ 0xAF, 0x14, 0x4B, 0xBD, 0x5A, 0x46, 0x4F, 0xDC,
+ 0xA3, 0x4D, 0xBD, 0x57, 0x17, 0xE8, 0xFF, 0x71,
+ 0x1D, 0x3F, 0xFE, 0xBB, 0xFA, 0x08, 0x5D, 0x67,
+ 0xFE, 0x99, 0x6A, 0x34, 0xF6, 0xD3, 0xE4, 0xE6,
+ 0x0B, 0x13, 0x96, 0xBF, 0x4B, 0x16, 0x10, 0xC2,
+ 0x63, 0xBD, 0xBB, 0x83, 0x4D, 0x56, 0x08, 0x16
+ },
+ {
+ 0x1A, 0xBA, 0x88, 0xBE, 0xFC, 0x55, 0xBC, 0x25,
+ 0xEF, 0xBC, 0xE0, 0x2D, 0xB8, 0xB9, 0x93, 0x3E,
+ 0x46, 0xF5, 0x76, 0x61, 0xBA, 0xEA, 0xBE, 0xB2,
+ 0x1C, 0xC2, 0x57, 0x4D, 0x2A, 0x51, 0x8A, 0x3C,
+ 0xBA, 0x5D, 0xC5, 0xA3, 0x8E, 0x49, 0x71, 0x34,
+ 0x40, 0xB2, 0x5F, 0x9C, 0x74, 0x4E, 0x75, 0xF6,
+ 0xB8, 0x5C, 0x9D, 0x8F, 0x46, 0x81, 0xF6, 0x76,
+ 0x16, 0x0F, 0x61, 0x05, 0x35, 0x7B, 0x84, 0x06
+ },
+ {
+ 0x5A, 0x99, 0x49, 0xFC, 0xB2, 0xC4, 0x73, 0xCD,
+ 0xA9, 0x68, 0xAC, 0x1B, 0x5D, 0x08, 0x56, 0x6D,
+ 0xC2, 0xD8, 0x16, 0xD9, 0x60, 0xF5, 0x7E, 0x63,
+ 0xB8, 0x98, 0xFA, 0x70, 0x1C, 0xF8, 0xEB, 0xD3,
+ 0xF5, 0x9B, 0x12, 0x4D, 0x95, 0xBF, 0xBB, 0xED,
+ 0xC5, 0xF1, 0xCF, 0x0E, 0x17, 0xD5, 0xEA, 0xED,
+ 0x0C, 0x02, 0xC5, 0x0B, 0x69, 0xD8, 0xA4, 0x02,
+ 0xCA, 0xBC, 0xCA, 0x44, 0x33, 0xB5, 0x1F, 0xD4
+ },
+ {
+ 0xB0, 0xCE, 0xAD, 0x09, 0x80, 0x7C, 0x67, 0x2A,
+ 0xF2, 0xEB, 0x2B, 0x0F, 0x06, 0xDD, 0xE4, 0x6C,
+ 0xF5, 0x37, 0x0E, 0x15, 0xA4, 0x09, 0x6B, 0x1A,
+ 0x7D, 0x7C, 0xBB, 0x36, 0xEC, 0x31, 0xC2, 0x05,
+ 0xFB, 0xEF, 0xCA, 0x00, 0xB7, 0xA4, 0x16, 0x2F,
+ 0xA8, 0x9F, 0xB4, 0xFB, 0x3E, 0xB7, 0x8D, 0x79,
+ 0x77, 0x0C, 0x23, 0xF4, 0x4E, 0x72, 0x06, 0x66,
+ 0x4C, 0xE3, 0xCD, 0x93, 0x1C, 0x29, 0x1E, 0x5D
+ },
+ {
+ 0xBB, 0x66, 0x64, 0x93, 0x1E, 0xC9, 0x70, 0x44,
+ 0xE4, 0x5B, 0x2A, 0xE4, 0x20, 0xAE, 0x1C, 0x55,
+ 0x1A, 0x88, 0x74, 0xBC, 0x93, 0x7D, 0x08, 0xE9,
+ 0x69, 0x39, 0x9C, 0x39, 0x64, 0xEB, 0xDB, 0xA8,
+ 0x34, 0x6C, 0xDD, 0x5D, 0x09, 0xCA, 0xAF, 0xE4,
+ 0xC2, 0x8B, 0xA7, 0xEC, 0x78, 0x81, 0x91, 0xCE,
+ 0xCA, 0x65, 0xDD, 0xD6, 0xF9, 0x5F, 0x18, 0x58,
+ 0x3E, 0x04, 0x0D, 0x0F, 0x30, 0xD0, 0x36, 0x4D
+ },
+ {
+ 0x65, 0xBC, 0x77, 0x0A, 0x5F, 0xAA, 0x37, 0x92,
+ 0x36, 0x98, 0x03, 0x68, 0x3E, 0x84, 0x4B, 0x0B,
+ 0xE7, 0xEE, 0x96, 0xF2, 0x9F, 0x6D, 0x6A, 0x35,
+ 0x56, 0x80, 0x06, 0xBD, 0x55, 0x90, 0xF9, 0xA4,
+ 0xEF, 0x63, 0x9B, 0x7A, 0x80, 0x61, 0xC7, 0xB0,
+ 0x42, 0x4B, 0x66, 0xB6, 0x0A, 0xC3, 0x4A, 0xF3,
+ 0x11, 0x99, 0x05, 0xF3, 0x3A, 0x9D, 0x8C, 0x3A,
+ 0xE1, 0x83, 0x82, 0xCA, 0x9B, 0x68, 0x99, 0x00
+ },
+ {
+ 0xEA, 0x9B, 0x4D, 0xCA, 0x33, 0x33, 0x36, 0xAA,
+ 0xF8, 0x39, 0xA4, 0x5C, 0x6E, 0xAA, 0x48, 0xB8,
+ 0xCB, 0x4C, 0x7D, 0xDA, 0xBF, 0xFE, 0xA4, 0xF6,
+ 0x43, 0xD6, 0x35, 0x7E, 0xA6, 0x62, 0x8A, 0x48,
+ 0x0A, 0x5B, 0x45, 0xF2, 0xB0, 0x52, 0xC1, 0xB0,
+ 0x7D, 0x1F, 0xED, 0xCA, 0x91, 0x8B, 0x6F, 0x11,
+ 0x39, 0xD8, 0x0F, 0x74, 0xC2, 0x45, 0x10, 0xDC,
+ 0xBA, 0xA4, 0xBE, 0x70, 0xEA, 0xCC, 0x1B, 0x06
+ },
+ {
+ 0xE6, 0x34, 0x2F, 0xB4, 0xA7, 0x80, 0xAD, 0x97,
+ 0x5D, 0x0E, 0x24, 0xBC, 0xE1, 0x49, 0x98, 0x9B,
+ 0x91, 0xD3, 0x60, 0x55, 0x7E, 0x87, 0x99, 0x4F,
+ 0x6B, 0x45, 0x7B, 0x89, 0x55, 0x75, 0xCC, 0x02,
+ 0xD0, 0xC1, 0x5B, 0xAD, 0x3C, 0xE7, 0x57, 0x7F,
+ 0x4C, 0x63, 0x92, 0x7F, 0xF1, 0x3F, 0x3E, 0x38,
+ 0x1F, 0xF7, 0xE7, 0x2B, 0xDB, 0xE7, 0x45, 0x32,
+ 0x48, 0x44, 0xA9, 0xD2, 0x7E, 0x3F, 0x1C, 0x01
+ },
+ {
+ 0x3E, 0x20, 0x9C, 0x9B, 0x33, 0xE8, 0xE4, 0x61,
+ 0x17, 0x8A, 0xB4, 0x6B, 0x1C, 0x64, 0xB4, 0x9A,
+ 0x07, 0xFB, 0x74, 0x5F, 0x1C, 0x8B, 0xC9, 0x5F,
+ 0xBF, 0xB9, 0x4C, 0x6B, 0x87, 0xC6, 0x95, 0x16,
+ 0x65, 0x1B, 0x26, 0x4E, 0xF9, 0x80, 0x93, 0x7F,
+ 0xAD, 0x41, 0x23, 0x8B, 0x91, 0xDD, 0xC0, 0x11,
+ 0xA5, 0xDD, 0x77, 0x7C, 0x7E, 0xFD, 0x44, 0x94,
+ 0xB4, 0xB6, 0xEC, 0xD3, 0xA9, 0xC2, 0x2A, 0xC0
+ },
+ {
+ 0xFD, 0x6A, 0x3D, 0x5B, 0x18, 0x75, 0xD8, 0x04,
+ 0x86, 0xD6, 0xE6, 0x96, 0x94, 0xA5, 0x6D, 0xBB,
+ 0x04, 0xA9, 0x9A, 0x4D, 0x05, 0x1F, 0x15, 0xDB,
+ 0x26, 0x89, 0x77, 0x6B, 0xA1, 0xC4, 0x88, 0x2E,
+ 0x6D, 0x46, 0x2A, 0x60, 0x3B, 0x70, 0x15, 0xDC,
+ 0x9F, 0x4B, 0x74, 0x50, 0xF0, 0x53, 0x94, 0x30,
+ 0x3B, 0x86, 0x52, 0xCF, 0xB4, 0x04, 0xA2, 0x66,
+ 0x96, 0x2C, 0x41, 0xBA, 0xE6, 0xE1, 0x8A, 0x94
+ },
+ {
+ 0x95, 0x1E, 0x27, 0x51, 0x7E, 0x6B, 0xAD, 0x9E,
+ 0x41, 0x95, 0xFC, 0x86, 0x71, 0xDE, 0xE3, 0xE7,
+ 0xE9, 0xBE, 0x69, 0xCE, 0xE1, 0x42, 0x2C, 0xB9,
+ 0xFE, 0xCF, 0xCE, 0x0D, 0xBA, 0x87, 0x5F, 0x7B,
+ 0x31, 0x0B, 0x93, 0xEE, 0x3A, 0x3D, 0x55, 0x8F,
+ 0x94, 0x1F, 0x63, 0x5F, 0x66, 0x8F, 0xF8, 0x32,
+ 0xD2, 0xC1, 0xD0, 0x33, 0xC5, 0xE2, 0xF0, 0x99,
+ 0x7E, 0x4C, 0x66, 0xF1, 0x47, 0x34, 0x4E, 0x02
+ },
+ {
+ 0x8E, 0xBA, 0x2F, 0x87, 0x4F, 0x1A, 0xE8, 0x40,
+ 0x41, 0x90, 0x3C, 0x7C, 0x42, 0x53, 0xC8, 0x22,
+ 0x92, 0x53, 0x0F, 0xC8, 0x50, 0x95, 0x50, 0xBF,
+ 0xDC, 0x34, 0xC9, 0x5C, 0x7E, 0x28, 0x89, 0xD5,
+ 0x65, 0x0B, 0x0A, 0xD8, 0xCB, 0x98, 0x8E, 0x5C,
+ 0x48, 0x94, 0xCB, 0x87, 0xFB, 0xFB, 0xB1, 0x96,
+ 0x12, 0xEA, 0x93, 0xCC, 0xC4, 0xC5, 0xCA, 0xD1,
+ 0x71, 0x58, 0xB9, 0x76, 0x34, 0x64, 0xB4, 0x92
+ },
+ {
+ 0x16, 0xF7, 0x12, 0xEA, 0xA1, 0xB7, 0xC6, 0x35,
+ 0x47, 0x19, 0xA8, 0xE7, 0xDB, 0xDF, 0xAF, 0x55,
+ 0xE4, 0x06, 0x3A, 0x4D, 0x27, 0x7D, 0x94, 0x75,
+ 0x50, 0x01, 0x9B, 0x38, 0xDF, 0xB5, 0x64, 0x83,
+ 0x09, 0x11, 0x05, 0x7D, 0x50, 0x50, 0x61, 0x36,
+ 0xE2, 0x39, 0x4C, 0x3B, 0x28, 0x94, 0x5C, 0xC9,
+ 0x64, 0x96, 0x7D, 0x54, 0xE3, 0x00, 0x0C, 0x21,
+ 0x81, 0x62, 0x6C, 0xFB, 0x9B, 0x73, 0xEF, 0xD2
+ },
+ {
+ 0xC3, 0x96, 0x39, 0xE7, 0xD5, 0xC7, 0xFB, 0x8C,
+ 0xDD, 0x0F, 0xD3, 0xE6, 0xA5, 0x20, 0x96, 0x03,
+ 0x94, 0x37, 0x12, 0x2F, 0x21, 0xC7, 0x8F, 0x16,
+ 0x79, 0xCE, 0xA9, 0xD7, 0x8A, 0x73, 0x4C, 0x56,
+ 0xEC, 0xBE, 0xB2, 0x86, 0x54, 0xB4, 0xF1, 0x8E,
+ 0x34, 0x2C, 0x33, 0x1F, 0x6F, 0x72, 0x29, 0xEC,
+ 0x4B, 0x4B, 0xC2, 0x81, 0xB2, 0xD8, 0x0A, 0x6E,
+ 0xB5, 0x00, 0x43, 0xF3, 0x17, 0x96, 0xC8, 0x8C
+ },
+ {
+ 0x72, 0xD0, 0x81, 0xAF, 0x99, 0xF8, 0xA1, 0x73,
+ 0xDC, 0xC9, 0xA0, 0xAC, 0x4E, 0xB3, 0x55, 0x74,
+ 0x05, 0x63, 0x9A, 0x29, 0x08, 0x4B, 0x54, 0xA4,
+ 0x01, 0x72, 0x91, 0x2A, 0x2F, 0x8A, 0x39, 0x51,
+ 0x29, 0xD5, 0x53, 0x6F, 0x09, 0x18, 0xE9, 0x02,
+ 0xF9, 0xE8, 0xFA, 0x60, 0x00, 0x99, 0x5F, 0x41,
+ 0x68, 0xDD, 0xC5, 0xF8, 0x93, 0x01, 0x1B, 0xE6,
+ 0xA0, 0xDB, 0xC9, 0xB8, 0xA1, 0xA3, 0xF5, 0xBB
+ },
+ {
+ 0xC1, 0x1A, 0xA8, 0x1E, 0x5E, 0xFD, 0x24, 0xD5,
+ 0xFC, 0x27, 0xEE, 0x58, 0x6C, 0xFD, 0x88, 0x47,
+ 0xFB, 0xB0, 0xE2, 0x76, 0x01, 0xCC, 0xEC, 0xE5,
+ 0xEC, 0xCA, 0x01, 0x98, 0xE3, 0xC7, 0x76, 0x53,
+ 0x93, 0xBB, 0x74, 0x45, 0x7C, 0x7E, 0x7A, 0x27,
+ 0xEB, 0x91, 0x70, 0x35, 0x0E, 0x1F, 0xB5, 0x38,
+ 0x57, 0x17, 0x75, 0x06, 0xBE, 0x3E, 0x76, 0x2C,
+ 0xC0, 0xF1, 0x4D, 0x8C, 0x3A, 0xFE, 0x90, 0x77
+ },
+ {
+ 0xC2, 0x8F, 0x21, 0x50, 0xB4, 0x52, 0xE6, 0xC0,
+ 0xC4, 0x24, 0xBC, 0xDE, 0x6F, 0x8D, 0x72, 0x00,
+ 0x7F, 0x93, 0x10, 0xFE, 0xD7, 0xF2, 0xF8, 0x7D,
+ 0xE0, 0xDB, 0xB6, 0x4F, 0x44, 0x79, 0xD6, 0xC1,
+ 0x44, 0x1B, 0xA6, 0x6F, 0x44, 0xB2, 0xAC, 0xCE,
+ 0xE6, 0x16, 0x09, 0x17, 0x7E, 0xD3, 0x40, 0x12,
+ 0x8B, 0x40, 0x7E, 0xCE, 0xC7, 0xC6, 0x4B, 0xBE,
+ 0x50, 0xD6, 0x3D, 0x22, 0xD8, 0x62, 0x77, 0x27
+ },
+ {
+ 0xF6, 0x3D, 0x88, 0x12, 0x28, 0x77, 0xEC, 0x30,
+ 0xB8, 0xC8, 0xB0, 0x0D, 0x22, 0xE8, 0x90, 0x00,
+ 0xA9, 0x66, 0x42, 0x61, 0x12, 0xBD, 0x44, 0x16,
+ 0x6E, 0x2F, 0x52, 0x5B, 0x76, 0x9C, 0xCB, 0xE9,
+ 0xB2, 0x86, 0xD4, 0x37, 0xA0, 0x12, 0x91, 0x30,
+ 0xDD, 0xE1, 0xA8, 0x6C, 0x43, 0xE0, 0x4B, 0xED,
+ 0xB5, 0x94, 0xE6, 0x71, 0xD9, 0x82, 0x83, 0xAF,
+ 0xE6, 0x4C, 0xE3, 0x31, 0xDE, 0x98, 0x28, 0xFD
+ },
+ {
+ 0x34, 0x8B, 0x05, 0x32, 0x88, 0x0B, 0x88, 0xA6,
+ 0x61, 0x4A, 0x8D, 0x74, 0x08, 0xC3, 0xF9, 0x13,
+ 0x35, 0x7F, 0xBB, 0x60, 0xE9, 0x95, 0xC6, 0x02,
+ 0x05, 0xBE, 0x91, 0x39, 0xE7, 0x49, 0x98, 0xAE,
+ 0xDE, 0x7F, 0x45, 0x81, 0xE4, 0x2F, 0x6B, 0x52,
+ 0x69, 0x8F, 0x7F, 0xA1, 0x21, 0x97, 0x08, 0xC1,
+ 0x44, 0x98, 0x06, 0x7F, 0xD1, 0xE0, 0x95, 0x02,
+ 0xDE, 0x83, 0xA7, 0x7D, 0xD2, 0x81, 0x15, 0x0C
+ },
+ {
+ 0x51, 0x33, 0xDC, 0x8B, 0xEF, 0x72, 0x53, 0x59,
+ 0xDF, 0xF5, 0x97, 0x92, 0xD8, 0x5E, 0xAF, 0x75,
+ 0xB7, 0xE1, 0xDC, 0xD1, 0x97, 0x8B, 0x01, 0xC3,
+ 0x5B, 0x1B, 0x85, 0xFC, 0xEB, 0xC6, 0x33, 0x88,
+ 0xAD, 0x99, 0xA1, 0x7B, 0x63, 0x46, 0xA2, 0x17,
+ 0xDC, 0x1A, 0x96, 0x22, 0xEB, 0xD1, 0x22, 0xEC,
+ 0xF6, 0x91, 0x3C, 0x4D, 0x31, 0xA6, 0xB5, 0x2A,
+ 0x69, 0x5B, 0x86, 0xAF, 0x00, 0xD7, 0x41, 0xA0
+ },
+ {
+ 0x27, 0x53, 0xC4, 0xC0, 0xE9, 0x8E, 0xCA, 0xD8,
+ 0x06, 0xE8, 0x87, 0x80, 0xEC, 0x27, 0xFC, 0xCD,
+ 0x0F, 0x5C, 0x1A, 0xB5, 0x47, 0xF9, 0xE4, 0xBF,
+ 0x16, 0x59, 0xD1, 0x92, 0xC2, 0x3A, 0xA2, 0xCC,
+ 0x97, 0x1B, 0x58, 0xB6, 0x80, 0x25, 0x80, 0xBA,
+ 0xEF, 0x8A, 0xDC, 0x3B, 0x77, 0x6E, 0xF7, 0x08,
+ 0x6B, 0x25, 0x45, 0xC2, 0x98, 0x7F, 0x34, 0x8E,
+ 0xE3, 0x71, 0x9C, 0xDE, 0xF2, 0x58, 0xC4, 0x03
+ },
+ {
+ 0xB1, 0x66, 0x35, 0x73, 0xCE, 0x4B, 0x9D, 0x8C,
+ 0xAE, 0xFC, 0x86, 0x50, 0x12, 0xF3, 0xE3, 0x97,
+ 0x14, 0xB9, 0x89, 0x8A, 0x5D, 0xA6, 0xCE, 0x17,
+ 0xC2, 0x5A, 0x6A, 0x47, 0x93, 0x1A, 0x9D, 0xDB,
+ 0x9B, 0xBE, 0x98, 0xAD, 0xAA, 0x55, 0x3B, 0xEE,
+ 0xD4, 0x36, 0xE8, 0x95, 0x78, 0x45, 0x54, 0x16,
+ 0xC2, 0xA5, 0x2A, 0x52, 0x5C, 0xF2, 0x86, 0x2B,
+ 0x8D, 0x1D, 0x49, 0xA2, 0x53, 0x1B, 0x73, 0x91
+ },
+ {
+ 0x64, 0xF5, 0x8B, 0xD6, 0xBF, 0xC8, 0x56, 0xF5,
+ 0xE8, 0x73, 0xB2, 0xA2, 0x95, 0x6E, 0xA0, 0xED,
+ 0xA0, 0xD6, 0xDB, 0x0D, 0xA3, 0x9C, 0x8C, 0x7F,
+ 0xC6, 0x7C, 0x9F, 0x9F, 0xEE, 0xFC, 0xFF, 0x30,
+ 0x72, 0xCD, 0xF9, 0xE6, 0xEA, 0x37, 0xF6, 0x9A,
+ 0x44, 0xF0, 0xC6, 0x1A, 0xA0, 0xDA, 0x36, 0x93,
+ 0xC2, 0xDB, 0x5B, 0x54, 0x96, 0x0C, 0x02, 0x81,
+ 0xA0, 0x88, 0x15, 0x1D, 0xB4, 0x2B, 0x11, 0xE8
+ },
+ {
+ 0x07, 0x64, 0xC7, 0xBE, 0x28, 0x12, 0x5D, 0x90,
+ 0x65, 0xC4, 0xB9, 0x8A, 0x69, 0xD6, 0x0A, 0xED,
+ 0xE7, 0x03, 0x54, 0x7C, 0x66, 0xA1, 0x2E, 0x17,
+ 0xE1, 0xC6, 0x18, 0x99, 0x41, 0x32, 0xF5, 0xEF,
+ 0x82, 0x48, 0x2C, 0x1E, 0x3F, 0xE3, 0x14, 0x6C,
+ 0xC6, 0x53, 0x76, 0xCC, 0x10, 0x9F, 0x01, 0x38,
+ 0xED, 0x9A, 0x80, 0xE4, 0x9F, 0x1F, 0x3C, 0x7D,
+ 0x61, 0x0D, 0x2F, 0x24, 0x32, 0xF2, 0x06, 0x05
+ },
+ {
+ 0xF7, 0x48, 0x78, 0x43, 0x98, 0xA2, 0xFF, 0x03,
+ 0xEB, 0xEB, 0x07, 0xE1, 0x55, 0xE6, 0x61, 0x16,
+ 0xA8, 0x39, 0x74, 0x1A, 0x33, 0x6E, 0x32, 0xDA,
+ 0x71, 0xEC, 0x69, 0x60, 0x01, 0xF0, 0xAD, 0x1B,
+ 0x25, 0xCD, 0x48, 0xC6, 0x9C, 0xFC, 0xA7, 0x26,
+ 0x5E, 0xCA, 0x1D, 0xD7, 0x19, 0x04, 0xA0, 0xCE,
+ 0x74, 0x8A, 0xC4, 0x12, 0x4F, 0x35, 0x71, 0x07,
+ 0x6D, 0xFA, 0x71, 0x16, 0xA9, 0xCF, 0x00, 0xE9
+ },
+ {
+ 0x3F, 0x0D, 0xBC, 0x01, 0x86, 0xBC, 0xEB, 0x6B,
+ 0x78, 0x5B, 0xA7, 0x8D, 0x2A, 0x2A, 0x01, 0x3C,
+ 0x91, 0x0B, 0xE1, 0x57, 0xBD, 0xAF, 0xFA, 0xE8,
+ 0x1B, 0xB6, 0x66, 0x3B, 0x1A, 0x73, 0x72, 0x2F,
+ 0x7F, 0x12, 0x28, 0x79, 0x5F, 0x3E, 0xCA, 0xDA,
+ 0x87, 0xCF, 0x6E, 0xF0, 0x07, 0x84, 0x74, 0xAF,
+ 0x73, 0xF3, 0x1E, 0xCA, 0x0C, 0xC2, 0x00, 0xED,
+ 0x97, 0x5B, 0x68, 0x93, 0xF7, 0x61, 0xCB, 0x6D
+ },
+ {
+ 0xD4, 0x76, 0x2C, 0xD4, 0x59, 0x98, 0x76, 0xCA,
+ 0x75, 0xB2, 0xB8, 0xFE, 0x24, 0x99, 0x44, 0xDB,
+ 0xD2, 0x7A, 0xCE, 0x74, 0x1F, 0xDA, 0xB9, 0x36,
+ 0x16, 0xCB, 0xC6, 0xE4, 0x25, 0x46, 0x0F, 0xEB,
+ 0x51, 0xD4, 0xE7, 0xAD, 0xCC, 0x38, 0x18, 0x0E,
+ 0x7F, 0xC4, 0x7C, 0x89, 0x02, 0x4A, 0x7F, 0x56,
+ 0x19, 0x1A, 0xDB, 0x87, 0x8D, 0xFD, 0xE4, 0xEA,
+ 0xD6, 0x22, 0x23, 0xF5, 0xA2, 0x61, 0x0E, 0xFE
+ },
+ {
+ 0xCD, 0x36, 0xB3, 0xD5, 0xB4, 0xC9, 0x1B, 0x90,
+ 0xFC, 0xBB, 0xA7, 0x95, 0x13, 0xCF, 0xEE, 0x19,
+ 0x07, 0xD8, 0x64, 0x5A, 0x16, 0x2A, 0xFD, 0x0C,
+ 0xD4, 0xCF, 0x41, 0x92, 0xD4, 0xA5, 0xF4, 0xC8,
+ 0x92, 0x18, 0x3A, 0x8E, 0xAC, 0xDB, 0x2B, 0x6B,
+ 0x6A, 0x9D, 0x9A, 0xA8, 0xC1, 0x1A, 0xC1, 0xB2,
+ 0x61, 0xB3, 0x80, 0xDB, 0xEE, 0x24, 0xCA, 0x46,
+ 0x8F, 0x1B, 0xFD, 0x04, 0x3C, 0x58, 0xEE, 0xFE
+ },
+ {
+ 0x98, 0x59, 0x34, 0x52, 0x28, 0x16, 0x61, 0xA5,
+ 0x3C, 0x48, 0xA9, 0xD8, 0xCD, 0x79, 0x08, 0x26,
+ 0xC1, 0xA1, 0xCE, 0x56, 0x77, 0x38, 0x05, 0x3D,
+ 0x0B, 0xEE, 0x4A, 0x91, 0xA3, 0xD5, 0xBD, 0x92,
+ 0xEE, 0xFD, 0xBA, 0xBE, 0xBE, 0x32, 0x04, 0xF2,
+ 0x03, 0x1C, 0xA5, 0xF7, 0x81, 0xBD, 0xA9, 0x9E,
+ 0xF5, 0xD8, 0xAE, 0x56, 0xE5, 0xB0, 0x4A, 0x9E,
+ 0x1E, 0xCD, 0x21, 0xB0, 0xEB, 0x05, 0xD3, 0xE1
+ },
+ {
+ 0x77, 0x1F, 0x57, 0xDD, 0x27, 0x75, 0xCC, 0xDA,
+ 0xB5, 0x59, 0x21, 0xD3, 0xE8, 0xE3, 0x0C, 0xCF,
+ 0x48, 0x4D, 0x61, 0xFE, 0x1C, 0x1B, 0x9C, 0x2A,
+ 0xE8, 0x19, 0xD0, 0xFB, 0x2A, 0x12, 0xFA, 0xB9,
+ 0xBE, 0x70, 0xC4, 0xA7, 0xA1, 0x38, 0xDA, 0x84,
+ 0xE8, 0x28, 0x04, 0x35, 0xDA, 0xAD, 0xE5, 0xBB,
+ 0xE6, 0x6A, 0xF0, 0x83, 0x6A, 0x15, 0x4F, 0x81,
+ 0x7F, 0xB1, 0x7F, 0x33, 0x97, 0xE7, 0x25, 0xA3
+ },
+ {
+ 0xC6, 0x08, 0x97, 0xC6, 0xF8, 0x28, 0xE2, 0x1F,
+ 0x16, 0xFB, 0xB5, 0xF1, 0x5B, 0x32, 0x3F, 0x87,
+ 0xB6, 0xC8, 0x95, 0x5E, 0xAB, 0xF1, 0xD3, 0x80,
+ 0x61, 0xF7, 0x07, 0xF6, 0x08, 0xAB, 0xDD, 0x99,
+ 0x3F, 0xAC, 0x30, 0x70, 0x63, 0x3E, 0x28, 0x6C,
+ 0xF8, 0x33, 0x9C, 0xE2, 0x95, 0xDD, 0x35, 0x2D,
+ 0xF4, 0xB4, 0xB4, 0x0B, 0x2F, 0x29, 0xDA, 0x1D,
+ 0xD5, 0x0B, 0x3A, 0x05, 0xD0, 0x79, 0xE6, 0xBB
+ },
+ {
+ 0x82, 0x10, 0xCD, 0x2C, 0x2D, 0x3B, 0x13, 0x5C,
+ 0x2C, 0xF0, 0x7F, 0xA0, 0xD1, 0x43, 0x3C, 0xD7,
+ 0x71, 0xF3, 0x25, 0xD0, 0x75, 0xC6, 0x46, 0x9D,
+ 0x9C, 0x7F, 0x1B, 0xA0, 0x94, 0x3C, 0xD4, 0xAB,
+ 0x09, 0x80, 0x8C, 0xAB, 0xF4, 0xAC, 0xB9, 0xCE,
+ 0x5B, 0xB8, 0x8B, 0x49, 0x89, 0x29, 0xB4, 0xB8,
+ 0x47, 0xF6, 0x81, 0xAD, 0x2C, 0x49, 0x0D, 0x04,
+ 0x2D, 0xB2, 0xAE, 0xC9, 0x42, 0x14, 0xB0, 0x6B
+ },
+ {
+ 0x1D, 0x4E, 0xDF, 0xFF, 0xD8, 0xFD, 0x80, 0xF7,
+ 0xE4, 0x10, 0x78, 0x40, 0xFA, 0x3A, 0xA3, 0x1E,
+ 0x32, 0x59, 0x84, 0x91, 0xE4, 0xAF, 0x70, 0x13,
+ 0xC1, 0x97, 0xA6, 0x5B, 0x7F, 0x36, 0xDD, 0x3A,
+ 0xC4, 0xB4, 0x78, 0x45, 0x61, 0x11, 0xCD, 0x43,
+ 0x09, 0xD9, 0x24, 0x35, 0x10, 0x78, 0x2F, 0xA3,
+ 0x1B, 0x7C, 0x4C, 0x95, 0xFA, 0x95, 0x15, 0x20,
+ 0xD0, 0x20, 0xEB, 0x7E, 0x5C, 0x36, 0xE4, 0xEF
+ },
+ {
+ 0xAF, 0x8E, 0x6E, 0x91, 0xFA, 0xB4, 0x6C, 0xE4,
+ 0x87, 0x3E, 0x1A, 0x50, 0xA8, 0xEF, 0x44, 0x8C,
+ 0xC2, 0x91, 0x21, 0xF7, 0xF7, 0x4D, 0xEE, 0xF3,
+ 0x4A, 0x71, 0xEF, 0x89, 0xCC, 0x00, 0xD9, 0x27,
+ 0x4B, 0xC6, 0xC2, 0x45, 0x4B, 0xBB, 0x32, 0x30,
+ 0xD8, 0xB2, 0xEC, 0x94, 0xC6, 0x2B, 0x1D, 0xEC,
+ 0x85, 0xF3, 0x59, 0x3B, 0xFA, 0x30, 0xEA, 0x6F,
+ 0x7A, 0x44, 0xD7, 0xC0, 0x94, 0x65, 0xA2, 0x53
+ },
+ {
+ 0x29, 0xFD, 0x38, 0x4E, 0xD4, 0x90, 0x6F, 0x2D,
+ 0x13, 0xAA, 0x9F, 0xE7, 0xAF, 0x90, 0x59, 0x90,
+ 0x93, 0x8B, 0xED, 0x80, 0x7F, 0x18, 0x32, 0x45,
+ 0x4A, 0x37, 0x2A, 0xB4, 0x12, 0xEE, 0xA1, 0xF5,
+ 0x62, 0x5A, 0x1F, 0xCC, 0x9A, 0xC8, 0x34, 0x3B,
+ 0x7C, 0x67, 0xC5, 0xAB, 0xA6, 0xE0, 0xB1, 0xCC,
+ 0x46, 0x44, 0x65, 0x49, 0x13, 0x69, 0x2C, 0x6B,
+ 0x39, 0xEB, 0x91, 0x87, 0xCE, 0xAC, 0xD3, 0xEC
+ },
+ {
+ 0xA2, 0x68, 0xC7, 0x88, 0x5D, 0x98, 0x74, 0xA5,
+ 0x1C, 0x44, 0xDF, 0xFE, 0xD8, 0xEA, 0x53, 0xE9,
+ 0x4F, 0x78, 0x45, 0x6E, 0x0B, 0x2E, 0xD9, 0x9F,
+ 0xF5, 0xA3, 0x92, 0x47, 0x60, 0x81, 0x38, 0x26,
+ 0xD9, 0x60, 0xA1, 0x5E, 0xDB, 0xED, 0xBB, 0x5D,
+ 0xE5, 0x22, 0x6B, 0xA4, 0xB0, 0x74, 0xE7, 0x1B,
+ 0x05, 0xC5, 0x5B, 0x97, 0x56, 0xBB, 0x79, 0xE5,
+ 0x5C, 0x02, 0x75, 0x4C, 0x2C, 0x7B, 0x6C, 0x8A
+ },
+ {
+ 0x0C, 0xF8, 0x54, 0x54, 0x88, 0xD5, 0x6A, 0x86,
+ 0x81, 0x7C, 0xD7, 0xEC, 0xB1, 0x0F, 0x71, 0x16,
+ 0xB7, 0xEA, 0x53, 0x0A, 0x45, 0xB6, 0xEA, 0x49,
+ 0x7B, 0x6C, 0x72, 0xC9, 0x97, 0xE0, 0x9E, 0x3D,
+ 0x0D, 0xA8, 0x69, 0x8F, 0x46, 0xBB, 0x00, 0x6F,
+ 0xC9, 0x77, 0xC2, 0xCD, 0x3D, 0x11, 0x77, 0x46,
+ 0x3A, 0xC9, 0x05, 0x7F, 0xDD, 0x16, 0x62, 0xC8,
+ 0x5D, 0x0C, 0x12, 0x64, 0x43, 0xC1, 0x04, 0x73
+ },
+ {
+ 0xB3, 0x96, 0x14, 0x26, 0x8F, 0xDD, 0x87, 0x81,
+ 0x51, 0x5E, 0x2C, 0xFE, 0xBF, 0x89, 0xB4, 0xD5,
+ 0x40, 0x2B, 0xAB, 0x10, 0xC2, 0x26, 0xE6, 0x34,
+ 0x4E, 0x6B, 0x9A, 0xE0, 0x00, 0xFB, 0x0D, 0x6C,
+ 0x79, 0xCB, 0x2F, 0x3E, 0xC8, 0x0E, 0x80, 0xEA,
+ 0xEB, 0x19, 0x80, 0xD2, 0xF8, 0x69, 0x89, 0x16,
+ 0xBD, 0x2E, 0x9F, 0x74, 0x72, 0x36, 0x65, 0x51,
+ 0x16, 0x64, 0x9C, 0xD3, 0xCA, 0x23, 0xA8, 0x37
+ },
+ {
+ 0x74, 0xBE, 0xF0, 0x92, 0xFC, 0x6F, 0x1E, 0x5D,
+ 0xBA, 0x36, 0x63, 0xA3, 0xFB, 0x00, 0x3B, 0x2A,
+ 0x5B, 0xA2, 0x57, 0x49, 0x65, 0x36, 0xD9, 0x9F,
+ 0x62, 0xB9, 0xD7, 0x3F, 0x8F, 0x9E, 0xB3, 0xCE,
+ 0x9F, 0xF3, 0xEE, 0xC7, 0x09, 0xEB, 0x88, 0x36,
+ 0x55, 0xEC, 0x9E, 0xB8, 0x96, 0xB9, 0x12, 0x8F,
+ 0x2A, 0xFC, 0x89, 0xCF, 0x7D, 0x1A, 0xB5, 0x8A,
+ 0x72, 0xF4, 0xA3, 0xBF, 0x03, 0x4D, 0x2B, 0x4A
+ },
+ {
+ 0x3A, 0x98, 0x8D, 0x38, 0xD7, 0x56, 0x11, 0xF3,
+ 0xEF, 0x38, 0xB8, 0x77, 0x49, 0x80, 0xB3, 0x3E,
+ 0x57, 0x3B, 0x6C, 0x57, 0xBE, 0xE0, 0x46, 0x9B,
+ 0xA5, 0xEE, 0xD9, 0xB4, 0x4F, 0x29, 0x94, 0x5E,
+ 0x73, 0x47, 0x96, 0x7F, 0xBA, 0x2C, 0x16, 0x2E,
+ 0x1C, 0x3B, 0xE7, 0xF3, 0x10, 0xF2, 0xF7, 0x5E,
+ 0xE2, 0x38, 0x1E, 0x7B, 0xFD, 0x6B, 0x3F, 0x0B,
+ 0xAE, 0xA8, 0xD9, 0x5D, 0xFB, 0x1D, 0xAF, 0xB1
+ },
+ {
+ 0x58, 0xAE, 0xDF, 0xCE, 0x6F, 0x67, 0xDD, 0xC8,
+ 0x5A, 0x28, 0xC9, 0x92, 0xF1, 0xC0, 0xBD, 0x09,
+ 0x69, 0xF0, 0x41, 0xE6, 0x6F, 0x1E, 0xE8, 0x80,
+ 0x20, 0xA1, 0x25, 0xCB, 0xFC, 0xFE, 0xBC, 0xD6,
+ 0x17, 0x09, 0xC9, 0xC4, 0xEB, 0xA1, 0x92, 0xC1,
+ 0x5E, 0x69, 0xF0, 0x20, 0xD4, 0x62, 0x48, 0x60,
+ 0x19, 0xFA, 0x8D, 0xEA, 0x0C, 0xD7, 0xA4, 0x29,
+ 0x21, 0xA1, 0x9D, 0x2F, 0xE5, 0x46, 0xD4, 0x3D
+ },
+ {
+ 0x93, 0x47, 0xBD, 0x29, 0x14, 0x73, 0xE6, 0xB4,
+ 0xE3, 0x68, 0x43, 0x7B, 0x8E, 0x56, 0x1E, 0x06,
+ 0x5F, 0x64, 0x9A, 0x6D, 0x8A, 0xDA, 0x47, 0x9A,
+ 0xD0, 0x9B, 0x19, 0x99, 0xA8, 0xF2, 0x6B, 0x91,
+ 0xCF, 0x61, 0x20, 0xFD, 0x3B, 0xFE, 0x01, 0x4E,
+ 0x83, 0xF2, 0x3A, 0xCF, 0xA4, 0xC0, 0xAD, 0x7B,
+ 0x37, 0x12, 0xB2, 0xC3, 0xC0, 0x73, 0x32, 0x70,
+ 0x66, 0x31, 0x12, 0xCC, 0xD9, 0x28, 0x5C, 0xD9
+ },
+ {
+ 0xB3, 0x21, 0x63, 0xE7, 0xC5, 0xDB, 0xB5, 0xF5,
+ 0x1F, 0xDC, 0x11, 0xD2, 0xEA, 0xC8, 0x75, 0xEF,
+ 0xBB, 0xCB, 0x7E, 0x76, 0x99, 0x09, 0x0A, 0x7E,
+ 0x7F, 0xF8, 0xA8, 0xD5, 0x07, 0x95, 0xAF, 0x5D,
+ 0x74, 0xD9, 0xFF, 0x98, 0x54, 0x3E, 0xF8, 0xCD,
+ 0xF8, 0x9A, 0xC1, 0x3D, 0x04, 0x85, 0x27, 0x87,
+ 0x56, 0xE0, 0xEF, 0x00, 0xC8, 0x17, 0x74, 0x56,
+ 0x61, 0xE1, 0xD5, 0x9F, 0xE3, 0x8E, 0x75, 0x37
+ },
+ {
+ 0x10, 0x85, 0xD7, 0x83, 0x07, 0xB1, 0xC4, 0xB0,
+ 0x08, 0xC5, 0x7A, 0x2E, 0x7E, 0x5B, 0x23, 0x46,
+ 0x58, 0xA0, 0xA8, 0x2E, 0x4F, 0xF1, 0xE4, 0xAA,
+ 0xAC, 0x72, 0xB3, 0x12, 0xFD, 0xA0, 0xFE, 0x27,
+ 0xD2, 0x33, 0xBC, 0x5B, 0x10, 0xE9, 0xCC, 0x17,
+ 0xFD, 0xC7, 0x69, 0x7B, 0x54, 0x0C, 0x7D, 0x95,
+ 0xEB, 0x21, 0x5A, 0x19, 0xA1, 0xA0, 0xE2, 0x0E,
+ 0x1A, 0xBF, 0xA1, 0x26, 0xEF, 0xD5, 0x68, 0xC7
+ },
+ {
+ 0x4E, 0x5C, 0x73, 0x4C, 0x7D, 0xDE, 0x01, 0x1D,
+ 0x83, 0xEA, 0xC2, 0xB7, 0x34, 0x7B, 0x37, 0x35,
+ 0x94, 0xF9, 0x2D, 0x70, 0x91, 0xB9, 0xCA, 0x34,
+ 0xCB, 0x9C, 0x6F, 0x39, 0xBD, 0xF5, 0xA8, 0xD2,
+ 0xF1, 0x34, 0x37, 0x9E, 0x16, 0xD8, 0x22, 0xF6,
+ 0x52, 0x21, 0x70, 0xCC, 0xF2, 0xDD, 0xD5, 0x5C,
+ 0x84, 0xB9, 0xE6, 0xC6, 0x4F, 0xC9, 0x27, 0xAC,
+ 0x4C, 0xF8, 0xDF, 0xB2, 0xA1, 0x77, 0x01, 0xF2
+ },
+ {
+ 0x69, 0x5D, 0x83, 0xBD, 0x99, 0x0A, 0x11, 0x17,
+ 0xB3, 0xD0, 0xCE, 0x06, 0xCC, 0x88, 0x80, 0x27,
+ 0xD1, 0x2A, 0x05, 0x4C, 0x26, 0x77, 0xFD, 0x82,
+ 0xF0, 0xD4, 0xFB, 0xFC, 0x93, 0x57, 0x55, 0x23,
+ 0xE7, 0x99, 0x1A, 0x5E, 0x35, 0xA3, 0x75, 0x2E,
+ 0x9B, 0x70, 0xCE, 0x62, 0x99, 0x2E, 0x26, 0x8A,
+ 0x87, 0x77, 0x44, 0xCD, 0xD4, 0x35, 0xF5, 0xF1,
+ 0x30, 0x86, 0x9C, 0x9A, 0x20, 0x74, 0xB3, 0x38
+ },
+ {
+ 0xA6, 0x21, 0x37, 0x43, 0x56, 0x8E, 0x3B, 0x31,
+ 0x58, 0xB9, 0x18, 0x43, 0x01, 0xF3, 0x69, 0x08,
+ 0x47, 0x55, 0x4C, 0x68, 0x45, 0x7C, 0xB4, 0x0F,
+ 0xC9, 0xA4, 0xB8, 0xCF, 0xD8, 0xD4, 0xA1, 0x18,
+ 0xC3, 0x01, 0xA0, 0x77, 0x37, 0xAE, 0xDA, 0x0F,
+ 0x92, 0x9C, 0x68, 0x91, 0x3C, 0x5F, 0x51, 0xC8,
+ 0x03, 0x94, 0xF5, 0x3B, 0xFF, 0x1C, 0x3E, 0x83,
+ 0xB2, 0xE4, 0x0C, 0xA9, 0x7E, 0xBA, 0x9E, 0x15
+ },
+ {
+ 0xD4, 0x44, 0xBF, 0xA2, 0x36, 0x2A, 0x96, 0xDF,
+ 0x21, 0x3D, 0x07, 0x0E, 0x33, 0xFA, 0x84, 0x1F,
+ 0x51, 0x33, 0x4E, 0x4E, 0x76, 0x86, 0x6B, 0x81,
+ 0x39, 0xE8, 0xAF, 0x3B, 0xB3, 0x39, 0x8B, 0xE2,
+ 0xDF, 0xAD, 0xDC, 0xBC, 0x56, 0xB9, 0x14, 0x6D,
+ 0xE9, 0xF6, 0x81, 0x18, 0xDC, 0x58, 0x29, 0xE7,
+ 0x4B, 0x0C, 0x28, 0xD7, 0x71, 0x19, 0x07, 0xB1,
+ 0x21, 0xF9, 0x16, 0x1C, 0xB9, 0x2B, 0x69, 0xA9
+ },
+ {
+ 0x14, 0x27, 0x09, 0xD6, 0x2E, 0x28, 0xFC, 0xCC,
+ 0xD0, 0xAF, 0x97, 0xFA, 0xD0, 0xF8, 0x46, 0x5B,
+ 0x97, 0x1E, 0x82, 0x20, 0x1D, 0xC5, 0x10, 0x70,
+ 0xFA, 0xA0, 0x37, 0x2A, 0xA4, 0x3E, 0x92, 0x48,
+ 0x4B, 0xE1, 0xC1, 0xE7, 0x3B, 0xA1, 0x09, 0x06,
+ 0xD5, 0xD1, 0x85, 0x3D, 0xB6, 0xA4, 0x10, 0x6E,
+ 0x0A, 0x7B, 0xF9, 0x80, 0x0D, 0x37, 0x3D, 0x6D,
+ 0xEE, 0x2D, 0x46, 0xD6, 0x2E, 0xF2, 0xA4, 0x61
+ },
+};
+
+#endif
diff --git a/lib/blake2.h b/lib/blake2.h
new file mode 100644
index 00000000..8519bbf7
--- /dev/null
+++ b/lib/blake2.h
@@ -0,0 +1,148 @@
+/*
+ * BIRD Library -- BLAKE2 Hash Functions
+ *
+ * Based on the code from BLAKE2 reference source code package
+ *
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ *
+ * You may use this under the terms of the CC0, the OpenSSL Licence, or the
+ * Apache Public License 2.0, at your option. The terms of these licenses
+ * can be found at:
+ *
+ * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
+ * - OpenSSL license : https://www.openssl.org/source/license.html
+ * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * More information about the BLAKE2 hash function can be found at
+ * https://blake2.net/ web.
+ */
+
+#ifndef _BIRD_BLAKE2_H_
+#define _BIRD_BLAKE2_H_
+
+#include "nest/bird.h"
+
+
+enum blake2s_constant
+{
+ BLAKE2S_BLOCKBYTES = 64,
+ BLAKE2S_OUTBYTES = 32,
+ BLAKE2S_KEYBYTES = 32,
+ BLAKE2S_SALTBYTES = 8,
+ BLAKE2S_PERSONALBYTES = 8,
+};
+
+enum blake2b_constant
+{
+ BLAKE2B_BLOCKBYTES = 128,
+ BLAKE2B_OUTBYTES = 64,
+ BLAKE2B_KEYBYTES = 64,
+ BLAKE2B_SALTBYTES = 16,
+ BLAKE2B_PERSONALBYTES = 16,
+};
+
+#define BLAKE2S_SIZE 32 // BLAKE2S_OUTBYTES
+#define BLAKE2S_BLOCK_SIZE 64 // BLAKE2S_BLOCKBYTES
+#define BLAKE2S_256_SIZE 32
+
+#define BLAKE2B_SIZE 64 // BLAKE2B_OUTBYTES
+#define BLAKE2B_BLOCK_SIZE 128 // BLAKE2B_BLOCKBYTES
+#define BLAKE2B_512_SIZE 64
+
+
+struct blake2s_state
+{
+ u32 h[8];
+ u32 t[2];
+ u32 f[2];
+ byte buf[BLAKE2S_BLOCK_SIZE];
+ uint buflen;
+ uint outlen;
+ u8 last_node;
+};
+
+struct blake2b_state
+{
+ u64 h[8];
+ u64 t[2];
+ u64 f[2];
+ byte buf[BLAKE2B_BLOCK_SIZE];
+ uint buflen;
+ uint outlen;
+ u8 last_node;
+};
+
+struct blake2s_param
+{
+ u8 digest_length; /* 1 */
+ u8 key_length; /* 2 */
+ u8 fanout; /* 3 */
+ u8 depth; /* 4 */
+ u32 leaf_length; /* 8 */
+ u32 node_offset; /* 12 */
+ u16 xof_length; /* 14 */
+ u8 node_depth; /* 15 */
+ u8 inner_length; /* 16 */
+ /* byte reserved[0]; */
+ byte salt[BLAKE2S_SALTBYTES]; /* 24 */
+ byte personal[BLAKE2S_PERSONALBYTES]; /* 32 */
+} PACKED;
+
+struct blake2b_param
+{
+ u8 digest_length; /* 1 */
+ u8 key_length; /* 2 */
+ u8 fanout; /* 3 */
+ u8 depth; /* 4 */
+ u32 leaf_length; /* 8 */
+ u32 node_offset; /* 12 */
+ u32 xof_length; /* 16 */
+ u8 node_depth; /* 17 */
+ u8 inner_length; /* 18 */
+ byte reserved[14]; /* 32 */
+ byte salt[BLAKE2B_SALTBYTES]; /* 48 */
+ byte personal[BLAKE2B_PERSONALBYTES]; /* 64 */
+} PACKED;
+
+
+/* Streaming API */
+int blake2s_init(struct blake2s_state *s, size_t outlen);
+int blake2s_init_key(struct blake2s_state *s, size_t outlen, const void *key, size_t keylen);
+int blake2s_init_param(struct blake2s_state *s, const struct blake2s_param *p);
+int blake2s_update(struct blake2s_state *s, const void *in, size_t inlen);
+int blake2s_final(struct blake2s_state *s, void *out, size_t outlen);
+
+int blake2b_init(struct blake2b_state *s, size_t outlen);
+int blake2b_init_key(struct blake2b_state *s, size_t outlen, const void *key, size_t keylen);
+int blake2b_init_param(struct blake2b_state *s, const struct blake2b_param *p);
+int blake2b_update(struct blake2b_state *s, const void *in, size_t inlen);
+int blake2b_final(struct blake2b_state *s, void *out, size_t outlen);
+
+
+/* Wrapper functions for MAC class */
+
+struct mac_desc;
+struct mac_context;
+
+struct blake2s_context {
+ const struct mac_desc *type;
+ struct blake2s_state state;
+ byte buf[BLAKE2S_SIZE];
+};
+
+struct blake2b_context {
+ const struct mac_desc *type;
+ struct blake2b_state state;
+ byte buf[BLAKE2B_SIZE];
+};
+
+
+void blake2s_mac_init(struct mac_context *ctx, const byte *key, uint keylen);
+void blake2s_mac_update(struct mac_context *ctx, const byte *data, uint datalen);
+byte *blake2s_mac_final(struct mac_context *ctx);
+
+void blake2b_mac_init(struct mac_context *ctx, const byte *key, uint keylen);
+void blake2b_mac_update(struct mac_context *ctx, const byte *data, uint datalen);
+byte *blake2b_mac_final(struct mac_context *ctx);
+
+#endif /* _BIRD_BLAKE2_H_ */
diff --git a/lib/blake2b.c b/lib/blake2b.c
new file mode 100644
index 00000000..e08d5425
--- /dev/null
+++ b/lib/blake2b.c
@@ -0,0 +1,322 @@
+/*
+ * BIRD Library -- BLAKE2b Hash Function
+ *
+ * Based on the code from BLAKE2 reference source code package
+ *
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ *
+ * You may use this under the terms of the CC0, the OpenSSL Licence, or the
+ * Apache Public License 2.0, at your option. The terms of these licenses
+ * can be found at:
+ *
+ * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
+ * - OpenSSL license : https://www.openssl.org/source/license.html
+ * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * More information about the BLAKE2 hash function can be found at
+ * https://blake2.net/ web.
+ */
+
+#include "lib/mac.h"
+#include "lib/blake2.h"
+#include "lib/blake2-impl.h"
+
+
+static const u64 blake2b_IV[8] =
+{
+ U64(0x6a09e667f3bcc908),
+ U64(0xbb67ae8584caa73b),
+ U64(0x3c6ef372fe94f82b),
+ U64(0xa54ff53a5f1d36f1),
+ U64(0x510e527fade682d1),
+ U64(0x9b05688c2b3e6c1f),
+ U64(0x1f83d9abfb41bd6b),
+ U64(0x5be0cd19137e2179)
+};
+
+static const u8 blake2b_sigma[12][16] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+};
+
+STATIC_ASSERT(sizeof(struct blake2b_param) == BLAKE2B_OUTBYTES);
+
+
+static inline void
+blake2b_set_lastnode(struct blake2b_state *s)
+{
+ s->f[1] = (u64) -1;
+}
+
+/* Some helper functions, not necessarily useful */
+static inline int
+blake2b_is_lastblock(const struct blake2b_state *s)
+{
+ return s->f[0] != 0;
+}
+
+static inline void
+blake2b_set_lastblock(struct blake2b_state *s)
+{
+ if (s->last_node)
+ blake2b_set_lastnode(s);
+
+ s->f[0] = (u64) -1;
+}
+
+static inline void
+blake2b_increment_counter(struct blake2b_state *s, const u64 inc)
+{
+ s->t[0] += inc;
+ s->t[1] += (s->t[0] < inc);
+}
+
+static void
+blake2b_init0(struct blake2b_state *s)
+{
+ memset(s, 0, sizeof(struct blake2b_state));
+
+ for (uint i = 0; i < 8; ++i)
+ s->h[i] = blake2b_IV[i];
+}
+
+/* init xors IV with input parameter block */
+int
+blake2b_init_param(struct blake2b_state *s, const struct blake2b_param *p)
+{
+ const byte *pb = (const void *) p;
+
+ blake2b_init0(s);
+
+ /* IV XOR ParamBlock */
+ for (uint i = 0; i < 8; ++i)
+ s->h[i] ^= load64(pb + sizeof(s->h[i]) * i);
+
+ s->outlen = p->digest_length;
+
+ return 0;
+}
+
+
+int
+blake2b_init(struct blake2b_state *s, size_t outlen)
+{
+ struct blake2b_param p[1];
+
+ if (!outlen || (outlen > BLAKE2B_OUTBYTES))
+ return -1;
+
+ p->digest_length = (uint8_t) outlen;
+ p->key_length = 0;
+ p->fanout = 1;
+ p->depth = 1;
+ store32(&p->leaf_length, 0);
+ store32(&p->node_offset, 0);
+ store32(&p->xof_length, 0);
+ p->node_depth = 0;
+ p->inner_length = 0;
+ memset(p->reserved, 0, sizeof(p->reserved));
+ memset(p->salt, 0, sizeof(p->salt));
+ memset(p->personal, 0, sizeof(p->personal));
+
+ return blake2b_init_param(s, p);
+}
+
+
+int
+blake2b_init_key(struct blake2b_state *s, size_t outlen, const void *key, size_t keylen)
+{
+ struct blake2b_param p[1];
+
+ if (!outlen || (outlen > BLAKE2B_OUTBYTES))
+ return -1;
+
+ if (!key || !keylen || (keylen > BLAKE2B_KEYBYTES))
+ return -1;
+
+ p->digest_length = (uint8_t) outlen;
+ p->key_length = (uint8_t) keylen;
+ p->fanout = 1;
+ p->depth = 1;
+ store32(&p->leaf_length, 0);
+ store32(&p->node_offset, 0);
+ store32(&p->xof_length, 0);
+ p->node_depth = 0;
+ p->inner_length = 0;
+ memset(p->reserved, 0, sizeof(p->reserved));
+ memset(p->salt, 0, sizeof(p->salt));
+ memset(p->personal, 0, sizeof(p->personal));
+
+ if (blake2b_init_param(s, p) < 0)
+ return -1;
+
+ {
+ byte block[BLAKE2B_BLOCKBYTES];
+ memset(block, 0, BLAKE2B_BLOCKBYTES);
+ memcpy(block, key, keylen);
+ blake2b_update(s, block, BLAKE2B_BLOCKBYTES);
+ secure_zero_memory(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */
+ }
+
+ return 0;
+}
+
+#define G(r,i,a,b,c,d) \
+ do { \
+ a = a + b + m[blake2b_sigma[r][2*i+0]]; \
+ d = rotr64(d ^ a, 32); \
+ c = c + d; \
+ b = rotr64(b ^ c, 24); \
+ a = a + b + m[blake2b_sigma[r][2*i+1]]; \
+ d = rotr64(d ^ a, 16); \
+ c = c + d; \
+ b = rotr64(b ^ c, 63); \
+ } while(0)
+
+#define ROUND(r) \
+ do { \
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+ G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+ G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+ G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+ G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+ } while(0)
+
+static void
+blake2b_compress(struct blake2b_state *s, const byte block[BLAKE2B_BLOCKBYTES])
+{
+ u64 m[16];
+ u64 v[16];
+ uint i;
+
+ for (i = 0; i < 16; ++i)
+ m[i] = load64(block + i * sizeof(m[i]));
+
+ for (i = 0; i < 8; ++i)
+ v[i] = s->h[i];
+
+ v[ 8] = blake2b_IV[0];
+ v[ 9] = blake2b_IV[1];
+ v[10] = blake2b_IV[2];
+ v[11] = blake2b_IV[3];
+ v[12] = blake2b_IV[4] ^ s->t[0];
+ v[13] = blake2b_IV[5] ^ s->t[1];
+ v[14] = blake2b_IV[6] ^ s->f[0];
+ v[15] = blake2b_IV[7] ^ s->f[1];
+
+ ROUND(0);
+ ROUND(1);
+ ROUND(2);
+ ROUND(3);
+ ROUND(4);
+ ROUND(5);
+ ROUND(6);
+ ROUND(7);
+ ROUND(8);
+ ROUND(9);
+ ROUND(10);
+ ROUND(11);
+
+ for (i = 0; i < 8; ++i)
+ s->h[i] = s->h[i] ^ v[i] ^ v[i + 8];
+}
+
+#undef G
+#undef ROUND
+
+int
+blake2b_update(struct blake2b_state *s, const void *pin, size_t inlen)
+{
+ const byte *in = pin;
+
+ if (inlen > 0)
+ {
+ size_t left = s->buflen;
+ size_t fill = BLAKE2B_BLOCKBYTES - left;
+
+ if (inlen > fill)
+ {
+ s->buflen = 0;
+ memcpy(s->buf + left, in, fill); /* Fill buffer */
+ blake2b_increment_counter(s, BLAKE2B_BLOCKBYTES);
+ blake2b_compress(s, s->buf); /* Compress */
+ in += fill; inlen -= fill;
+
+ while (inlen > BLAKE2B_BLOCKBYTES)
+ {
+ blake2b_increment_counter(s, BLAKE2B_BLOCKBYTES);
+ blake2b_compress(s, in);
+ in += BLAKE2B_BLOCKBYTES;
+ inlen -= BLAKE2B_BLOCKBYTES;
+ }
+ }
+
+ memcpy(s->buf + s->buflen, in, inlen);
+ s->buflen += inlen;
+ }
+
+ return 0;
+}
+
+int
+blake2b_final(struct blake2b_state *s, void *out, size_t outlen)
+{
+ byte buffer[BLAKE2B_OUTBYTES] = {0};
+
+ if (!out || (outlen < s->outlen))
+ return -1;
+
+ if (blake2b_is_lastblock(s))
+ return -1;
+
+ blake2b_increment_counter(s, s->buflen);
+ blake2b_set_lastblock(s);
+ memset(s->buf + s->buflen, 0, BLAKE2B_BLOCKBYTES - s->buflen); /* Padding */
+ blake2b_compress(s, s->buf);
+
+ /* Output full hash to temp buffer */
+ for (uint i = 0; i < 8; ++i)
+ store64(buffer + sizeof(s->h[i]) * i, s->h[i]);
+
+ memcpy(out, buffer, s->outlen);
+ secure_zero_memory(buffer, sizeof(buffer));
+
+ return 0;
+}
+
+
+void
+blake2b_mac_init(struct mac_context *mac, const byte *key, uint keylen)
+{
+ struct blake2b_context *ctx = (void *) mac;
+ blake2b_init_key(&ctx->state, mac_get_length(mac), key, keylen);
+}
+
+void
+blake2b_mac_update(struct mac_context *mac, const byte *buf, uint len)
+{
+ struct blake2b_context *ctx = (void *) mac;
+ blake2b_update(&ctx->state, buf, len);
+}
+
+byte *
+blake2b_mac_final(struct mac_context *mac)
+{
+ struct blake2b_context *ctx = (void *) mac;
+ blake2b_final(&ctx->state, ctx->buf, mac_get_length(mac));
+ return ctx->buf;
+}
diff --git a/lib/blake2s.c b/lib/blake2s.c
new file mode 100644
index 00000000..dd6f3aaf
--- /dev/null
+++ b/lib/blake2s.c
@@ -0,0 +1,313 @@
+/*
+ * BIRD Library -- BLAKE2s Hash Function
+ *
+ * Based on the code from BLAKE2 reference source code package
+ *
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ *
+ * You may use this under the terms of the CC0, the OpenSSL Licence, or the
+ * Apache Public License 2.0, at your option. The terms of these licenses
+ * can be found at:
+ *
+ * - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
+ * - OpenSSL license : https://www.openssl.org/source/license.html
+ * - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * More information about the BLAKE2 hash function can be found at
+ * https://blake2.net/ web.
+ */
+
+#include "lib/mac.h"
+#include "lib/blake2.h"
+#include "lib/blake2-impl.h"
+
+
+static const u32 blake2s_IV[8] =
+{
+ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+ 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
+};
+
+static const u8 blake2s_sigma[10][16] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
+};
+
+STATIC_ASSERT(sizeof(struct blake2s_param) == BLAKE2S_OUTBYTES);
+
+
+static inline void
+blake2s_set_lastnode(struct blake2s_state *s)
+{
+ s->f[1] = (u32) -1;
+}
+
+/* Some helper functions, not necessarily useful */
+static inline int
+blake2s_is_lastblock(const struct blake2s_state *s)
+{
+ return s->f[0] != 0;
+}
+
+static inline void
+blake2s_set_lastblock(struct blake2s_state *s)
+{
+ if (s->last_node)
+ blake2s_set_lastnode(s);
+
+ s->f[0] = (u32) -1;
+}
+
+static inline void
+blake2s_increment_counter(struct blake2s_state *s, const u32 inc)
+{
+ s->t[0] += inc;
+ s->t[1] += (s->t[0] < inc);
+}
+
+static void
+blake2s_init0(struct blake2s_state *s)
+{
+ memset(s, 0, sizeof(struct blake2s_state));
+
+ for (uint i = 0; i < 8; ++i)
+ s->h[i] = blake2s_IV[i];
+}
+
+/* init2 xors IV with input parameter block */
+int
+blake2s_init_param(struct blake2s_state *s, const struct blake2s_param *p)
+{
+ const byte *pb = (const void *) p;
+
+ blake2s_init0(s);
+
+ /* IV XOR ParamBlock */
+ for (uint i = 0; i < 8; ++i)
+ s->h[i] ^= load32(&pb[i * 4]);
+
+ s->outlen = p->digest_length;
+
+ return 0;
+}
+
+
+/* Sequential blake2s initialization */
+int
+blake2s_init(struct blake2s_state *s, size_t outlen)
+{
+ struct blake2s_param p[1];
+
+ /* Move interval verification here? */
+ if (!outlen || (outlen > BLAKE2S_OUTBYTES))
+ return -1;
+
+ p->digest_length = (uint8_t) outlen;
+ p->key_length = 0;
+ p->fanout = 1;
+ p->depth = 1;
+ store32(&p->leaf_length, 0);
+ store32(&p->node_offset, 0);
+ store16(&p->xof_length, 0);
+ p->node_depth = 0;
+ p->inner_length = 0;
+ /* memset(p->reserved, 0, sizeof(p->reserved)); */
+ memset(p->salt, 0, sizeof(p->salt));
+ memset(p->personal, 0, sizeof(p->personal));
+
+ return blake2s_init_param(s, p);
+}
+
+int
+blake2s_init_key(struct blake2s_state *s, size_t outlen, const void *key, size_t keylen)
+{
+ struct blake2s_param p[1];
+
+ if (!outlen || (outlen > BLAKE2S_OUTBYTES))
+ return -1;
+
+ if (!key || !keylen || (keylen > BLAKE2S_KEYBYTES))
+ return -1;
+
+ p->digest_length = (uint8_t) outlen;
+ p->key_length = (uint8_t) keylen;
+ p->fanout = 1;
+ p->depth = 1;
+ store32(&p->leaf_length, 0);
+ store32(&p->node_offset, 0);
+ store16(&p->xof_length, 0);
+ p->node_depth = 0;
+ p->inner_length = 0;
+ /* memset(p->reserved, 0, sizeof(p->reserved)); */
+ memset(p->salt, 0, sizeof(p->salt));
+ memset(p->personal, 0, sizeof(p->personal));
+
+ if (blake2s_init_param(s, p) < 0)
+ return -1;
+
+ {
+ byte block[BLAKE2S_BLOCKBYTES];
+ memset(block, 0, BLAKE2S_BLOCKBYTES);
+ memcpy(block, key, keylen);
+ blake2s_update(s, block, BLAKE2S_BLOCKBYTES);
+ secure_zero_memory(block, BLAKE2S_BLOCKBYTES); /* Burn the key from stack */
+ }
+
+ return 0;
+}
+
+#define G(r,i,a,b,c,d) \
+ do { \
+ a = a + b + m[blake2s_sigma[r][2*i+0]]; \
+ d = rotr32(d ^ a, 16); \
+ c = c + d; \
+ b = rotr32(b ^ c, 12); \
+ a = a + b + m[blake2s_sigma[r][2*i+1]]; \
+ d = rotr32(d ^ a, 8); \
+ c = c + d; \
+ b = rotr32(b ^ c, 7); \
+ } while(0)
+
+#define ROUND(r) \
+ do { \
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+ G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+ G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+ G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+ G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+ } while(0)
+
+static void
+blake2s_compress(struct blake2s_state *s, const byte in[BLAKE2S_BLOCKBYTES])
+{
+ u32 m[16];
+ u32 v[16];
+ uint i;
+
+ for (i = 0; i < 16; ++i)
+ m[i] = load32(in + i * sizeof(m[i]));
+
+ for (i = 0; i < 8; ++i)
+ v[i] = s->h[i];
+
+ v[ 8] = blake2s_IV[0];
+ v[ 9] = blake2s_IV[1];
+ v[10] = blake2s_IV[2];
+ v[11] = blake2s_IV[3];
+ v[12] = s->t[0] ^ blake2s_IV[4];
+ v[13] = s->t[1] ^ blake2s_IV[5];
+ v[14] = s->f[0] ^ blake2s_IV[6];
+ v[15] = s->f[1] ^ blake2s_IV[7];
+
+ ROUND(0);
+ ROUND(1);
+ ROUND(2);
+ ROUND(3);
+ ROUND(4);
+ ROUND(5);
+ ROUND(6);
+ ROUND(7);
+ ROUND(8);
+ ROUND(9);
+
+ for (i = 0; i < 8; ++i)
+ s->h[i] = s->h[i] ^ v[i] ^ v[i + 8];
+}
+
+#undef G
+#undef ROUND
+
+int
+blake2s_update(struct blake2s_state *s, const void *pin, size_t inlen)
+{
+ const byte *in = pin;
+
+ if (inlen > 0)
+ {
+ size_t left = s->buflen;
+ size_t fill = BLAKE2S_BLOCKBYTES - left;
+
+ if (inlen > fill)
+ {
+ s->buflen = 0;
+ memcpy(s->buf + left, in, fill); /* Fill buffer */
+ blake2s_increment_counter(s, BLAKE2S_BLOCKBYTES);
+ blake2s_compress(s, s->buf); /* Compress */
+ in += fill; inlen -= fill;
+
+ while (inlen > BLAKE2S_BLOCKBYTES)
+ {
+ blake2s_increment_counter(s, BLAKE2S_BLOCKBYTES);
+ blake2s_compress(s, in);
+ in += BLAKE2S_BLOCKBYTES;
+ inlen -= BLAKE2S_BLOCKBYTES;
+ }
+ }
+
+ memcpy(s->buf + s->buflen, in, inlen);
+ s->buflen += inlen;
+ }
+
+ return 0;
+}
+
+int
+blake2s_final(struct blake2s_state *s, void *out, size_t outlen)
+{
+ byte buffer[BLAKE2S_OUTBYTES] = {0};
+
+ if (!out || (outlen < s->outlen))
+ return -1;
+
+ if (blake2s_is_lastblock(s))
+ return -1;
+
+ blake2s_increment_counter(s, s->buflen);
+ blake2s_set_lastblock(s);
+ memset(s->buf + s->buflen, 0, BLAKE2S_BLOCKBYTES - s->buflen); /* Padding */
+ blake2s_compress(s, s->buf);
+
+ /* Output full hash to temp buffer */
+ for (uint i = 0; i < 8; ++i)
+ store32(buffer + sizeof(s->h[i]) * i, s->h[i]);
+
+ memcpy(out, buffer, outlen);
+ secure_zero_memory(buffer, sizeof(buffer));
+
+ return 0;
+}
+
+
+void
+blake2s_mac_init(struct mac_context *mac, const byte *key, uint keylen)
+{
+ struct blake2s_context *ctx = (void *) mac;
+ blake2s_init_key(&ctx->state, mac_get_length(mac), key, keylen);
+}
+
+void
+blake2s_mac_update(struct mac_context *mac, const byte *data, uint datalen)
+{
+ struct blake2s_context *ctx = (void *) mac;
+ blake2s_update(&ctx->state, data, datalen);
+}
+
+byte *
+blake2s_mac_final(struct mac_context *mac)
+{
+ struct blake2s_context *ctx = (void *) mac;
+ blake2s_final(&ctx->state, ctx->buf, mac_get_length(mac));
+ return ctx->buf;
+}
diff --git a/lib/flowspec.c b/lib/flowspec.c
index 42770c50..df5c8da3 100644
--- a/lib/flowspec.c
+++ b/lib/flowspec.c
@@ -31,6 +31,8 @@
* flowspec component type.
*/
+#include <stdlib.h>
+
#include "nest/bird.h"
#include "lib/flowspec.h"
#include "conf/conf.h"
@@ -306,6 +308,21 @@ flow_read_ip6_part(const byte *part)
return flow_read_ip6(part + 3, part[1], part[2]);
}
+static uint
+get_value(const byte *val, u8 len)
+{
+ switch (len)
+ {
+ case 1: return *val;
+ case 2: return get_u16(val);
+ case 4: return get_u32(val);
+ // No component may have length 8
+ // case 8: return get_u64(val);
+ }
+
+ return 0;
+}
+
/*
* Flowspec validation
@@ -798,8 +815,8 @@ flow_builder_add_op_val(struct flow_builder *fb, byte op, u32 value)
* @mask: bitmask
*
* It is required to set appropriate flowspec component type using function
- * flow_builder_set_type(). This function should return 1 for successful adding,
- * otherwise returns 0.
+ * flow_builder_set_type(). Note that for negation, value must be zero or equal
+ * to bitmask.
*/
int
flow_builder_add_val_mask(struct flow_builder *fb, byte op, u32 value, u32 mask)
@@ -928,6 +945,209 @@ flow_builder_clear(struct flow_builder *fb)
/*
+ * Flowspec explication
+ */
+
+/**
+ * flow_explicate_buffer_size - return buffer size needed for explication
+ * @part: flowspec part to explicate
+ *
+ * This function computes and returns a required buffer size that has to be
+ * preallocated and passed to flow_explicate_part(). Note that it returns number
+ * of records, not number of bytes.
+ */
+uint
+flow_explicate_buffer_size(const byte *part)
+{
+ const byte *pos = part + 1;
+ uint first = 1;
+ uint len = 0;
+
+ while (1)
+ {
+ /*
+ * Conjunction sequences represent (mostly) one interval, do not count
+ * additional AND-ed operators. Ignore AND bit for the first operator.
+ */
+ if (!isset_and(pos) || first)
+ len++;
+
+ /*
+ * The exception is that NEQ operator adds one more interval (by splitting
+ * one of intervals defined by other operators).
+ */
+ if (num_op(pos) == FLOW_OP_NEQ)
+ len++;
+
+ if (isset_end(pos))
+ break;
+
+ first = 0;
+ pos = pos + 1 + get_value_length(pos);
+ }
+
+ return len;
+}
+
+static int flow_uint_cmp(const void *p1, const void *p2)
+{ return uint_cmp(* (const uint *) p1, * (const uint *) p2); }
+
+/**
+ * flow_explicate_part - compute explicit interval list from flowspec part
+ * @part: flowspec part to explicate
+ * @buf: pre-allocated buffer for result
+ *
+ * This function analyzes a flowspec part with numeric operators (e.g. port) and
+ * computes an explicit interval list of allowed values. The result is written
+ * to provided buffer @buf, which must have space for enough interval records as
+ * returned by flow_explicate_buffer_size(). The intervals are represented as
+ * two-sized arrays of lower and upper bound, both including. The return value
+ * is the number of intervals in the buffer.
+ */
+uint
+flow_explicate_part(const byte *part, uint (*buf)[2])
+{
+ /*
+ * The Flowspec numeric expression is almost in DNF form (as union of
+ * intersections), where each operator represents one elementary interval.
+ * The exception is NEQ operator, which represents union of two intervals,
+ * separated by the excluded value. Naive algorithm would be like:
+ *
+ * A <- empty set of intervals
+ * for each sequence of operators in conjunction
+ * {
+ * B <- empty set of intervals
+ * for each operator in the current sequence
+ * {
+ * C <- one or two elementary intervals from the current operator
+ * B <- intersection(B, C)
+ * }
+ * A <- union(A, B)
+ * }
+ *
+ * We simplify this by representing B just as one interval (vars lo, hi) and a
+ * list of excluded values. After the inner cycle, we expand that to a proper
+ * list of intervals that is added to existing ones from previous cycles.
+ * Finally, we sort and merge intersecting or touching intervals in A.
+ *
+ * The code handles up to 32bit values in numeric operators. Intervals are
+ * represented by lower and upper bound, both including. Intermediate values
+ * use s64 to simplify representation of excluding bounds for 0 and UINT32_MAX.
+ */
+
+ const byte *pos = part + 1;
+ const s64 max = 0xffffffff;
+ s64 lo = 0;
+ s64 hi = max;
+ uint num = 0;
+ uint neqs = 0;
+
+ /* Step 1 - convert conjunction sequences to lists of intervals */
+ while (1)
+ {
+ uint op = num_op(pos);
+ uint len = get_value_length(pos);
+ s64 val = get_value(pos + 1, len);
+ uint last = isset_end(pos);
+ const byte *next_pos = pos + 1 + len;
+
+ /* Get a new interval from this operator */
+ s64 nlo = (op & FLOW_OP_LT) ? 0 : ((op & FLOW_OP_EQ) ? val : (val + 1));
+ s64 nhi = (op & FLOW_OP_GT) ? max : ((op & FLOW_OP_EQ) ? val : (val - 1));
+
+ /* Restrict current interval */
+ lo = MAX(lo, nlo);
+ hi = MIN(hi, nhi);
+
+ /* Store NEQs for later */
+ if (op == FLOW_OP_NEQ)
+ {
+ buf[num + neqs][0] = val;
+ buf[num + neqs][1] = 0;
+ neqs++;
+ }
+
+ /* End of conjunction sequence */
+ if (last || !isset_and(next_pos))
+ {
+ if (neqs)
+ {
+ /* Sort stored NEQs */
+ qsort(buf + num, neqs, 2 * sizeof(uint), flow_uint_cmp);
+
+ /* Dump stored NEQs as intervals */
+ uint base = num;
+ for (uint i = 0; i < neqs; i++)
+ {
+ val = buf[base + i][0];
+
+ if ((val < lo) || (val > hi))
+ continue;
+
+ if (val == lo)
+ { lo++; continue; }
+
+ if (val == hi)
+ { hi--; continue; }
+
+ buf[num][0] = lo;
+ buf[num][1] = val - 1;
+ num++;
+
+ lo = val + 1;
+ }
+
+ neqs = 0;
+ }
+
+ /* Save final interval */
+ if (lo <= hi)
+ {
+ buf[num][0] = lo;
+ buf[num][1] = hi;
+ num++;
+ }
+
+ lo = 0;
+ hi = max;
+ }
+
+ if (last)
+ break;
+
+ pos = next_pos;
+ }
+
+ if (num < 2)
+ return num;
+
+ /* Step 2 - Sort and merge list of intervals */
+ qsort(buf, num, 2 * sizeof(uint), flow_uint_cmp);
+
+ uint i = 0, j = 0;
+ while (i < num)
+ {
+ lo = buf[i][0];
+ hi = buf[i][1];
+ i++;
+
+ /* If intervals are intersecting or just touching, merge them */
+ while ((i < num) && ((s64) buf[i][0] <= (hi + 1)))
+ {
+ hi = MAX(hi, (s64) buf[i][1]);
+ i++;
+ }
+
+ buf[j][0] = lo;
+ buf[j][1] = hi;
+ j++;
+ }
+
+ return j;
+}
+
+
+/*
* Net Formatting
*/
@@ -951,21 +1171,6 @@ num_op_str(const byte *op)
return NULL;
}
-static uint
-get_value(const byte *val, u8 len)
-{
- switch (len)
- {
- case 1: return *val;
- case 2: return get_u16(val);
- case 4: return get_u32(val);
- // No component may have length 8
- // case 8: return get_u64(val);
- }
-
- return 0;
-}
-
static const char *
fragment_val_str(u8 val)
{
@@ -1073,17 +1278,8 @@ net_format_flow_bitmask(buffer *b, const byte *part)
while (1)
{
if (!first)
- {
- if (isset_and(op))
- {
- b->pos--; /* Remove last char (it is a space) */
- buffer_puts(b, ",");
- }
- else
- {
- buffer_puts(b, "|| ");
- }
- }
+ buffer_puts(b, isset_and(op) ? "&& " : "|| ");
+
first = 0;
len = get_value_length(op);
@@ -1155,11 +1351,11 @@ net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
case FLOW_TYPE_ICMP_CODE:
case FLOW_TYPE_PACKET_LENGTH:
case FLOW_TYPE_DSCP:
+ case FLOW_TYPE_LABEL:
net_format_flow_num(&b, part);
break;
case FLOW_TYPE_TCP_FLAGS:
case FLOW_TYPE_FRAGMENT:
- case FLOW_TYPE_LABEL:
net_format_flow_bitmask(&b, part);
break;
}
diff --git a/lib/flowspec.h b/lib/flowspec.h
index 9bafc52e..91a2671b 100644
--- a/lib/flowspec.h
+++ b/lib/flowspec.h
@@ -15,14 +15,14 @@
/* Flow component operators */
-#define FLOW_OP_TRUE 0x00 /* 0b000 */
+#define FLOW_OP_FALSE 0x00 /* 0b000 */
#define FLOW_OP_EQ 0x01 /* 0b001 */
#define FLOW_OP_GT 0x02 /* 0b010 */
#define FLOW_OP_GEQ 0x03 /* 0b011 */
#define FLOW_OP_LT 0x04 /* 0b100 */
#define FLOW_OP_LEQ 0x05 /* 0b101 */
#define FLOW_OP_NEQ 0x06 /* 0b110 */
-#define FLOW_OP_FALSE 0x07 /* 0b111 */
+#define FLOW_OP_TRUE 0x07 /* 0b111 */
#define FLOW_OP_OR 0x00
#define FLOW_OP_AND 0x40
diff --git a/lib/flowspec_test.c b/lib/flowspec_test.c
index b6b4d7b8..ed4afe51 100644
--- a/lib/flowspec_test.c
+++ b/lib/flowspec_test.c
@@ -630,7 +630,7 @@ t_formatting4(void)
net_addr_flow4 *input;
NET_ADDR_FLOW4_(input, ip4_build(5, 6, 7, 0), 24, nlri);
- const char *expect = "flow4 { dst 10.0.0.0/8; proto 23; dport > 24 && < 30 || 40..50,60..70,80 && >= 90; sport > 24 && < 30 || 40,50,60..70,80; icmp type 80; icmp code 90; tcp flags 0x3/0x3,0x0/0xc; length 0..65535; dscp 63; fragment dont_fragment || !is_fragment; }";
+ const char *expect = "flow4 { dst 10.0.0.0/8; proto 23; dport > 24 && < 30 || 40..50,60..70,80 && >= 90; sport > 24 && < 30 || 40,50,60..70,80; icmp type 80; icmp code 90; tcp flags 0x3/0x3 && 0x0/0xc; length 0..65535; dscp 63; fragment dont_fragment || !is_fragment; }";
bt_assert(flow4_net_format(b, sizeof(b), input) == strlen(expect));
bt_debug(" expect: '%s',\n output: '%s'\n", expect, b);
@@ -650,14 +650,14 @@ t_formatting6(void)
FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
FLOW_TYPE_NEXT_HEADER, 0x81, 0x06,
FLOW_TYPE_PORT, 0x03, 20, 0x45, 40, 0x91, 0x01, 0x11,
- FLOW_TYPE_LABEL, 0xa0, 0x12, 0x34, 0x56, 0x78,
+ FLOW_TYPE_LABEL, 0xa4, 0x00, 0x07, 0xa1, 0x20,
};
*nlri = (u8) sizeof(nlri);
net_addr_flow6 *input;
NET_ADDR_FLOW6_(input, ip6_build(0, 1, 0x12345678, 0x98000000), 103, nlri);
- const char *expect = "flow6 { dst ::1:1234:5678:9800:0/103 offset 61; src c000::/8; next header 6; port 20..40,273; label !0x0/0x12345678; }";
+ const char *expect = "flow6 { dst ::1:1234:5678:9800:0/103 offset 61; src c000::/8; next header 6; port 20..40,273; label < 500000; }";
bt_assert(flow6_net_format(b, sizeof(b), input) == strlen(expect));
bt_debug(" expect: '%s',\n output: '%s'\n", expect, b);
diff --git a/lib/ip.h b/lib/ip.h
index f3b1cc31..9eef2e16 100644
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -47,6 +47,8 @@
#define IP6_HEADER_LENGTH 40
#define UDP_HEADER_LENGTH 8
+#define MPLS_NULL 3
+
/* IANA Address Family Numbers */
/* https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml */
@@ -277,11 +279,35 @@ static inline uint ip6_pxlen(ip6_addr a, ip6_addr b)
return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]);
}
+static inline int ip4_prefix_equal(ip4_addr a, ip4_addr b, uint n)
+{
+ return (_I(a) ^ _I(b)) < ((u64) 1 << (32 - n));
+}
+
+static inline int ip6_prefix_equal(ip6_addr a, ip6_addr b, uint n)
+{
+ uint n0 = n / 32;
+ uint n1 = n % 32;
+
+ return
+ ((n0 <= 0) || (_I0(a) == _I0(b))) &&
+ ((n0 <= 1) || (_I1(a) == _I1(b))) &&
+ ((n0 <= 2) || (_I2(a) == _I2(b))) &&
+ ((n0 <= 3) || (_I3(a) == _I3(b))) &&
+ (!n1 || ((a.addr[n0] ^ b.addr[n0]) < (1u << (32 - n1))));
+}
+
static inline u32 ip4_getbit(ip4_addr a, uint pos)
-{ return _I(a) & (0x80000000 >> pos); }
+{ return (_I(a) >> (31 - pos)) & 1; }
+
+static inline u32 ip4_getbits(ip4_addr a, uint pos, uint n)
+{ return (_I(a) >> ((32 - n) - pos)) & ((1u << n) - 1); }
static inline u32 ip6_getbit(ip6_addr a, uint pos)
-{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); }
+{ return (a.addr[pos / 32] >> (31 - (pos % 32))) & 0x1; }
+
+static inline u32 ip6_getbits(ip6_addr a, uint pos, uint n)
+{ return (a.addr[pos / 32] >> ((32 - n) - (pos % 32))) & ((1u << n) - 1); }
static inline u32 ip4_setbit(ip4_addr *a, uint pos)
{ return _I(*a) |= (0x80000000 >> pos); }
@@ -295,6 +321,13 @@ static inline u32 ip4_clrbit(ip4_addr *a, uint pos)
static inline u32 ip6_clrbit(ip6_addr *a, uint pos)
{ return a->addr[pos / 32] &= ~(0x80000000 >> (pos % 32)); }
+static inline ip4_addr ip4_setbits(ip4_addr a, uint pos, uint val)
+{ _I(a) |= val << (31 - pos); return a; }
+
+static inline ip6_addr ip6_setbits(ip6_addr a, uint pos, uint val)
+{ a.addr[pos / 32] |= val << (31 - pos % 32); return a; }
+
+
static inline ip4_addr ip4_opposite_m1(ip4_addr a)
{ return _MI4(_I(a) ^ 1); }
diff --git a/lib/ip_test.c b/lib/ip_test.c
index 36d10d68..eee0a427 100644
--- a/lib/ip_test.c
+++ b/lib/ip_test.c
@@ -167,6 +167,70 @@ t_ip6_ntop(void)
return bt_assert_batch(test_vectors, test_ipa_ntop, bt_fmt_ipa, bt_fmt_str);
}
+static int
+t_ip4_prefix_equal(void)
+{
+ bt_assert( ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x1234ffff), 16));
+ bt_assert(!ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x1234ffff), 17));
+ bt_assert( ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x12345000), 21));
+ bt_assert(!ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x12345000), 22));
+
+ bt_assert( ip4_prefix_equal(ip4_from_u32(0x00000000), ip4_from_u32(0xffffffff), 0));
+ bt_assert( ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x12345678), 0));
+
+ bt_assert( ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x12345678), 32));
+ bt_assert(!ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x12345679), 32));
+ bt_assert(!ip4_prefix_equal(ip4_from_u32(0x12345678), ip4_from_u32(0x92345678), 32));
+
+ return 1;
+}
+
+static int
+t_ip6_prefix_equal(void)
+{
+ bt_assert( ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ ip6_build(0x20010db8, 0x1234ffff, 0xfefefefe, 0xdcdcdcdc),
+ 48));
+
+ bt_assert(!ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ ip6_build(0x20010db8, 0x1234ffff, 0xfefefefe, 0xdcdcdcdc),
+ 49));
+
+ bt_assert(!ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ ip6_build(0x20020db8, 0x12345678, 0xfefefefe, 0xdcdcdcdc),
+ 48));
+
+ bt_assert( ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ ip6_build(0x20010db8, 0x12345678, 0xfefefefe, 0xdcdcdcdc),
+ 64));
+
+ bt_assert(!ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ ip6_build(0x20010db8, 0x1234567e, 0xfefefefe, 0xdcdcdcdc),
+ 64));
+
+ bt_assert( ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20002020),
+ ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ 106));
+
+ bt_assert(!ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20002020),
+ ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ 107));
+
+ bt_assert( ip6_prefix_equal(ip6_build(0xfeef0db8, 0x87654321, 0x10101010, 0x20202020),
+ ip6_build(0x20010db8, 0x12345678, 0xfefefefe, 0xdcdcdcdc),
+ 0));
+
+ bt_assert( ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ 128));
+
+ bt_assert(!ip6_prefix_equal(ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202020),
+ ip6_build(0x20010db8, 0x12345678, 0x10101010, 0x20202021),
+ 128));
+
+ return 1;
+}
+
int
main(int argc, char *argv[])
{
@@ -176,6 +240,8 @@ main(int argc, char *argv[])
bt_test_suite(t_ip6_pton, "Converting IPv6 string to ip6_addr struct");
bt_test_suite(t_ip4_ntop, "Converting ip4_addr struct to IPv4 string");
bt_test_suite(t_ip6_ntop, "Converting ip6_addr struct to IPv6 string");
+ bt_test_suite(t_ip4_prefix_equal, "Testing ip4_prefix_equal()");
+ bt_test_suite(t_ip6_prefix_equal, "Testing ip6_prefix_equal()");
return bt_exit_value();
}
diff --git a/lib/lists.h b/lib/lists.h
index 066eafbb..479f4ed1 100644
--- a/lib/lists.h
+++ b/lib/lists.h
@@ -59,6 +59,8 @@ typedef union list { /* In fact two overlayed nodes */
/* WALK_LIST_FIRST supposes that called code removes each processed node */
#define WALK_LIST_FIRST(n,list) \
while(n=HEAD(list), (NODE (n))->next)
+#define WALK_LIST_FIRST2(n,pos,list) \
+ while(n=SKIP_BACK(typeof(*n),pos,HEAD(list)), (n)->pos.next)
#define WALK_LIST_BACKWARDS(n,list) for(n=TAIL(list);(NODE (n))->prev; \
n=(void *)((NODE (n))->prev))
#define WALK_LIST_BACKWARDS_DELSAFE(n,prv,list) \
diff --git a/lib/mac.c b/lib/mac.c
index 977d6559..6c9cc743 100644
--- a/lib/mac.c
+++ b/lib/mac.c
@@ -32,6 +32,7 @@
#include "lib/sha1.h"
#include "lib/sha256.h"
#include "lib/sha512.h"
+#include "lib/blake2.h"
/*
@@ -154,13 +155,26 @@ hmac_final(struct mac_context *ctx)
* Common code
*/
-#define HASH_DESC(name, px, PX) \
- { name, PX##_SIZE, sizeof(struct nrmh_context), nrmh_init, nrmh_update, nrmh_final, \
- PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final }
+#define HASH_DESC(name, px, PX) \
+ { \
+ name, PX##_SIZE, sizeof(struct nrmh_context), \
+ nrmh_init, nrmh_update, nrmh_final, \
+ PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final \
+ }
#define HMAC_DESC(name, px, PX) \
- { name, PX##_SIZE, sizeof(struct hmac_context), hmac_init, hmac_update, hmac_final, \
- PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final }
+ { \
+ name, PX##_SIZE, sizeof(struct hmac_context), \
+ hmac_init, hmac_update, hmac_final, \
+ PX##_SIZE, PX##_BLOCK_SIZE, px##_init, px##_update, px##_final \
+ }
+
+#define BLAKE_DESC(name, vx, VX, size) \
+ { \
+ name, size/8, sizeof(struct vx##_context), \
+ vx##_mac_init, vx##_mac_update, vx##_mac_final, \
+ size/8, VX##_BLOCK_SIZE, NULL, NULL, NULL, 0, VX##_SIZE \
+ }
const struct mac_desc mac_table[ALG_MAX] = {
[ALG_MD5] = HASH_DESC("Keyed MD5", md5, MD5),
@@ -169,6 +183,10 @@ const struct mac_desc mac_table[ALG_MAX] = {
[ALG_SHA256] = HASH_DESC("Keyed SHA-256", sha256, SHA256),
[ALG_SHA384] = HASH_DESC("Keyed SHA-384", sha384, SHA384),
[ALG_SHA512] = HASH_DESC("Keyed SHA-512", sha512, SHA512),
+ [ALG_BLAKE2S_128] = BLAKE_DESC("Blake2s-128", blake2s, BLAKE2S, 128),
+ [ALG_BLAKE2S_256] = BLAKE_DESC("Blake2s-256", blake2s, BLAKE2S, 256),
+ [ALG_BLAKE2B_256] = BLAKE_DESC("Blake2b-256", blake2b, BLAKE2B, 256),
+ [ALG_BLAKE2B_512] = BLAKE_DESC("Blake2b-512", blake2b, BLAKE2B, 512),
[ALG_HMAC_MD5] = HMAC_DESC("HMAC-MD5", md5, MD5),
[ALG_HMAC_SHA1] = HMAC_DESC("HMAC-SHA-1", sha1, SHA1),
[ALG_HMAC_SHA224] = HMAC_DESC("HMAC-SHA-224", sha224, SHA224),
diff --git a/lib/mac.h b/lib/mac.h
index b6f3af52..99a56eed 100644
--- a/lib/mac.h
+++ b/lib/mac.h
@@ -12,6 +12,7 @@
#include "nest/bird.h"
#include "lib/sha512.h"
+#include "lib/blake2.h"
#define ALG_UNDEFINED 0
@@ -21,6 +22,10 @@
#define ALG_SHA256 0x04
#define ALG_SHA384 0x05
#define ALG_SHA512 0x06
+#define ALG_BLAKE2S_128 0x07
+#define ALG_BLAKE2S_256 0x08
+#define ALG_BLAKE2B_256 0x09
+#define ALG_BLAKE2B_512 0x0A
#define ALG_HMAC 0x10
#define ALG_HMAC_MD5 0x11
#define ALG_HMAC_SHA1 0x12
@@ -71,6 +76,8 @@ union mac_context_union {
struct mac_context mac;
struct nrmh_context nrmh;
struct hmac_context hmac;
+ struct blake2s_context blake2s;
+ struct blake2b_context blake2b;
};
@@ -87,6 +94,8 @@ struct mac_desc {
void (*hash_init)(struct hash_context *ctx);
void (*hash_update)(struct hash_context *ctx, const byte *data, uint datalen);
byte *(*hash_final)(struct hash_context *ctx);
+ uint min_key_length; /* Minimum allowed key length */
+ uint max_key_length; /* Maximum allowed key length */
};
extern const struct mac_desc mac_table[ALG_MAX];
diff --git a/lib/mac_test.c b/lib/mac_test.c
index 806fe3e4..0e2f94c7 100644
--- a/lib/mac_test.c
+++ b/lib/mac_test.c
@@ -1133,6 +1133,94 @@ t_sha512_concating(void)
return 1;
}
+#include "lib/blake2.h"
+#include "lib/blake2-kat.h"
+
+static void
+blake_in_fmt(char *buf, size_t size, const void *data, size_t key_len)
+{
+ uint8_t in[BLAKE2_KAT_LENGTH] = {0};
+ uint8_t key[64] = {0};
+ size_t i, len = (size_t)data;
+
+ if (size < len*2+key_len*2+2)
+ return;
+
+ for (i = 0; i < sizeof(in); ++i)
+ in[i] = i;
+ for (i = 0; i < sizeof(key); ++i)
+ key[i] = i;
+
+ bt_bytes_to_hex(buf, in, len);
+ buf[len*2] = ',';
+ bt_bytes_to_hex(buf+len*2+1, key, key_len);
+}
+
+#define define_blake_fmt(name, sz) \
+static void \
+name##_in_fmt(char *buf, size_t size, const void *data) \
+{ \
+ if (size < sz * 2 + 1) \
+ return; \
+ blake_in_fmt(buf, size, data, sz); \
+} \
+static void \
+name##_out_fmt(char *buf, size_t size, const void *data) \
+{ \
+ if (size < sz * 2) \
+ return; \
+ bt_bytes_to_hex(buf, data, sz); \
+}
+
+define_blake_fmt(blake2s, BLAKE2S_256_SIZE)
+define_blake_fmt(blake2b, BLAKE2B_512_SIZE)
+
+#define define_test_blake_fn(name, id) \
+static int test_##name(void *out_, const void *in_, \
+ const void *expected_out_) { \
+ uint8_t in[BLAKE2_KAT_LENGTH] = {0}; \
+ uint8_t key[64] = {0}; \
+ uint len = mac_type_length(id); \
+ uint in_len = (size_t)in_; \
+ byte *out; \
+ size_t i; \
+ \
+ for (i = 0; i < sizeof(in); ++i) \
+ in[i] = i; \
+ \
+ for (i = 0; i < sizeof(key); ++i) \
+ key[i] = i; \
+ \
+ struct mac_context ctx; \
+ mac_init(&ctx, id, key, len); \
+ mac_update(&ctx, in, in_len); \
+ out = mac_final(&ctx); \
+ memcpy(out_, out, len); \
+ return memcmp(out, expected_out_, len) == 0; \
+}
+
+define_test_blake_fn(blake2s, ALG_BLAKE2S_256)
+define_test_blake_fn(blake2b, ALG_BLAKE2B_512)
+
+
+#define define_t_blake(name) \
+static int \
+t_##name(void) \
+{ \
+ struct bt_pair test_vectors[BLAKE2_KAT_LENGTH]; \
+ size_t i; \
+ \
+ for (i = 0; i < BLAKE2_KAT_LENGTH; i++) { \
+ test_vectors[i].in = (void *)i; \
+ test_vectors[i].out = name##_keyed_kat[i]; \
+ } \
+ \
+ return bt_assert_batch(test_vectors, test_##name, name##_in_fmt, name##_out_fmt); \
+}
+
+define_t_blake(blake2s)
+define_t_blake(blake2b)
+
int
main(int argc, char *argv[])
{
@@ -1155,5 +1243,8 @@ main(int argc, char *argv[])
bt_test_suite(t_sha256_concating, "Testing concatenation input string to hash using sha256_update");
bt_test_suite(t_sha512_concating, "Testing concatenation input string to hash using sha512_update");
+ bt_test_suite(t_blake2s, "Testing Blake2s-256");
+ bt_test_suite(t_blake2b, "Testing Blake2b-512");
+
return bt_exit_value();
}
diff --git a/lib/mempool.c b/lib/mempool.c
index 758882ce..90d7c774 100644
--- a/lib/mempool.c
+++ b/lib/mempool.c
@@ -45,7 +45,7 @@ struct linpool {
static void lp_free(resource *);
static void lp_dump(resource *);
static resource *lp_lookup(resource *, unsigned long);
-static size_t lp_memsize(resource *r);
+static struct resmem lp_memsize(resource *r);
static struct resclass lp_class = {
"LinPool",
@@ -287,7 +287,7 @@ lp_dump(resource *r)
m->total_large);
}
-static size_t
+static struct resmem
lp_memsize(resource *r)
{
linpool *m = (linpool *) r;
@@ -299,9 +299,11 @@ lp_memsize(resource *r)
for(c=m->first_large; c; c=c->next)
cnt++;
- return ALLOC_OVERHEAD + sizeof(struct linpool) +
- cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)) +
- m->total + m->total_large;
+ return (struct resmem) {
+ .effective = m->total + m->total_large,
+ .overhead = ALLOC_OVERHEAD + sizeof(struct linpool) +
+ cnt * (ALLOC_OVERHEAD + sizeof(struct lp_chunk)),
+ };
}
diff --git a/lib/net.h b/lib/net.h
index 8eb4c7b9..9f4a00ad 100644
--- a/lib/net.h
+++ b/lib/net.h
@@ -38,6 +38,7 @@
#define NB_IP (NB_IP4 | NB_IP6)
#define NB_VPN (NB_VPN4 | NB_VPN6)
+#define NB_ROA (NB_ROA4 | NB_ROA6)
#define NB_FLOW (NB_FLOW4 | NB_FLOW6)
#define NB_DEST (NB_IP | NB_IP6_SADR | NB_VPN | NB_MPLS)
#define NB_ANY 0xffffffff
diff --git a/lib/resource.c b/lib/resource.c
index 5589373e..5d4c7780 100644
--- a/lib/resource.c
+++ b/lib/resource.c
@@ -2,6 +2,7 @@
* BIRD Resource Manager
*
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ * (c) 2021 Maria Matejka <mq@jmq.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -37,7 +38,7 @@ struct pool {
static void pool_dump(resource *);
static void pool_free(resource *);
static resource *pool_lookup(resource *, unsigned long);
-static size_t pool_memsize(resource *P);
+static struct resmem pool_memsize(resource *P);
static struct resclass pool_class = {
"Pool",
@@ -97,15 +98,22 @@ pool_dump(resource *P)
indent -= 3;
}
-static size_t
+static struct resmem
pool_memsize(resource *P)
{
pool *p = (pool *) P;
resource *r;
- size_t sum = sizeof(pool) + ALLOC_OVERHEAD;
+ struct resmem sum = {
+ .effective = 0,
+ .overhead = sizeof(pool) + ALLOC_OVERHEAD,
+ };
WALK_LIST(r, p->inside)
- sum += rmemsize(r);
+ {
+ struct resmem add = rmemsize(r);
+ sum.effective += add.effective;
+ sum.overhead += add.overhead;
+ }
return sum;
}
@@ -193,14 +201,17 @@ rdump(void *res)
debug("NULL\n");
}
-size_t
+struct resmem
rmemsize(void *res)
{
resource *r = res;
if (!r)
- return 0;
+ return (struct resmem) {};
if (!r->class->memsize)
- return r->class->size + ALLOC_OVERHEAD;
+ return (struct resmem) {
+ .effective = r->class->size - sizeof(resource),
+ .overhead = ALLOC_OVERHEAD + sizeof(resource),
+ };
return r->class->memsize(r);
}
@@ -305,11 +316,14 @@ mbl_lookup(resource *r, unsigned long a)
return NULL;
}
-static size_t
+static struct resmem
mbl_memsize(resource *r)
{
struct mblock *m = (struct mblock *) r;
- return ALLOC_OVERHEAD + sizeof(struct mblock) + m->size;
+ return (struct resmem) {
+ .effective = m->size,
+ .overhead = ALLOC_OVERHEAD + sizeof(struct mblock),
+ };
}
static struct resclass mb_class = {
@@ -393,6 +407,21 @@ mb_realloc(void *m, unsigned size)
return b->data;
}
+/**
+ * mb_move - move a memory block
+ * @m: memory block
+ * @p: target pool
+ *
+ * mb_move() moves the given memory block to another pool in the same way
+ * as rmove() moves a plain resource.
+ */
+void
+mb_move(void *m, pool *p)
+{
+ struct mblock *b = SKIP_BACK(struct mblock, data, m);
+ rmove(b, p);
+}
+
/**
* mb_free - free a memory block
diff --git a/lib/resource.h b/lib/resource.h
index b56bcff5..9ec41ed8 100644
--- a/lib/resource.h
+++ b/lib/resource.h
@@ -2,6 +2,7 @@
* BIRD Resource Manager
*
* (c) 1998--1999 Martin Mares <mj@ucw.cz>
+ * (c) 2021 Maria Matejka <mq@jmq.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -11,6 +12,11 @@
#include "lib/lists.h"
+struct resmem {
+ size_t effective; /* Memory actually used for data storage */
+ size_t overhead; /* Overhead memory imposed by allocator strategies */
+};
+
/* Resource */
typedef struct resource {
@@ -26,11 +32,11 @@ struct resclass {
void (*free)(resource *); /* Freeing function */
void (*dump)(resource *); /* Dump to debug output */
resource *(*lookup)(resource *, unsigned long); /* Look up address (only for debugging) */
- size_t (*memsize)(resource *); /* Return size of memory used by the resource, may be NULL */
+ struct resmem (*memsize)(resource *); /* Return size of memory used by the resource, may be NULL */
};
/* Estimate of system allocator overhead per item, for memory consumtion stats */
-#define ALLOC_OVERHEAD 8
+#define ALLOC_OVERHEAD 16
/* Generic resource manipulation */
@@ -40,7 +46,7 @@ void resource_init(void);
pool *rp_new(pool *, const char *); /* Create new pool */
void rfree(void *); /* Free single resource */
void rdump(void *); /* Dump to debug output */
-size_t rmemsize(void *res); /* Return size of memory used by the resource */
+struct resmem rmemsize(void *res); /* Return size of memory used by the resource */
void rlookup(unsigned long); /* Look up address (only for debugging) */
void rmove(void *, pool *); /* Move to a different pool */
@@ -53,6 +59,7 @@ extern pool root_pool;
void *mb_alloc(pool *, unsigned size);
void *mb_allocz(pool *, unsigned size);
void *mb_realloc(void *m, unsigned size);
+void mb_move(void *, pool *);
void mb_free(void *);
/* Memory pools with linear allocation */
@@ -93,6 +100,11 @@ void sl_free(slab *, void *);
void buffer_realloc(void **buf, unsigned *size, unsigned need, unsigned item_size);
+/* Allocator of whole pages; for use in slabs and other high-level allocators. */
+u64 get_page_size(void);
+void *alloc_page(void);
+void free_page(void *);
+extern uint pages_kept;
#ifdef HAVE_LIBDMALLOC
/*
diff --git a/lib/slab.c b/lib/slab.c
index f31355e0..1d844bab 100644
--- a/lib/slab.c
+++ b/lib/slab.c
@@ -4,6 +4,7 @@
* Heavily inspired by the original SLAB paper by Jeff Bonwick.
*
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
+ * (c) 2020 Maria Matejka <mq@jmq.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -41,7 +42,7 @@
static void slab_free(resource *r);
static void slab_dump(resource *r);
static resource *slab_lookup(resource *r, unsigned long addr);
-static size_t slab_memsize(resource *r);
+static struct resmem slab_memsize(resource *r);
#ifdef FAKE_SLAB
@@ -127,7 +128,7 @@ slab_dump(resource *r)
debug("(%d objects per %d bytes)\n", cnt, s->size);
}
-static size_t
+static struct resmem
slab_memsize(resource *r)
{
slab *s = (slab *) r;
@@ -137,7 +138,10 @@ slab_memsize(resource *r)
WALK_LIST(o, s->objs)
cnt++;
- return ALLOC_OVERHEAD + sizeof(struct slab) + cnt * (ALLOC_OVERHEAD + s->size);
+ return (struct resmem) {
+ .effective = cnt * s->size,
+ .overhead = ALLOC_OVERHEAD + sizeof(struct slab) + cnt * ALLOC_OVERHEAD,
+ };
}
@@ -147,12 +151,12 @@ slab_memsize(resource *r)
* Real efficient version.
*/
-#define SLAB_SIZE 4096
#define MAX_EMPTY_HEADS 1
struct slab {
resource r;
- uint obj_size, head_size, objs_per_slab, num_empty_heads, data_size;
+ uint obj_size, head_size, head_bitfield_len;
+ uint objs_per_slab, num_empty_heads, data_size;
list empty_heads, partial_heads, full_heads;
};
@@ -167,16 +171,8 @@ static struct resclass sl_class = {
struct sl_head {
node n;
- struct sl_obj *first_free;
- int num_full;
-};
-
-struct sl_obj {
- struct sl_head *slab;
- union {
- struct sl_obj *next;
- byte data[0];
- } u;
+ u32 num_full;
+ u32 used_bits[0];
};
struct sl_alignment { /* Magic structure for testing of alignment */
@@ -184,6 +180,8 @@ struct sl_alignment { /* Magic structure for testing of alignment */
int x[0];
};
+#define SL_GET_HEAD(x) ((struct sl_head *) (((uintptr_t) (x)) & ~(get_page_size()-1)))
+
/**
* sl_new - create a new Slab
* @p: resource pool
@@ -197,48 +195,35 @@ sl_new(pool *p, uint size)
{
slab *s = ralloc(p, &sl_class);
uint align = sizeof(struct sl_alignment);
- if (align < sizeof(int))
- align = sizeof(int);
+ if (align < sizeof(void *))
+ align = sizeof(void *);
s->data_size = size;
- size += OFFSETOF(struct sl_obj, u.data);
- if (size < sizeof(struct sl_obj))
- size = sizeof(struct sl_obj);
size = (size + align - 1) / align * align;
s->obj_size = size;
- s->head_size = (sizeof(struct sl_head) + align - 1) / align * align;
- s->objs_per_slab = (SLAB_SIZE - s->head_size) / size;
+
+ s->head_size = sizeof(struct sl_head);
+ u64 page_size = get_page_size();
+
+ do {
+ s->objs_per_slab = (page_size - s->head_size) / size;
+ s->head_bitfield_len = (s->objs_per_slab + 31) / 32;
+ s->head_size = (
+ sizeof(struct sl_head)
+ + sizeof(u32) * s->head_bitfield_len
+ + align - 1)
+ / align * align;
+ } while (s->objs_per_slab * size + s->head_size > page_size);
+
if (!s->objs_per_slab)
bug("Slab: object too large");
s->num_empty_heads = 0;
+
init_list(&s->empty_heads);
init_list(&s->partial_heads);
init_list(&s->full_heads);
return s;
}
-static struct sl_head *
-sl_new_head(slab *s)
-{
- struct sl_head *h = xmalloc(SLAB_SIZE);
- struct sl_obj *o = (struct sl_obj *)((byte *)h+s->head_size);
- struct sl_obj *no;
- uint n = s->objs_per_slab;
-
- *h = (struct sl_head) {
- .first_free = o,
- .num_full = 0,
- };
-
- while (n--)
- {
- o->slab = h;
- no = (struct sl_obj *)((char *) o+s->obj_size);
- o->u.next = n ? no : NULL;
- o = no;
- }
- return h;
-}
-
/**
* sl_alloc - allocate an object from Slab
* @s: slab
@@ -250,24 +235,29 @@ void *
sl_alloc(slab *s)
{
struct sl_head *h;
- struct sl_obj *o;
redo:
h = HEAD(s->partial_heads);
if (!h->n.next)
goto no_partial;
okay:
- o = h->first_free;
- if (!o)
- goto full_partial;
- h->first_free = o->u.next;
- h->num_full++;
+ for (uint i=0; i<s->head_bitfield_len; i++)
+ if (~h->used_bits[i])
+ {
+ uint pos = u32_ctz(~h->used_bits[i]);
+ if (i * 32 + pos >= s->objs_per_slab)
+ break;
+
+ h->used_bits[i] |= 1 << pos;
+ h->num_full++;
+
+ void *out = ((void *) h) + s->head_size + (i * 32 + pos) * s->obj_size;
#ifdef POISON
- memset(o->u.data, 0xcd, s->data_size);
+ memset(out, 0xcd, s->data_size);
#endif
- return o->u.data;
+ return out;
+ }
-full_partial:
rem_node(&h->n);
add_tail(&s->full_heads, &h->n);
goto redo;
@@ -281,7 +271,9 @@ no_partial:
s->num_empty_heads--;
goto okay;
}
- h = sl_new_head(s);
+ h = alloc_page();
+ ASSERT_DIE(SL_GET_HEAD(h) == h);
+ memset(h, 0, s->head_size);
add_head(&s->partial_heads, &h->n);
goto okay;
}
@@ -313,30 +305,35 @@ sl_allocz(slab *s)
void
sl_free(slab *s, void *oo)
{
- struct sl_obj *o = SKIP_BACK(struct sl_obj, u.data, oo);
- struct sl_head *h = o->slab;
+ struct sl_head *h = SL_GET_HEAD(oo);
#ifdef POISON
memset(oo, 0xdb, s->data_size);
#endif
- o->u.next = h->first_free;
- h->first_free = o;
- if (!--h->num_full)
+
+ uint offset = oo - ((void *) h) - s->head_size;
+ ASSERT_DIE(offset % s->obj_size == 0);
+ uint pos = offset / s->obj_size;
+ ASSERT_DIE(pos < s->objs_per_slab);
+
+ h->used_bits[pos / 32] &= ~(1 << (pos % 32));
+
+ if (h->num_full-- == s->objs_per_slab)
+ {
+ rem_node(&h->n);
+ add_head(&s->partial_heads, &h->n);
+ }
+ else if (!h->num_full)
{
rem_node(&h->n);
if (s->num_empty_heads >= MAX_EMPTY_HEADS)
- xfree(h);
+ free_page(h);
else
{
add_head(&s->empty_heads, &h->n);
s->num_empty_heads++;
}
}
- else if (!o->u.next)
- {
- rem_node(&h->n);
- add_head(&s->partial_heads, &h->n);
- }
}
static void
@@ -346,11 +343,11 @@ slab_free(resource *r)
struct sl_head *h, *g;
WALK_LIST_DELSAFE(h, g, s->empty_heads)
- xfree(h);
+ free_page(h);
WALK_LIST_DELSAFE(h, g, s->partial_heads)
- xfree(h);
+ free_page(h);
WALK_LIST_DELSAFE(h, g, s->full_heads)
- xfree(h);
+ free_page(h);
}
static void
@@ -369,21 +366,33 @@ slab_dump(resource *r)
debug("(%de+%dp+%df blocks per %d objs per %d bytes)\n", ec, pc, fc, s->objs_per_slab, s->obj_size);
}
-static size_t
+static struct resmem
slab_memsize(resource *r)
{
slab *s = (slab *) r;
size_t heads = 0;
struct sl_head *h;
- WALK_LIST(h, s->empty_heads)
+ WALK_LIST(h, s->full_heads)
heads++;
+
+ size_t items = heads * s->objs_per_slab;
+
WALK_LIST(h, s->partial_heads)
+ {
heads++;
- WALK_LIST(h, s->full_heads)
+ items += h->num_full;
+ }
+
+ WALK_LIST(h, s->empty_heads)
heads++;
- return ALLOC_OVERHEAD + sizeof(struct slab) + heads * (ALLOC_OVERHEAD + SLAB_SIZE);
+ size_t eff = items * s->obj_size;
+
+ return (struct resmem) {
+ .effective = eff,
+ .overhead = ALLOC_OVERHEAD + sizeof(struct slab) + heads * get_page_size() - eff,
+ };
}
static resource *
@@ -393,10 +402,10 @@ slab_lookup(resource *r, unsigned long a)
struct sl_head *h;
WALK_LIST(h, s->partial_heads)
- if ((unsigned long) h < a && (unsigned long) h + SLAB_SIZE < a)
+ if ((unsigned long) h < a && (unsigned long) h + get_page_size() < a)
return r;
WALK_LIST(h, s->full_heads)
- if ((unsigned long) h < a && (unsigned long) h + SLAB_SIZE < a)
+ if ((unsigned long) h < a && (unsigned long) h + get_page_size() < a)
return r;
return NULL;
}
diff --git a/lib/socket.h b/lib/socket.h
index 96fedeeb..0b6ac589 100644
--- a/lib/socket.h
+++ b/lib/socket.h
@@ -123,6 +123,7 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
#define SKF_TTL_RX 0x08 /* Report TTL / Hop Limit for RX packets */
#define SKF_BIND 0x10 /* Bind datagram socket to given source address */
#define SKF_HIGH_PORT 0x20 /* Choose port from high range if possible */
+#define SKF_FREEBIND 0x40 /* Allow socket to bind to a nonlocal address */
#define SKF_THREAD 0x100 /* Socked used in thread, Do not add to main loop */
#define SKF_TRUNCATED 0x200 /* Received packet was truncated, set by IO layer */
diff --git a/lib/string.h b/lib/string.h
index 0f650178..976b1c24 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -26,6 +26,7 @@ void buffer_puts(buffer *buf, const char *str);
u64 bstrtoul10(const char *str, char **end);
u64 bstrtoul16(const char *str, char **end);
+byte bstrtobyte16(const char *str);
int patmatch(const byte *pat, const byte *str);
diff --git a/lib/strtoul.c b/lib/strtoul.c
index 44a1bb1d..a5b11f68 100644
--- a/lib/strtoul.c
+++ b/lib/strtoul.c
@@ -59,3 +59,30 @@ bstrtoul16(const char *str, char **end)
errno = ERANGE;
return UINT64_MAX;
}
+
+byte
+bstrtobyte16(const char *str)
+{
+ byte out = 0;
+ for (int i=0; i<2; i++) {
+ switch (str[i]) {
+ case '0' ... '9':
+ out *= 16;
+ out += str[i] - '0';
+ break;
+ case 'a' ... 'f':
+ out *= 16;
+ out += str[i] + 10 - 'a';
+ break;
+ case 'A' ... 'F':
+ out *= 16;
+ out += str[i] + 10 - 'A';
+ break;
+ default:
+ errno = ERANGE;
+ return -1;
+ }
+ }
+
+ return out;
+}
diff --git a/lib/timer.c b/lib/timer.c
index a5abbcc4..381163d0 100644
--- a/lib/timer.c
+++ b/lib/timer.c
@@ -365,8 +365,9 @@ tm_format_real_time(char *x, size_t max, const char *fmt, btime t)
if (!localtime_r(&ts, &tm))
return 0;
- byte tbuf[TM_DATETIME_BUFFER_SIZE];
- if (!strfusec(tbuf, max, fmt, t2))
+ size_t tbuf_size = MIN(max, 4096);
+ byte *tbuf = alloca(tbuf_size);
+ if (!strfusec(tbuf, tbuf_size, fmt, t2))
return 0;
if (!strftime(x, max, tbuf, &tm))
diff --git a/nest/a-set.c b/nest/a-set.c
index 1186eb56..71fbac94 100644
--- a/nest/a-set.c
+++ b/nest/a-set.c
@@ -516,6 +516,48 @@ int_set_sort(struct linpool *pool, const struct adata *src)
return dst;
}
+int
+int_set_min(const struct adata *list, u32 *val)
+{
+ if (!list)
+ return 0;
+
+ u32 *l = (u32 *) list->data;
+ int len = int_set_get_size(list);
+ int i;
+
+ if (len < 1)
+ return 0;
+
+ *val = *l++;
+ for (i = 1; i < len; i++, l++)
+ if (int_set_cmp(val, l) > 0)
+ *val = *l;
+
+ return 1;
+}
+
+int
+int_set_max(const struct adata *list, u32 *val)
+{
+ if (!list)
+ return 0;
+
+ u32 *l = (u32 *) list->data;
+ int len = int_set_get_size(list);
+ int i;
+
+ if (len < 1)
+ return 0;
+
+ *val = *l++;
+ for (i = 1; i < len; i++, l++)
+ if (int_set_cmp(val, l) < 0)
+ *val = *l;
+
+ return 1;
+}
+
static int
ec_set_cmp(const void *X, const void *Y)
@@ -541,6 +583,50 @@ ec_set_sort_x(struct adata *set)
qsort(set->data, set->length / 8, 8, ec_set_cmp);
}
+int
+ec_set_min(const struct adata *list, u64 *val)
+{
+ if (!list)
+ return 0;
+
+ u32 *l = int_set_get_data(list);
+ int len = int_set_get_size(list);
+ int i;
+
+ if (len < 1)
+ return 0;
+
+ u32 *res = l; l += 2;
+ for (i = 2; i < len; i += 2, l += 2)
+ if (ec_set_cmp(res, l) > 0)
+ res = l;
+
+ *val = ec_generic(res[0], res[1]);
+ return 1;
+}
+
+int
+ec_set_max(const struct adata *list, u64 *val)
+{
+ if (!list)
+ return 0;
+
+ u32 *l = int_set_get_data(list);
+ int len = int_set_get_size(list);
+ int i;
+
+ if (len < 1)
+ return 0;
+
+ u32 *res = l; l += 2;
+ for (i = 2; i < len; i += 2, l += 2)
+ if (ec_set_cmp(res, l) < 0)
+ res = l;
+
+ *val = ec_generic(res[0], res[1]);
+ return 1;
+}
+
static int
lc_set_cmp(const void *X, const void *Y)
@@ -563,3 +649,47 @@ lc_set_sort(struct linpool *pool, const struct adata *src)
qsort(dst->data, dst->length / LCOMM_LENGTH, LCOMM_LENGTH, lc_set_cmp);
return dst;
}
+
+int
+lc_set_min(const struct adata *list, lcomm *val)
+{
+ if (!list)
+ return 0;
+
+ u32 *l = int_set_get_data(list);
+ int len = int_set_get_size(list);
+ int i;
+
+ if (len < 1)
+ return 0;
+
+ u32 *res = l; l += 3;
+ for (i = 3; i < len; i += 3, l += 3)
+ if (lc_set_cmp(res, l) > 0)
+ res = l;
+
+ *val = (lcomm) { res[0], res[1], res[2] };
+ return 1;
+}
+
+int
+lc_set_max(const struct adata *list, lcomm *val)
+{
+ if (!list)
+ return 0;
+
+ u32 *l = int_set_get_data(list);
+ int len = int_set_get_size(list);
+ int i;
+
+ if (len < 1)
+ return 0;
+
+ u32 *res = l; l += 3;
+ for (i = 3; i < len; i += 3, l += 3)
+ if (lc_set_cmp(res, l) < 0)
+ res = l;
+
+ *val = (lcomm) { res[0], res[1], res[2] };
+ return 1;
+}
diff --git a/nest/attrs.h b/nest/attrs.h
index 50da817b..ef2b95e6 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -218,6 +218,12 @@ struct adata *ec_set_del_nontrans(struct linpool *pool, const struct adata *set)
struct adata *int_set_sort(struct linpool *pool, const struct adata *src);
struct adata *ec_set_sort(struct linpool *pool, const struct adata *src);
struct adata *lc_set_sort(struct linpool *pool, const struct adata *src);
+int int_set_min(const struct adata *list, u32 *val);
+int ec_set_min(const struct adata *list, u64 *val);
+int lc_set_min(const struct adata *list, lcomm *val);
+int int_set_max(const struct adata *list, u32 *val);
+int ec_set_max(const struct adata *list, u64 *val);
+int lc_set_max(const struct adata *list, lcomm *val);
void ec_set_sort_x(struct adata *set); /* Sort in place */
diff --git a/nest/cmds.c b/nest/cmds.c
index 18f39eb5..1a16f9c7 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -67,18 +67,43 @@ cmd_show_symbols(struct sym_show_data *sd)
}
}
-static void
-print_size(char *dsc, size_t val)
+#define SIZE_SUFFIX " kMGT"
+#define SIZE_FORMAT "% 4u.%1u % 1cB"
+#define SIZE_ARGS(a) (a).val, (a).decimal, SIZE_SUFFIX[(a).magnitude]
+
+struct size_args {
+ u64 val:48;
+ u64 decimal:8;
+ u64 magnitude:8;
+};
+
+static struct size_args
+get_size_args(u64 val)
{
- char *px = " kMG";
- int i = 0;
- while ((val >= 10000) && (i < 3))
+#define VALDEC 10 /* One decimal place */
+ val *= VALDEC;
+
+ uint i = 0;
+ while ((val >= 10000 * VALDEC) && (i < 4))
{
val = (val + 512) / 1024;
i++;
}
- cli_msg(-1018, "%-17s %4u %cB", dsc, (unsigned) val, px[i]);
+ return (struct size_args) {
+ .val = (val / VALDEC),
+ .decimal = (val % VALDEC),
+ .magnitude = i,
+ };
+}
+
+static void
+print_size(char *dsc, struct resmem vals)
+{
+ struct size_args effective = get_size_args(vals.effective);
+ struct size_args overhead = get_size_args(vals.overhead);
+
+ cli_msg(-1018, "%-17s " SIZE_FORMAT " " SIZE_FORMAT, dsc, SIZE_ARGS(effective), SIZE_ARGS(overhead));
}
extern pool *rt_table_pool;
@@ -88,10 +113,16 @@ void
cmd_show_memory(void)
{
cli_msg(-1018, "BIRD memory usage");
+ cli_msg(-1018, "%-17s Effective Overhead", "");
print_size("Routing tables:", rmemsize(rt_table_pool));
print_size("Route attributes:", rmemsize(rta_pool));
print_size("Protocols:", rmemsize(proto_pool));
- print_size("Total:", rmemsize(&root_pool));
+ struct resmem total = rmemsize(&root_pool);
+#ifdef HAVE_MMAP
+ print_size("Standby memory:", (struct resmem) { .overhead = get_page_size() * pages_kept });
+ total.overhead += get_page_size() * pages_kept;
+#endif
+ print_size("Total:", total);
cli_msg(0, "");
}
diff --git a/nest/config.Y b/nest/config.Y
index 7b7f12cc..72bc7930 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -17,6 +17,7 @@ CF_HDR
CF_DEFINES
+static struct rtable_config *this_table;
static struct proto_config *this_proto;
static struct channel_config *this_channel;
static struct iface_patt *this_ipatt;
@@ -37,6 +38,30 @@ iface_patt_check(void)
cf_error("Interface name/mask expected, not IP prefix");
}
+static inline void
+init_password_list(void)
+{
+ if (!this_p_list) {
+ this_p_list = cfg_allocz(sizeof(list));
+ init_list(this_p_list);
+ password_id = 1;
+ }
+}
+
+static inline void
+init_password(const void *key, uint length, uint id)
+{
+ this_p_item = cfg_allocz(sizeof (struct password_item));
+ this_p_item->password = key;
+ this_p_item->length = length;
+ this_p_item->genfrom = 0;
+ this_p_item->gento = TIME_INFINITY;
+ this_p_item->accfrom = 0;
+ this_p_item->accto = TIME_INFINITY;
+ this_p_item->id = id;
+ this_p_item->alg = ALG_UNDEFINED;
+ add_tail(this_p_list, &this_p_item->n);
+}
static inline void
reset_passwords(void)
@@ -91,15 +116,16 @@ CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBU
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED, RPKI)
-CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CHANNELS, INTERFACES)
-CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
-CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
-CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
+CF_KEYWORDS(PASSWORD, KEY, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CHANNELS, INTERFACES)
+CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512, BLAKE2S128, BLAKE2S256, BLAKE2B256, BLAKE2B512)
+CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, IN, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
+CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
CF_KEYWORDS(CHECK, LINK)
+CF_KEYWORDS(SORTED, TRIE, MIN, MAX, SETTLE, TIME)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
@@ -117,7 +143,7 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
%type <s> optproto
%type <ra> r_args
%type <sd> sym_args
-%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos password_algorithm
+%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type tos password_algorithm
%type <ps> proto_patt proto_patt2
%type <cc> channel_start proto_channel
%type <cl> limit_spec
@@ -182,16 +208,37 @@ CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP
conf: table ;
+table: table_start table_sorted table_opt_list ;
+
+table_start: net_type TABLE symbol {
+ this_table = rt_new_table($3, $1);
+ }
+ ;
+
table_sorted:
- { $$ = 0; }
- | SORTED { $$ = 1; }
+ /* empty */
+ | SORTED { this_table->sorted = 1; }
;
-table: net_type TABLE symbol table_sorted {
- struct rtable_config *cf;
- cf = rt_new_table($3, $1);
- cf->sorted = $4;
+table_opt:
+ SORTED bool { this_table->sorted = $2; }
+ | TRIE bool {
+ if (!net_val_match(this_table->addr_type, NB_IP | NB_VPN | NB_ROA | NB_IP6_SADR))
+ cf_error("Trie option not supported for %s table", net_label[this_table->addr_type]);
+ this_table->trie_used = $2;
}
+ | MIN SETTLE TIME expr_us { this_table->min_settle_time = $4; }
+ | MAX SETTLE TIME expr_us { this_table->max_settle_time = $4; }
+ ;
+
+table_opts:
+ /* empty */
+ | table_opts table_opt ';'
+ ;
+
+table_opt_list:
+ /* empty */
+ | '{' table_opts '}'
;
@@ -475,6 +522,10 @@ mrtdump_flag:
/* Password lists */
password_list:
+ password_list_body
+;
+
+password_list_body:
PASSWORDS '{' password_items '}'
| password_item
;
@@ -485,28 +536,15 @@ password_items:
;
password_item:
- password_item_begin '{' password_item_params '}'
- | password_item_begin
+ password_item_begin '{' password_item_params '}' password_item_end
+ | password_item_begin password_item_end
;
+pass_key: PASSWORD | KEY;
+
password_item_begin:
- PASSWORD text {
- if (!this_p_list) {
- this_p_list = cfg_allocz(sizeof(list));
- init_list(this_p_list);
- password_id = 1;
- }
- this_p_item = cfg_allocz(sizeof(struct password_item));
- this_p_item->password = $2;
- this_p_item->length = strlen($2);
- this_p_item->genfrom = 0;
- this_p_item->gento = TIME_INFINITY;
- this_p_item->accfrom = 0;
- this_p_item->accto = TIME_INFINITY;
- this_p_item->id = password_id++;
- this_p_item->alg = ALG_UNDEFINED;
- add_tail(this_p_list, &this_p_item->n);
- }
+ pass_key text { init_password_list(); init_password($2, strlen($2), password_id++); }
+ | pass_key BYTESTRING { init_password_list(); init_password($2->data, $2->length, password_id++); }
;
password_item_params:
@@ -532,8 +570,17 @@ password_algorithm:
| HMAC SHA256 { $$ = ALG_HMAC_SHA256; }
| HMAC SHA384 { $$ = ALG_HMAC_SHA384; }
| HMAC SHA512 { $$ = ALG_HMAC_SHA512; }
+ | BLAKE2S128 { $$ = ALG_BLAKE2S_128; }
+ | BLAKE2S256 { $$ = ALG_BLAKE2S_256; }
+ | BLAKE2B256 { $$ = ALG_BLAKE2B_256; }
+ | BLAKE2B512 { $$ = ALG_BLAKE2B_512; }
;
+password_item_end:
+{
+ password_validate_length(this_p_item);
+};
+
/* BFD options */
@@ -597,14 +644,22 @@ r_args:
$$ = $1;
if ($$->addr) cf_error("Only one prefix expected");
$$->addr = $2;
+ $$->addr_mode = RSD_ADDR_EQUAL;
}
| r_args FOR r_args_for {
$$ = $1;
if ($$->addr) cf_error("Only one prefix expected");
- $$->show_for = 1;
$$->addr = $3;
+ $$->addr_mode = RSD_ADDR_FOR;
+ }
+ | r_args IN net_any {
+ $$ = $1;
+ if ($$->addr) cf_error("Only one prefix expected");
+ if (!net_type_match($3, NB_IP)) cf_error("Only IP networks accepted for 'in' argument");
+ $$->addr = $3;
+ $$->addr_mode = RSD_ADDR_IN;
}
- | r_args TABLE CF_SYM_KNOWN {
+| r_args TABLE CF_SYM_KNOWN {
cf_assert_symbol($3, SYM_TABLE);
$$ = $1;
rt_show_add_table($$, $3->table->table);
diff --git a/nest/iface.c b/nest/iface.c
index 83a633a3..682340c5 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -591,7 +591,7 @@ ifa_update(struct ifa *a)
if (ipa_equal(b->brd, a->brd) &&
ipa_equal(b->opposite, a->opposite) &&
b->scope == a->scope &&
- !((b->flags ^ a->flags) & IA_PEER))
+ !((b->flags ^ a->flags) & (IA_SECONDARY | IA_PEER | IA_HOST)))
{
b->flags |= IA_UPDATED;
return b;
diff --git a/nest/password.c b/nest/password.c
index 6f87af21..34e2a61e 100644
--- a/nest/password.c
+++ b/nest/password.c
@@ -9,6 +9,7 @@
#include "nest/bird.h"
#include "nest/password.h"
+#include "conf/conf.h"
#include "lib/string.h"
#include "lib/timer.h"
#include "lib/mac.h"
@@ -85,3 +86,28 @@ max_mac_length(list *l)
return val;
}
+
+/**
+ * password_validate_length - enforce key length restrictions
+ * @pi: Password item
+ *
+ * This is a common MAC algorithm validation function that will enforce that the
+ * key length constrains specified in the MAC type table.
+ */
+
+void
+password_validate_length(const struct password_item *pi)
+{
+ if (!pi->alg)
+ return;
+
+ const struct mac_desc *alg = &mac_table[pi->alg];
+
+ if (alg->min_key_length && (pi->length < alg->min_key_length))
+ cf_error("Key length (%u B) below minimum length of %u B for %s",
+ pi->length, alg->min_key_length, alg->name);
+
+ if (alg->max_key_length && (pi->length > alg->max_key_length))
+ cf_error("Key length (%u B) exceeds maximum length of %u B for %s",
+ pi->length, alg->max_key_length, alg->name);
+}
diff --git a/nest/password.h b/nest/password.h
index 8a0da223..53168bb7 100644
--- a/nest/password.h
+++ b/nest/password.h
@@ -24,6 +24,7 @@ extern struct password_item *last_password_item;
struct password_item *password_find(list *l, int first_fit);
struct password_item *password_find_by_id(list *l, uint id);
struct password_item *password_find_by_value(list *l, char *pass, uint size);
+void password_validate_length(const struct password_item *p);
static inline int password_verify(struct password_item *p1, char *p2, uint size)
{
diff --git a/nest/proto.c b/nest/proto.c
index 1c27e638..31ee1fa1 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -518,11 +518,12 @@ void
channel_setup_in_table(struct channel *c)
{
struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
+
cf->name = "import";
cf->addr_type = c->net_type;
+ cf->internal = 1;
- c->in_table = mb_allocz(c->proto->pool, sizeof(struct rtable));
- rt_setup(c->proto->pool, c->in_table, cf);
+ c->in_table = rt_setup(c->proto->pool, cf);
c->reload_event = ev_new_init(c->proto->pool, channel_reload_loop, c);
}
@@ -534,9 +535,9 @@ channel_setup_out_table(struct channel *c)
struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
cf->name = "export";
cf->addr_type = c->net_type;
+ cf->internal = 1;
- c->out_table = mb_allocz(c->proto->pool, sizeof(struct rtable));
- rt_setup(c->proto->pool, c->out_table, cf);
+ c->out_table = rt_setup(c->proto->pool, cf);
}
@@ -609,6 +610,8 @@ channel_do_down(struct channel *c)
c->reload_event = NULL;
c->out_table = NULL;
+ /* The in_table and out_table are going to be freed by freeing their resource pools. */
+
CALL(c->channel->cleanup, c);
/* Schedule protocol shutddown */
diff --git a/nest/protocol.h b/nest/protocol.h
index 48eb01d2..abcc505d 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -616,7 +616,7 @@ struct channel {
struct channel_config *proto_cf_find_channel(struct proto_config *p, uint net_type);
static inline struct channel_config *proto_cf_main_channel(struct proto_config *pc)
-{ struct channel_config *cc = HEAD(pc->channels); return NODE_VALID(cc) ? cc : NULL; }
+{ return proto_cf_find_channel(pc, pc->net_type); }
struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t);
struct channel *proto_find_channel_by_name(struct proto *p, const char *n);
diff --git a/nest/route.h b/nest/route.h
index 53cdcee8..7930058a 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -20,7 +20,10 @@ struct proto;
struct rte_src;
struct symbol;
struct timer;
+struct fib;
struct filter;
+struct f_trie;
+struct f_trie_walk_state;
struct cli;
/*
@@ -49,7 +52,7 @@ struct fib_iterator { /* See lib/slists.h for an explanation */
uint hash;
};
-typedef void (*fib_init_fn)(void *);
+typedef void (*fib_init_fn)(struct fib *, void *);
struct fib {
pool *fib_pool; /* Pool holding all our data */
@@ -148,19 +151,27 @@ struct rtable_config {
int gc_max_ops; /* Maximum number of operations before GC is run */
int gc_min_time; /* Minimum time between two consecutive GC runs */
byte sorted; /* Routes of network are sorted according to rte_better() */
+ byte internal; /* Internal table of a protocol */
+ byte trie_used; /* Rtable has attached trie */
btime min_settle_time; /* Minimum settle time for notifications */
btime max_settle_time; /* Maximum settle time for notifications */
};
typedef struct rtable {
+ resource r;
node n; /* Node in list of all tables */
+ pool *rp; /* Resource pool to allocate everything from, including itself */
struct fib fib;
+ struct f_trie *trie; /* Trie of prefixes defined in fib */
char *name; /* Name of this table */
list channels; /* List of attached channels (struct channel) */
uint addr_type; /* Type of address data stored in table (NET_*) */
int pipe_busy; /* Pipe loop detection */
int use_count; /* Number of protocols using this table */
u32 rt_count; /* Number of routes in the table */
+
+ byte internal; /* Internal table of a protocol */
+
struct hmap id_map;
struct hostcache *hostcache;
struct rtable_config *config; /* Configuration of this table */
@@ -174,13 +185,20 @@ typedef struct rtable {
btime gc_time; /* Time of last GC */
int gc_counter; /* Number of operations since last GC */
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
+ byte prune_trie; /* Prune prefix trie during next table prune */
byte hcu_scheduled; /* Hostcache update is scheduled */
byte nhu_state; /* Next Hop Update state */
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
+ struct f_trie *trie_new; /* New prefix trie defined during pruning */
+ struct f_trie *trie_old; /* Old prefix trie waiting to be freed */
+ u32 trie_lock_count; /* Prefix trie locked by walks */
+ u32 trie_old_lock_count; /* Old prefix trie locked by walks */
list subscribers; /* Subscribers for notifications */
struct timer *settle_timer; /* Settle time for notifications */
+ list flowspec_links; /* List of flowspec links, src for NET_IPx and dst for NET_FLOWx */
+ struct f_trie *flowspec_trie; /* Trie for evaluation of flowspec notifications */
} rtable;
struct rt_subscription {
@@ -190,6 +208,13 @@ struct rt_subscription {
void *data;
};
+struct rt_flowspec_link {
+ node n;
+ rtable *src;
+ rtable *dst;
+ u32 uc;
+};
+
#define NHU_CLEAN 0
#define NHU_SCHEDULED 1
#define NHU_RUNNING 2
@@ -256,6 +281,7 @@ typedef struct rte {
struct {
u8 suppressed; /* Used for deterministic MED comparison */
s8 stale; /* Route is LLGR_STALE, -1 if unknown */
+ struct rtable *base_table; /* Base table for Flowspec validation */
} bgp;
#endif
#ifdef CONFIG_BABEL
@@ -309,14 +335,21 @@ void rt_preconfig(struct config *);
void rt_commit(struct config *new, struct config *old);
void rt_lock_table(rtable *);
void rt_unlock_table(rtable *);
+struct f_trie * rt_lock_trie(rtable *tab);
+void rt_unlock_trie(rtable *tab, struct f_trie *trie);
void rt_subscribe(rtable *tab, struct rt_subscription *s);
void rt_unsubscribe(struct rt_subscription *s);
-void rt_setup(pool *, rtable *, struct rtable_config *);
+void rt_flowspec_link(rtable *src, rtable *dst);
+void rt_flowspec_unlink(rtable *src, rtable *dst);
+rtable *rt_setup(pool *, struct rtable_config *);
+static inline void rt_shutdown(rtable *r) { rfree(r->rp); }
+
static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
static inline net *net_find_valid(rtable *tab, const net_addr *addr)
{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
-void *net_route(rtable *tab, const net_addr *n);
+net *net_get(rtable *tab, const net_addr *addr);
+net *net_route(rtable *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
rte *rte_find(net *net, struct rte_src *src);
rte *rte_get_temp(struct rta *);
@@ -348,6 +381,18 @@ void rt_prune_sync(rtable *t, int all);
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
+static inline int rt_is_ip(rtable *tab)
+{ return (tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6); }
+
+static inline int rt_is_vpn(rtable *tab)
+{ return (tab->addr_type == NET_VPN4) || (tab->addr_type == NET_VPN6); }
+
+static inline int rt_is_roa(rtable *tab)
+{ return (tab->addr_type == NET_ROA4) || (tab->addr_type == NET_ROA6); }
+
+static inline int rt_is_flow(rtable *tab)
+{ return (tab->addr_type == NET_FLOW4) || (tab->addr_type == NET_FLOW6); }
+
/* Default limit for ECMP next hops, defined in sysdep code */
extern const int rt_default_ecmp;
@@ -364,6 +409,8 @@ struct rt_show_data {
struct rt_show_data_rtable *tab; /* Iterator over table list */
struct rt_show_data_rtable *last_table; /* Last table in output */
struct fib_iterator fit; /* Iterator over networks in table */
+ struct f_trie_walk_state *walk_state; /* Iterator over networks in trie */
+ struct f_trie *walk_lock; /* Locked trie for walking */
int verbose, tables_defined_by;
const struct filter *filter;
struct proto *show_protocol;
@@ -371,9 +418,10 @@ struct rt_show_data {
struct channel *export_channel;
struct config *running_on_config;
struct krt_proto *kernel;
- int export_mode, primary_only, filtered, stats, show_for;
+ int export_mode, addr_mode, primary_only, filtered, stats;
int table_open; /* Iteration (fit) is open */
+ int trie_walk; /* Current table is iterated using trie */
int net_counter, rt_counter, show_counter, table_counter;
int net_counter_last, rt_counter_last, show_counter_last;
};
@@ -390,6 +438,11 @@ struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t
#define RSD_TDB_SET 0x1 /* internal: show empty tables */
#define RSD_TDB_NMN 0x2 /* internal: need matching net */
+/* Value of addr_mode */
+#define RSD_ADDR_EQUAL 1 /* Exact query - show route <addr> */
+#define RSD_ADDR_FOR 2 /* Longest prefix match - show route for <addr> */
+#define RSD_ADDR_IN 3 /* Interval query - show route in <addr> */
+
/* Value of export_mode in struct rt_show_data */
#define RSEM_NONE 0 /* Export mode not used */
#define RSEM_PREEXPORT 1 /* Routes ready for export, before filtering */
@@ -710,6 +763,9 @@ rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr
static inline void rt_lock_hostentry(struct hostentry *he) { if (he) he->uc++; }
static inline void rt_unlock_hostentry(struct hostentry *he) { if (he) he->uc--; }
+int rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior);
+
+
/*
* Default protocol preferences
*/
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 25e39488..c630aa95 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -748,14 +748,22 @@ static inline ea_list *
ea_list_copy(ea_list *o)
{
ea_list *n;
- unsigned i, len;
+ unsigned i, adpos, elen;
if (!o)
return NULL;
ASSERT(!o->next);
- len = sizeof(ea_list) + sizeof(eattr) * o->count;
- n = mb_alloc(rta_pool, len);
- memcpy(n, o, len);
+ elen = adpos = sizeof(ea_list) + sizeof(eattr) * o->count;
+
+ for(i=0; i<o->count; i++)
+ {
+ eattr *a = &o->attrs[i];
+ if (!(a->type & EAF_EMBEDDED))
+ elen += sizeof(struct adata) + a->u.ptr->length;
+ }
+
+ n = mb_alloc(rta_pool, elen);
+ memcpy(n, o, adpos);
n->flags |= EALF_CACHED;
for(i=0; i<o->count; i++)
{
@@ -763,28 +771,25 @@ ea_list_copy(ea_list *o)
if (!(a->type & EAF_EMBEDDED))
{
unsigned size = sizeof(struct adata) + a->u.ptr->length;
- struct adata *d = mb_alloc(rta_pool, size);
+ ASSERT_DIE(adpos + size <= elen);
+
+ struct adata *d = ((void *) n) + adpos;
memcpy(d, a->u.ptr, size);
a->u.ptr = d;
+
+ adpos += size;
}
}
+ ASSERT_DIE(adpos == elen);
return n;
}
static inline void
ea_free(ea_list *o)
{
- int i;
-
if (o)
{
ASSERT(!o->next);
- for(i=0; i<o->count; i++)
- {
- eattr *a = &o->attrs[i];
- if (!(a->type & EAF_EMBEDDED))
- mb_free((void *) a->u.ptr);
- }
mb_free(o);
}
}
diff --git a/nest/rt-fib.c b/nest/rt-fib.c
index a7f70371..1690a8f6 100644
--- a/nest/rt-fib.c
+++ b/nest/rt-fib.c
@@ -331,7 +331,7 @@ fib_get(struct fib *f, const net_addr *a)
memset(b, 0, f->node_offset);
if (f->init)
- f->init(b);
+ f->init(f, b);
if (f->entries++ > f->entries_max)
fib_rehash(f, HASH_HI_STEP);
diff --git a/nest/rt-show.c b/nest/rt-show.c
index 7691878d..f8b7ba51 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -15,6 +15,7 @@
#include "nest/cli.h"
#include "nest/iface.h"
#include "filter/filter.h"
+#include "filter/data.h"
#include "sysdep/unix/krt.h"
static void
@@ -110,10 +111,9 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
ASSUME(!d->export_mode || ec);
int first = 1;
+ int first_show = 1;
int pass = 0;
- bsnprintf(ia, sizeof(ia), "%N", n->n.addr);
-
for (e = n->routes; e; e = e->next)
{
if (rte_is_filtered(e) != d->filtered)
@@ -187,10 +187,17 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
goto skip;
if (d->stats < 2)
+ {
+ if (first_show)
+ net_format(n->n.addr, ia, sizeof(ia));
+ else
+ ia[0] = 0;
+
rt_show_rte(c, ia, e, d, (e->net->routes == ee));
+ first_show = 0;
+ }
d->show_counter++;
- ia[0] = 0;
skip:
if (e != ee)
@@ -212,9 +219,12 @@ rt_show_cleanup(struct cli *c)
struct rt_show_data_rtable *tab;
/* Unlink the iterator */
- if (d->table_open)
+ if (d->table_open && !d->trie_walk)
fit_get(&d->tab->table->fib, &d->fit);
+ if (d->walk_lock)
+ rt_unlock_trie(d->tab->table, d->walk_lock);
+
/* Unlock referenced tables */
WALK_LIST(tab, d->tables)
rt_unlock_table(tab->table);
@@ -224,12 +234,13 @@ static void
rt_show_cont(struct cli *c)
{
struct rt_show_data *d = c->rover;
+ struct rtable *tab = d->tab->table;
#ifdef DEBUGGING
unsigned max = 4;
#else
unsigned max = 64;
#endif
- struct fib *fib = &d->tab->table->fib;
+ struct fib *fib = &tab->fib;
struct fib_iterator *it = &d->fit;
if (d->running_on_config && (d->running_on_config != config))
@@ -240,7 +251,22 @@ rt_show_cont(struct cli *c)
if (!d->table_open)
{
- FIB_ITERATE_INIT(&d->fit, &d->tab->table->fib);
+ /* We use either trie-based walk or fib-based walk */
+ d->trie_walk = tab->trie &&
+ (d->addr_mode == RSD_ADDR_IN) &&
+ net_val_match(tab->addr_type, NB_IP);
+
+ if (d->trie_walk && !d->walk_state)
+ d->walk_state = lp_allocz(c->parser_pool, sizeof (struct f_trie_walk_state));
+
+ if (d->trie_walk)
+ {
+ d->walk_lock = rt_lock_trie(tab);
+ trie_walk_init(d->walk_state, tab->trie, d->addr);
+ }
+ else
+ FIB_ITERATE_INIT(&d->fit, &tab->fib);
+
d->table_open = 1;
d->table_counter++;
d->kernel = rt_show_get_kernel(d);
@@ -253,16 +279,44 @@ rt_show_cont(struct cli *c)
rt_show_table(c, d);
}
- FIB_ITERATE_START(fib, it, net, n)
+ if (d->trie_walk)
+ {
+ /* Trie-based walk */
+ net_addr addr;
+ while (trie_walk_next(d->walk_state, &addr))
+ {
+ net *n = net_find(tab, &addr);
+ if (!n)
+ continue;
+
+ rt_show_net(c, n, d);
+
+ if (!--max)
+ return;
+ }
+
+ rt_unlock_trie(tab, d->walk_lock);
+ d->walk_lock = NULL;
+ }
+ else
{
- if (!max--)
+ /* fib-based walk */
+ FIB_ITERATE_START(fib, it, net, n)
{
- FIB_ITERATE_PUT(it);
- return;
+ if ((d->addr_mode == RSD_ADDR_IN) && (!net_in_netX(n->n.addr, d->addr)))
+ goto next;
+
+ if (!max--)
+ {
+ FIB_ITERATE_PUT(it);
+ return;
+ }
+ rt_show_net(c, n, d);
+
+ next:;
}
- rt_show_net(c, n, d);
+ FIB_ITERATE_END;
}
- FIB_ITERATE_END;
if (d->stats)
{
@@ -271,7 +325,7 @@ rt_show_cont(struct cli *c)
cli_printf(c, -1007, "%d of %d routes for %d networks in table %s",
d->show_counter - d->show_counter_last, d->rt_counter - d->rt_counter_last,
- d->net_counter - d->net_counter_last, d->tab->table->name);
+ d->net_counter - d->net_counter_last, tab->name);
}
d->kernel = NULL;
@@ -402,7 +456,7 @@ rt_show(struct rt_show_data *d)
rt_show_prepare_tables(d);
- if (!d->addr)
+ if (!d->addr || (d->addr_mode == RSD_ADDR_IN))
{
WALK_LIST(tab, d->tables)
rt_lock_table(tab->table);
@@ -420,7 +474,7 @@ rt_show(struct rt_show_data *d)
d->tab = tab;
d->kernel = rt_show_get_kernel(d);
- if (d->show_for)
+ if (d->addr_mode == RSD_ADDR_FOR)
n = net_route(tab->table, d->addr);
else
n = net_find(tab->table, d->addr);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 626c2fb8..a10979e6 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -26,6 +26,66 @@
* (see the route attribute module for a precise explanation) holding the
* remaining route attributes which are expected to be shared by multiple
* routes in order to conserve memory.
+ *
+ * There are several mechanisms that allow automatic update of routes in one
+ * routing table (dst) as a result of changes in another routing table (src).
+ * They handle issues of recursive next hop resolving, flowspec validation and
+ * RPKI validation.
+ *
+ * The first such mechanism is handling of recursive next hops. A route in the
+ * dst table has an indirect next hop address, which is resolved through a route
+ * in the src table (which may also be the same table) to get an immediate next
+ * hop. This is implemented using structure &hostcache attached to the src
+ * table, which contains &hostentry structures for each tracked next hop
+ * address. These structures are linked from recursive routes in dst tables,
+ * possibly multiple routes sharing one hostentry (as many routes may have the
+ * same indirect next hop). There is also a trie in the hostcache, which matches
+ * all prefixes that may influence resolving of tracked next hops.
+ *
+ * When a best route changes in the src table, the hostcache is notified using
+ * rt_notify_hostcache(), which immediately checks using the trie whether the
+ * change is relevant and if it is, then it schedules asynchronous hostcache
+ * recomputation. The recomputation is done by rt_update_hostcache() (called
+ * from rt_event() of src table), it walks through all hostentries and resolves
+ * them (by rt_update_hostentry()). It also updates the trie. If a change in
+ * hostentry resolution was found, then it schedules asynchronous nexthop
+ * recomputation of associated dst table. That is done by rt_next_hop_update()
+ * (called from rt_event() of dst table), it iterates over all routes in the dst
+ * table and re-examines their hostentries for changes. Note that in contrast to
+ * hostcache update, next hop update can be interrupted by main loop. These two
+ * full-table walks (over hostcache and dst table) are necessary due to absence
+ * of direct lookups (route -> affected nexthop, nexthop -> its route).
+ *
+ * The second mechanism is for flowspec validation, where validity of flowspec
+ * routes depends of resolving their network prefixes in IP routing tables. This
+ * is similar to the recursive next hop mechanism, but simpler as there are no
+ * intermediate hostcache and hostentries (because flows are less likely to
+ * share common net prefix than routes sharing a common next hop). In src table,
+ * there is a list of dst tables (list flowspec_links), this list is updated by
+ * flowpsec channels (by rt_flowspec_link() and rt_flowspec_unlink() during
+ * channel start/stop). Each dst table has its own trie of prefixes that may
+ * influence validation of flowspec routes in it (flowspec_trie).
+ *
+ * When a best route changes in the src table, rt_flowspec_notify() immediately
+ * checks all dst tables from the list using their tries to see whether the
+ * change is relevant for them. If it is, then an asynchronous re-validation of
+ * flowspec routes in the dst table is scheduled. That is also done by function
+ * rt_next_hop_update(), like nexthop recomputation above. It iterates over all
+ * flowspec routes and re-validates them. It also recalculates the trie.
+ *
+ * Note that in contrast to the hostcache update, here the trie is recalculated
+ * during the rt_next_hop_update(), which may be interleaved with IP route
+ * updates. The trie is flushed at the beginning of recalculation, which means
+ * that such updates may use partial trie to see if they are relevant. But it
+ * works anyway! Either affected flowspec was already re-validated and added to
+ * the trie, then IP route change would match the trie and trigger a next round
+ * of re-validation, or it was not yet re-validated and added to the trie, but
+ * will be re-validated later in this round anyway.
+ *
+ * The third mechanism is used for RPKI re-validation of IP routes and it is the
+ * simplest. It is just a list of subscribers in src table, who are notified
+ * when any change happened, but only after a settle time. Also, in RPKI case
+ * the dst is not a table, but a channel, who refeeds routes through a filter.
*/
#undef LOCAL_DEBUG
@@ -44,6 +104,7 @@
#include "lib/hash.h"
#include "lib/string.h"
#include "lib/alloca.h"
+#include "lib/flowspec.h"
#ifdef CONFIG_BGP
#include "proto/bgp/bgp.h"
@@ -62,41 +123,184 @@ static void rt_update_hostcache(rtable *tab);
static void rt_next_hop_update(rtable *tab);
static inline void rt_prune_table(rtable *tab);
static inline void rt_schedule_notify(rtable *tab);
+static void rt_flowspec_notify(rtable *tab, net *net);
+
+
+static void
+net_init_with_trie(struct fib *f, void *N)
+{
+ rtable *tab = SKIP_BACK(rtable, fib, f);
+ net *n = N;
+
+ if (tab->trie)
+ trie_add_prefix(tab->trie, n->n.addr, n->n.addr->pxlen, n->n.addr->pxlen);
+
+ if (tab->trie_new)
+ trie_add_prefix(tab->trie_new, n->n.addr, n->n.addr->pxlen, n->n.addr->pxlen);
+}
+
+static inline net *
+net_route_ip4_trie(rtable *t, const net_addr_ip4 *n0)
+{
+ TRIE_WALK_TO_ROOT_IP4(t->trie, n0, n)
+ {
+ net *r;
+ if (r = net_find_valid(t, (net_addr *) &n))
+ return r;
+ }
+ TRIE_WALK_TO_ROOT_END;
+
+ return NULL;
+}
+
+static inline net *
+net_route_vpn4_trie(rtable *t, const net_addr_vpn4 *n0)
+{
+ TRIE_WALK_TO_ROOT_IP4(t->trie, (const net_addr_ip4 *) n0, px)
+ {
+ net_addr_vpn4 n = NET_ADDR_VPN4(px.prefix, px.pxlen, n0->rd);
+
+ net *r;
+ if (r = net_find_valid(t, (net_addr *) &n))
+ return r;
+ }
+ TRIE_WALK_TO_ROOT_END;
+
+ return NULL;
+}
+
+static inline net *
+net_route_ip6_trie(rtable *t, const net_addr_ip6 *n0)
+{
+ TRIE_WALK_TO_ROOT_IP6(t->trie, n0, n)
+ {
+ net *r;
+ if (r = net_find_valid(t, (net_addr *) &n))
+ return r;
+ }
+ TRIE_WALK_TO_ROOT_END;
+
+ return NULL;
+}
+static inline net *
+net_route_vpn6_trie(rtable *t, const net_addr_vpn6 *n0)
+{
+ TRIE_WALK_TO_ROOT_IP6(t->trie, (const net_addr_ip6 *) n0, px)
+ {
+ net_addr_vpn6 n = NET_ADDR_VPN6(px.prefix, px.pxlen, n0->rd);
+
+ net *r;
+ if (r = net_find_valid(t, (net_addr *) &n))
+ return r;
+ }
+ TRIE_WALK_TO_ROOT_END;
+
+ return NULL;
+}
-/* Like fib_route(), but skips empty net entries */
static inline void *
-net_route_ip4(rtable *t, net_addr_ip4 *n)
+net_route_ip6_sadr_trie(rtable *t, const net_addr_ip6_sadr *n0)
{
+ TRIE_WALK_TO_ROOT_IP6(t->trie, (const net_addr_ip6 *) n0, px)
+ {
+ net_addr_ip6_sadr n = NET_ADDR_IP6_SADR(px.prefix, px.pxlen, n0->src_prefix, n0->src_pxlen);
+ net *best = NULL;
+ int best_pxlen = 0;
+
+ /* We need to do dst first matching. Since sadr addresses are hashed on dst
+ prefix only, find the hash table chain and go through it to find the
+ match with the longest matching src prefix. */
+ for (struct fib_node *fn = fib_get_chain(&t->fib, (net_addr *) &n); fn; fn = fn->next)
+ {
+ net_addr_ip6_sadr *a = (void *) fn->addr;
+
+ if (net_equal_dst_ip6_sadr(&n, a) &&
+ net_in_net_src_ip6_sadr(&n, a) &&
+ (a->src_pxlen >= best_pxlen))
+ {
+ best = fib_node_to_user(&t->fib, fn);
+ best_pxlen = a->src_pxlen;
+ }
+ }
+
+ if (best)
+ return best;
+ }
+ TRIE_WALK_TO_ROOT_END;
+
+ return NULL;
+}
+
+static inline net *
+net_route_ip4_fib(rtable *t, const net_addr_ip4 *n0)
+{
+ net_addr_ip4 n;
+ net_copy_ip4(&n, n0);
+
net *r;
+ while (r = net_find_valid(t, (net_addr *) &n), (!r) && (n.pxlen > 0))
+ {
+ n.pxlen--;
+ ip4_clrbit(&n.prefix, n.pxlen);
+ }
+
+ return r;
+}
- while (r = net_find_valid(t, (net_addr *) n), (!r) && (n->pxlen > 0))
+static inline net *
+net_route_vpn4_fib(rtable *t, const net_addr_vpn4 *n0)
+{
+ net_addr_vpn4 n;
+ net_copy_vpn4(&n, n0);
+
+ net *r;
+ while (r = net_find_valid(t, (net_addr *) &n), (!r) && (n.pxlen > 0))
{
- n->pxlen--;
- ip4_clrbit(&n->prefix, n->pxlen);
+ n.pxlen--;
+ ip4_clrbit(&n.prefix, n.pxlen);
}
return r;
}
-static inline void *
-net_route_ip6(rtable *t, net_addr_ip6 *n)
+static inline net *
+net_route_ip6_fib(rtable *t, const net_addr_ip6 *n0)
{
+ net_addr_ip6 n;
+ net_copy_ip6(&n, n0);
+
net *r;
+ while (r = net_find_valid(t, (net_addr *) &n), (!r) && (n.pxlen > 0))
+ {
+ n.pxlen--;
+ ip6_clrbit(&n.prefix, n.pxlen);
+ }
- while (r = net_find_valid(t, (net_addr *) n), (!r) && (n->pxlen > 0))
+ return r;
+}
+
+static inline net *
+net_route_vpn6_fib(rtable *t, const net_addr_vpn6 *n0)
+{
+ net_addr_vpn6 n;
+ net_copy_vpn6(&n, n0);
+
+ net *r;
+ while (r = net_find_valid(t, (net_addr *) &n), (!r) && (n.pxlen > 0))
{
- n->pxlen--;
- ip6_clrbit(&n->prefix, n->pxlen);
+ n.pxlen--;
+ ip6_clrbit(&n.prefix, n.pxlen);
}
return r;
}
static inline void *
-net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n)
+net_route_ip6_sadr_fib(rtable *t, const net_addr_ip6_sadr *n0)
{
- struct fib_node *fn;
+ net_addr_ip6_sadr n;
+ net_copy_ip6_sadr(&n, n0);
while (1)
{
@@ -105,13 +309,13 @@ net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n)
/* We need to do dst first matching. Since sadr addresses are hashed on dst
prefix only, find the hash table chain and go through it to find the
- match with the smallest matching src prefix. */
- for (fn = fib_get_chain(&t->fib, (net_addr *) n); fn; fn = fn->next)
+ match with the longest matching src prefix. */
+ for (struct fib_node *fn = fib_get_chain(&t->fib, (net_addr *) &n); fn; fn = fn->next)
{
net_addr_ip6_sadr *a = (void *) fn->addr;
- if (net_equal_dst_ip6_sadr(n, a) &&
- net_in_net_src_ip6_sadr(n, a) &&
+ if (net_equal_dst_ip6_sadr(&n, a) &&
+ net_in_net_src_ip6_sadr(&n, a) &&
(a->src_pxlen >= best_pxlen))
{
best = fib_node_to_user(&t->fib, fn);
@@ -122,38 +326,52 @@ net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n)
if (best)
return best;
- if (!n->dst_pxlen)
+ if (!n.dst_pxlen)
break;
- n->dst_pxlen--;
- ip6_clrbit(&n->dst_prefix, n->dst_pxlen);
+ n.dst_pxlen--;
+ ip6_clrbit(&n.dst_prefix, n.dst_pxlen);
}
return NULL;
}
-void *
+net *
net_route(rtable *tab, const net_addr *n)
{
ASSERT(tab->addr_type == n->type);
- net_addr *n0 = alloca(n->length);
- net_copy(n0, n);
-
switch (n->type)
{
case NET_IP4:
+ if (tab->trie)
+ return net_route_ip4_trie(tab, (net_addr_ip4 *) n);
+ else
+ return net_route_ip4_fib (tab, (net_addr_ip4 *) n);
+
case NET_VPN4:
- case NET_ROA4:
- return net_route_ip4(tab, (net_addr_ip4 *) n0);
+ if (tab->trie)
+ return net_route_vpn4_trie(tab, (net_addr_vpn4 *) n);
+ else
+ return net_route_vpn4_fib (tab, (net_addr_vpn4 *) n);
case NET_IP6:
+ if (tab->trie)
+ return net_route_ip6_trie(tab, (net_addr_ip6 *) n);
+ else
+ return net_route_ip6_fib (tab, (net_addr_ip6 *) n);
+
case NET_VPN6:
- case NET_ROA6:
- return net_route_ip6(tab, (net_addr_ip6 *) n0);
+ if (tab->trie)
+ return net_route_vpn6_trie(tab, (net_addr_vpn6 *) n);
+ else
+ return net_route_vpn6_fib (tab, (net_addr_vpn6 *) n);
case NET_IP6_SADR:
- return net_route_ip6_sadr(tab, (net_addr_ip6_sadr *) n0);
+ if (tab->trie)
+ return net_route_ip6_sadr_trie(tab, (net_addr_ip6_sadr *) n);
+ else
+ return net_route_ip6_sadr_fib (tab, (net_addr_ip6_sadr *) n);
default:
return NULL;
@@ -162,7 +380,35 @@ net_route(rtable *tab, const net_addr *n)
static int
-net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn)
+net_roa_check_ip4_trie(rtable *tab, const net_addr_ip4 *px, u32 asn)
+{
+ int anything = 0;
+
+ TRIE_WALK_TO_ROOT_IP4(tab->trie, px, px0)
+ {
+ net_addr_roa4 roa0 = NET_ADDR_ROA4(px0.prefix, px0.pxlen, 0, 0);
+
+ struct fib_node *fn;
+ for (fn = fib_get_chain(&tab->fib, (net_addr *) &roa0); fn; fn = fn->next)
+ {
+ net_addr_roa4 *roa = (void *) fn->addr;
+ net *r = fib_node_to_user(&tab->fib, fn);
+
+ if (net_equal_prefix_roa4(roa, &roa0) && rte_is_valid(r->routes))
+ {
+ anything = 1;
+ if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
+ return ROA_VALID;
+ }
+ }
+ }
+ TRIE_WALK_TO_ROOT_END;
+
+ return anything ? ROA_INVALID : ROA_UNKNOWN;
+}
+
+static int
+net_roa_check_ip4_fib(rtable *tab, const net_addr_ip4 *px, u32 asn)
{
struct net_addr_roa4 n = NET_ADDR_ROA4(px->prefix, px->pxlen, 0, 0);
struct fib_node *fn;
@@ -194,7 +440,35 @@ net_roa_check_ip4(rtable *tab, const net_addr_ip4 *px, u32 asn)
}
static int
-net_roa_check_ip6(rtable *tab, const net_addr_ip6 *px, u32 asn)
+net_roa_check_ip6_trie(rtable *tab, const net_addr_ip6 *px, u32 asn)
+{
+ int anything = 0;
+
+ TRIE_WALK_TO_ROOT_IP6(tab->trie, px, px0)
+ {
+ net_addr_roa6 roa0 = NET_ADDR_ROA6(px0.prefix, px0.pxlen, 0, 0);
+
+ struct fib_node *fn;
+ for (fn = fib_get_chain(&tab->fib, (net_addr *) &roa0); fn; fn = fn->next)
+ {
+ net_addr_roa6 *roa = (void *) fn->addr;
+ net *r = fib_node_to_user(&tab->fib, fn);
+
+ if (net_equal_prefix_roa6(roa, &roa0) && rte_is_valid(r->routes))
+ {
+ anything = 1;
+ if (asn && (roa->asn == asn) && (roa->max_pxlen >= px->pxlen))
+ return ROA_VALID;
+ }
+ }
+ }
+ TRIE_WALK_TO_ROOT_END;
+
+ return anything ? ROA_INVALID : ROA_UNKNOWN;
+}
+
+static int
+net_roa_check_ip6_fib(rtable *tab, const net_addr_ip6 *px, u32 asn)
{
struct net_addr_roa6 n = NET_ADDR_ROA6(px->prefix, px->pxlen, 0, 0);
struct fib_node *fn;
@@ -244,9 +518,19 @@ int
net_roa_check(rtable *tab, const net_addr *n, u32 asn)
{
if ((tab->addr_type == NET_ROA4) && (n->type == NET_IP4))
- return net_roa_check_ip4(tab, (const net_addr_ip4 *) n, asn);
+ {
+ if (tab->trie)
+ return net_roa_check_ip4_trie(tab, (const net_addr_ip4 *) n, asn);
+ else
+ return net_roa_check_ip4_fib (tab, (const net_addr_ip4 *) n, asn);
+ }
else if ((tab->addr_type == NET_ROA6) && (n->type == NET_IP6))
- return net_roa_check_ip6(tab, (const net_addr_ip6 *) n, asn);
+ {
+ if (tab->trie)
+ return net_roa_check_ip6_trie(tab, (const net_addr_ip6 *) n, asn);
+ else
+ return net_roa_check_ip6_fib (tab, (const net_addr_ip6 *) n, asn);
+ }
else
return ROA_UNKNOWN; /* Should not happen */
}
@@ -618,6 +902,12 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
goto reject;
}
+#ifdef CONFIG_PIPE
+ /* Pipes need rte with stored tmpattrs, remaining protocols need expanded tmpattrs */
+ if (p->proto == &proto_pipe)
+ rte_store_tmp_attrs(rt, pool, NULL);
+#endif
+
accept:
if (rt != rt0)
*rt_free = rt;
@@ -968,6 +1258,9 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
if (tab->hostcache)
rt_notify_hostcache(tab, net);
+
+ if (!EMPTY_LIST(tab->flowspec_links))
+ rt_flowspec_notify(tab, net);
}
rt_schedule_notify(tab);
@@ -1029,6 +1322,10 @@ rte_validate(rte *e)
if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
{
+ /* Exception for flowspec that failed validation */
+ if (net_is_flow(n->n.addr) && (e->attrs->dest == RTD_UNREACHABLE))
+ return 1;
+
log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
n->n.addr, e->attrs->dest, e->sender->proto->name);
return 0;
@@ -1741,8 +2038,9 @@ void
rt_dump_all(void)
{
rtable *t;
+ node *n;
- WALK_LIST(t, routing_tables)
+ WALK_LIST2(t, n, routing_tables, n)
rt_dump(t);
}
@@ -1838,7 +2136,7 @@ rt_kick_settle_timer(rtable *tab)
tab->base_settle_time = current_time();
if (!tab->settle_timer)
- tab->settle_timer = tm_new_init(rt_table_pool, rt_settle_timer, tab, 0, 0);
+ tab->settle_timer = tm_new_init(tab->rp, rt_settle_timer, tab, 0, 0);
if (!tm_active(tab->settle_timer))
tm_set(tab->settle_timer, rt_settled_time(tab));
@@ -1871,23 +2169,180 @@ rt_unsubscribe(struct rt_subscription *s)
rt_unlock_table(s->tab);
}
+static struct rt_flowspec_link *
+rt_flowspec_find_link(rtable *src, rtable *dst)
+{
+ struct rt_flowspec_link *ln;
+ WALK_LIST(ln, src->flowspec_links)
+ if ((ln->src == src) && (ln->dst == dst))
+ return ln;
+
+ return NULL;
+}
+
+void
+rt_flowspec_link(rtable *src, rtable *dst)
+{
+ ASSERT(rt_is_ip(src));
+ ASSERT(rt_is_flow(dst));
+
+ struct rt_flowspec_link *ln = rt_flowspec_find_link(src, dst);
+
+ if (!ln)
+ {
+ rt_lock_table(src);
+ rt_lock_table(dst);
+
+ ln = mb_allocz(src->rp, sizeof(struct rt_flowspec_link));
+ ln->src = src;
+ ln->dst = dst;
+ add_tail(&src->flowspec_links, &ln->n);
+ }
+
+ ln->uc++;
+}
+
void
-rt_setup(pool *p, rtable *t, struct rtable_config *cf)
+rt_flowspec_unlink(rtable *src, rtable *dst)
{
- bzero(t, sizeof(*t));
+ struct rt_flowspec_link *ln = rt_flowspec_find_link(src, dst);
+
+ ASSERT(ln && (ln->uc > 0));
+
+ ln->uc--;
+
+ if (!ln->uc)
+ {
+ rem_node(&ln->n);
+ mb_free(ln);
+
+ rt_unlock_table(src);
+ rt_unlock_table(dst);
+ }
+}
+
+static void
+rt_flowspec_notify(rtable *src, net *net)
+{
+ /* Only IP tables are src links */
+ ASSERT(rt_is_ip(src));
+
+ struct rt_flowspec_link *ln;
+ WALK_LIST(ln, src->flowspec_links)
+ {
+ rtable *dst = ln->dst;
+ ASSERT(rt_is_flow(dst));
+
+ /* No need to inspect it further if recalculation is already active */
+ if ((dst->nhu_state == NHU_SCHEDULED) || (dst->nhu_state == NHU_DIRTY))
+ continue;
+
+ if (trie_match_net(dst->flowspec_trie, net->n.addr))
+ rt_schedule_nhu(dst);
+ }
+}
+
+static void
+rt_flowspec_reset_trie(rtable *tab)
+{
+ linpool *lp = tab->flowspec_trie->lp;
+ int ipv4 = tab->flowspec_trie->ipv4;
+
+ lp_flush(lp);
+ tab->flowspec_trie = f_new_trie(lp, 0);
+ tab->flowspec_trie->ipv4 = ipv4;
+}
+
+static void
+rt_free(resource *_r)
+{
+ rtable *r = (rtable *) _r;
+
+ DBG("Deleting routing table %s\n", r->name);
+ ASSERT_DIE(r->use_count == 0);
+
+ if (r->internal)
+ return;
+
+ r->config->table = NULL;
+ rem_node(&r->n);
+
+ if (r->hostcache)
+ rt_free_hostcache(r);
+
+ /* Freed automagically by the resource pool
+ fib_free(&r->fib);
+ hmap_free(&r->id_map);
+ rfree(r->rt_event);
+ rfree(r->settle_timer);
+ mb_free(r);
+ */
+}
+
+static void
+rt_res_dump(resource *_r)
+{
+ rtable *r = (rtable *) _r;
+ debug("name \"%s\", addr_type=%s, rt_count=%u, use_count=%d\n",
+ r->name, net_label[r->addr_type], r->rt_count, r->use_count);
+}
+
+static struct resclass rt_class = {
+ .name = "Routing table",
+ .size = sizeof(struct rtable),
+ .free = rt_free,
+ .dump = rt_res_dump,
+ .lookup = NULL,
+ .memsize = NULL,
+};
+
+rtable *
+rt_setup(pool *pp, struct rtable_config *cf)
+{
+ int ns = strlen("Routing table ") + strlen(cf->name) + 1;
+ void *nb = mb_alloc(pp, ns);
+ ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Routing table %s", cf->name));
+
+ pool *p = rp_new(pp, nb);
+ mb_move(nb, p);
+
+ rtable *t = ralloc(p, &rt_class);
+ t->rp = p;
+
t->name = cf->name;
t->config = cf;
t->addr_type = cf->addr_type;
+
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
- init_list(&t->channels);
- hmap_init(&t->id_map, p, 1024);
- hmap_set(&t->id_map, 0);
+ if (cf->trie_used)
+ {
+ t->trie = f_new_trie(lp_new_default(p), 0);
+ t->trie->ipv4 = net_val_match(t->addr_type, NB_IP4 | NB_VPN4 | NB_ROA4);
- t->rt_event = ev_new_init(p, rt_event, t);
- t->last_rt_change = t->gc_time = current_time();
+ t->fib.init = net_init_with_trie;
+ }
+ init_list(&t->channels);
+ init_list(&t->flowspec_links);
init_list(&t->subscribers);
+
+ if (!(t->internal = cf->internal))
+ {
+ hmap_init(&t->id_map, p, 1024);
+ hmap_set(&t->id_map, 0);
+
+ t->rt_event = ev_new_init(p, rt_event, t);
+ t->last_rt_change = t->gc_time = current_time();
+
+ if (rt_is_flow(t))
+ {
+ t->flowspec_trie = f_new_trie(lp_new_default(p), 0);
+ t->flowspec_trie->ipv4 = (t->addr_type == NET_FLOW4);
+ }
+ }
+
+ return t;
}
/**
@@ -1947,6 +2402,13 @@ rt_prune_table(rtable *tab)
FIB_ITERATE_INIT(fit, &tab->fib);
tab->prune_state = 2;
+
+ if (tab->prune_trie)
+ {
+ /* Init prefix trie pruning */
+ tab->trie_new = f_new_trie(lp_new_default(tab->rp), 0);
+ tab->trie_new->ipv4 = tab->trie->ipv4;
+ }
}
again:
@@ -1955,17 +2417,17 @@ again:
rte *e;
rescan:
+ if (limit <= 0)
+ {
+ FIB_ITERATE_PUT(fit);
+ ev_schedule(tab->rt_event);
+ return;
+ }
+
for (e=n->routes; e; e=e->next)
{
if (e->sender->flush_active || (e->flags & REF_DISCARD))
{
- if (limit <= 0)
- {
- FIB_ITERATE_PUT(fit);
- ev_schedule(tab->rt_event);
- return;
- }
-
rte_discard(e);
limit--;
@@ -1974,13 +2436,6 @@ again:
if (e->flags & REF_MODIFY)
{
- if (limit <= 0)
- {
- FIB_ITERATE_PUT(fit);
- ev_schedule(tab->rt_event);
- return;
- }
-
rte_modify(e);
limit--;
@@ -1994,6 +2449,12 @@ again:
fib_delete(&tab->fib, n);
goto again;
}
+
+ if (tab->trie_new)
+ {
+ trie_add_prefix(tab->trie_new, n->n.addr, n->n.addr->pxlen, n->n.addr->pxlen);
+ limit--;
+ }
}
FIB_ITERATE_END;
@@ -2007,6 +2468,37 @@ again:
/* state change 2->0, 3->1 */
tab->prune_state &= 1;
+ if (tab->trie_new)
+ {
+ /* Finish prefix trie pruning */
+
+ if (!tab->trie_lock_count)
+ {
+ rfree(tab->trie->lp);
+ }
+ else
+ {
+ ASSERT(!tab->trie_old);
+ tab->trie_old = tab->trie;
+ tab->trie_old_lock_count = tab->trie_lock_count;
+ tab->trie_lock_count = 0;
+ }
+
+ tab->trie = tab->trie_new;
+ tab->trie_new = NULL;
+ tab->prune_trie = 0;
+ }
+ else
+ {
+ /* Schedule prefix trie pruning */
+ if (tab->trie && !tab->trie_old && (tab->trie->prefix_count > (2 * tab->fib.entries)))
+ {
+ /* state change 0->1, 2->3 */
+ tab->prune_state |= 1;
+ tab->prune_trie = 1;
+ }
+ }
+
if (tab->prune_state > 0)
ev_schedule(tab->rt_event);
@@ -2024,6 +2516,72 @@ again:
return;
}
+/**
+ * rt_lock_trie - lock a prefix trie of a routing table
+ * @tab: routing table with prefix trie to be locked
+ *
+ * The prune loop may rebuild the prefix trie and invalidate f_trie_walk_state
+ * structures. Therefore, asynchronous walks should lock the prefix trie using
+ * this function. That allows the prune loop to rebuild the trie, but postpones
+ * its freeing until all walks are done (unlocked by rt_unlock_trie()).
+ *
+ * Return a current trie that will be locked, the value should be passed back to
+ * rt_unlock_trie() for unlocking.
+ *
+ */
+struct f_trie *
+rt_lock_trie(rtable *tab)
+{
+ ASSERT(tab->trie);
+
+ tab->trie_lock_count++;
+ return tab->trie;
+}
+
+/**
+ * rt_unlock_trie - unlock a prefix trie of a routing table
+ * @tab: routing table with prefix trie to be locked
+ * @trie: value returned by matching rt_lock_trie()
+ *
+ * Done for trie locked by rt_lock_trie() after walk over the trie is done.
+ * It may free the trie and schedule next trie pruning.
+ */
+void
+rt_unlock_trie(rtable *tab, struct f_trie *trie)
+{
+ ASSERT(trie);
+
+ if (trie == tab->trie)
+ {
+ /* Unlock the current prefix trie */
+ ASSERT(tab->trie_lock_count);
+ tab->trie_lock_count--;
+ }
+ else if (trie == tab->trie_old)
+ {
+ /* Unlock the old prefix trie */
+ ASSERT(tab->trie_old_lock_count);
+ tab->trie_old_lock_count--;
+
+ /* Free old prefix trie that is no longer needed */
+ if (!tab->trie_old_lock_count)
+ {
+ rfree(tab->trie_old->lp);
+ tab->trie_old = NULL;
+
+ /* Kick prefix trie pruning that was postponed */
+ if (tab->trie && (tab->trie->prefix_count > (2 * tab->fib.entries)))
+ {
+ tab->prune_trie = 1;
+ rt_schedule_prune(tab);
+ }
+ }
+ }
+ else
+ log(L_BUG "Invalid arg to rt_unlock_trie()");
+}
+
+
void
rt_preconfig(struct config *c)
{
@@ -2039,21 +2597,6 @@ rt_preconfig(struct config *c)
* triggered by rt_schedule_nhu().
*/
-static inline int
-rta_next_hop_outdated(rta *a)
-{
- struct hostentry *he = a->hostentry;
-
- if (!he)
- return 0;
-
- if (!he->src)
- return a->dest != RTD_UNREACHABLE;
-
- return (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
- (!he->nexthop_linkable) || !nexthop_same(&(a->nh), &(he->src->nh));
-}
-
void
rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls)
{
@@ -2145,9 +2688,27 @@ no_nexthop:
}
}
+static inline int
+rta_next_hop_outdated(rta *a)
+{
+ struct hostentry *he = a->hostentry;
+
+ if (!he)
+ return 0;
+
+ if (!he->src)
+ return a->dest != RTD_UNREACHABLE;
+
+ return (a->dest != he->dest) || (a->igp_metric != he->igp_metric) ||
+ (!he->nexthop_linkable) || !nexthop_same(&(a->nh), &(he->src->nh));
+}
+
static inline rte *
rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
{
+ if (!rta_next_hop_outdated(old->attrs))
+ return NULL;
+
rta *a = alloca(RTA_MAX_SIZE);
memcpy(a, old->attrs, rta_size(old->attrs));
@@ -2164,6 +2725,152 @@ rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
return e;
}
+
+#ifdef CONFIG_BGP
+
+static inline int
+net_flow_has_dst_prefix(const net_addr *n)
+{
+ ASSUME(net_is_flow(n));
+
+ if (n->pxlen)
+ return 1;
+
+ if (n->type == NET_FLOW4)
+ {
+ const net_addr_flow4 *n4 = (void *) n;
+ return (n4->length > sizeof(net_addr_flow4)) && (n4->data[0] == FLOW_TYPE_DST_PREFIX);
+ }
+ else
+ {
+ const net_addr_flow6 *n6 = (void *) n;
+ return (n6->length > sizeof(net_addr_flow6)) && (n6->data[0] == FLOW_TYPE_DST_PREFIX);
+ }
+}
+
+static inline int
+rta_as_path_is_empty(rta *a)
+{
+ eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
+ return !e || (as_path_getlen(e->u.ptr) == 0);
+}
+
+static inline u32
+rta_get_first_asn(rta *a)
+{
+ eattr *e = ea_find(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_AS_PATH));
+ u32 asn;
+
+ return (e && as_path_get_first_regular(e->u.ptr, &asn)) ? asn : 0;
+}
+
+int
+rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior)
+{
+ ASSERT(rt_is_ip(tab_ip));
+ ASSERT(rt_is_flow(tab_flow));
+ ASSERT(tab_ip->trie);
+
+ /* RFC 8955 6. a) Flowspec has defined dst prefix */
+ if (!net_flow_has_dst_prefix(n))
+ return 0;
+
+ /* RFC 9117 4.1. Accept AS_PATH is empty (fr */
+ if (interior && rta_as_path_is_empty(a))
+ return 1;
+
+
+ /* RFC 8955 6. b) Flowspec and its best-match route have the same originator */
+
+ /* Find flowspec dst prefix */
+ net_addr dst;
+ if (n->type == NET_FLOW4)
+ net_fill_ip4(&dst, net4_prefix(n), net4_pxlen(n));
+ else
+ net_fill_ip6(&dst, net6_prefix(n), net6_pxlen(n));
+
+ /* Find best-match BGP unicast route for flowspec dst prefix */
+ net *nb = net_route(tab_ip, &dst);
+ rte *rb = nb ? nb->routes : NULL;
+
+ /* Register prefix to trie for tracking further changes */
+ int max_pxlen = (n->type == NET_FLOW4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
+ trie_add_prefix(tab_flow->flowspec_trie, &dst, (nb ? nb->n.addr->pxlen : 0), max_pxlen);
+
+ /* No best-match BGP route -> no flowspec */
+ if (!rb || (rb->attrs->source != RTS_BGP))
+ return 0;
+
+ /* Find ORIGINATOR_ID values */
+ u32 orig_a = ea_get_int(a->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0);
+ u32 orig_b = ea_get_int(rb->attrs->eattrs, EA_CODE(PROTOCOL_BGP, BA_ORIGINATOR_ID), 0);
+
+ /* Originator is either ORIGINATOR_ID (if present), or BGP neighbor address (if not) */
+ if ((orig_a != orig_b) || (!orig_a && !orig_b && !ipa_equal(a->from, rb->attrs->from)))
+ return 0;
+
+
+ /* Find ASN of the best-match route, for use in next checks */
+ u32 asn_b = rta_get_first_asn(rb->attrs);
+ if (!asn_b)
+ return 0;
+
+ /* RFC 9117 4.2. For EBGP, flowspec and its best-match route are from the same AS */
+ if (!interior && (rta_get_first_asn(a) != asn_b))
+ return 0;
+
+ /* RFC 8955 6. c) More-specific routes are from the same AS as the best-match route */
+ TRIE_WALK(tab_ip->trie, subnet, &dst)
+ {
+ net *nc = net_find_valid(tab_ip, &subnet);
+ if (!nc)
+ continue;
+
+ rte *rc = nc->routes;
+ if (rc->attrs->source != RTS_BGP)
+ return 0;
+
+ if (rta_get_first_asn(rc->attrs) != asn_b)
+ return 0;
+ }
+ TRIE_WALK_END;
+
+ return 1;
+}
+
+#endif /* CONFIG_BGP */
+
+static rte *
+rt_flowspec_update_rte(rtable *tab, rte *r)
+{
+#ifdef CONFIG_BGP
+ if ((r->attrs->source != RTS_BGP) || !r->u.bgp.base_table)
+ return NULL;
+
+ const net_addr *n = r->net->n.addr;
+ struct bgp_proto *p = (void *) r->attrs->src->proto;
+ int valid = rt_flowspec_check(r->u.bgp.base_table, tab, n, r->attrs, p->is_interior);
+ int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
+
+ if (dest == r->attrs->dest)
+ return NULL;
+
+ rta *a = alloca(RTA_MAX_SIZE);
+ memcpy(a, r->attrs, rta_size(r->attrs));
+ a->dest = dest;
+ a->aflags = 0;
+
+ rte *new = sl_alloc(rte_slab);
+ memcpy(new, r, sizeof(rte));
+ new->attrs = rta_lookup(a);
+
+ return new;
+#else
+ return NULL;
+#endif
+}
+
+
static inline int
rt_next_hop_update_net(rtable *tab, net *n)
{
@@ -2176,9 +2883,14 @@ rt_next_hop_update_net(rtable *tab, net *n)
return 0;
for (k = &n->routes; e = *k; k = &e->next)
- if (rta_next_hop_outdated(e->attrs))
+ {
+ if (!net_is_flow(n->n.addr))
+ new = rt_next_hop_update_rte(tab, e);
+ else
+ new = rt_flowspec_update_rte(tab, e);
+
+ if (new)
{
- new = rt_next_hop_update_rte(tab, e);
*k = new;
rte_trace_in(D_ROUTES, new->sender, new, "updated");
@@ -2197,6 +2909,7 @@ rt_next_hop_update_net(rtable *tab, net *n)
e = new;
count++;
}
+ }
if (!count)
return 0;
@@ -2244,6 +2957,9 @@ rt_next_hop_update(rtable *tab)
{
FIB_ITERATE_INIT(fit, &tab->fib);
tab->nhu_state = NHU_RUNNING;
+
+ if (tab->flowspec_trie)
+ rt_flowspec_reset_trie(tab);
}
FIB_ITERATE_START(&tab->fib, fit, net, n)
@@ -2325,20 +3041,29 @@ rt_unlock_table(rtable *r)
if (!--r->use_count && r->deleted)
{
struct config *conf = r->deleted;
- DBG("Deleting routing table %s\n", r->name);
- r->config->table = NULL;
- if (r->hostcache)
- rt_free_hostcache(r);
- rem_node(&r->n);
- fib_free(&r->fib);
- hmap_free(&r->id_map);
- rfree(r->rt_event);
- rfree(r->settle_timer);
- mb_free(r);
+
+ /* Delete the routing table by freeing its pool */
+ rt_shutdown(r);
config_del_obstacle(conf);
}
}
+static int
+rt_reconfigure(rtable *tab, struct rtable_config *new, struct rtable_config *old)
+{
+ if ((new->addr_type != old->addr_type) ||
+ (new->sorted != old->sorted) ||
+ (new->trie_used != old->trie_used))
+ return 0;
+
+ DBG("\t%s: same\n", new->name);
+ new->table = tab;
+ tab->name = new->name;
+ tab->config = new;
+
+ return 1;
+}
+
static struct rtable_config *
rt_find_table_config(struct config *cf, char *name)
{
@@ -2368,39 +3093,28 @@ rt_commit(struct config *new, struct config *old)
{
WALK_LIST(o, old->tables)
{
- rtable *ot = o->table;
- if (!ot->deleted)
- {
- r = rt_find_table_config(new, o->name);
- if (r && (r->addr_type == o->addr_type) && !new->shutdown)
- {
- DBG("\t%s: same\n", o->name);
- r->table = ot;
- ot->name = r->name;
- ot->config = r;
- if (o->sorted != r->sorted)
- log(L_WARN "Reconfiguration of rtable sorted flag not implemented");
- }
- else
- {
- DBG("\t%s: deleted\n", o->name);
- ot->deleted = old;
- config_add_obstacle(old);
- rt_lock_table(ot);
- rt_unlock_table(ot);
- }
- }
+ rtable *tab = o->table;
+ if (tab->deleted)
+ continue;
+
+ r = rt_find_table_config(new, o->name);
+ if (r && !new->shutdown && rt_reconfigure(tab, r, o))
+ continue;
+
+ DBG("\t%s: deleted\n", o->name);
+ tab->deleted = old;
+ config_add_obstacle(old);
+ rt_lock_table(tab);
+ rt_unlock_table(tab);
}
}
WALK_LIST(r, new->tables)
if (!r->table)
{
- rtable *t = mb_allocz(rt_table_pool, sizeof(struct rtable));
+ r->table = rt_setup(rt_table_pool, r);
DBG("\t%s: created\n", r->name);
- rt_setup(rt_table_pool, t, r);
- add_tail(&routing_tables, &t->n);
- r->table = t;
+ add_tail(&routing_tables, &r->table->n);
}
DBG("\tdone\n");
}
@@ -2565,6 +3279,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
if (!old)
goto drop_withdraw;
+ if (!net->routes)
+ fib_delete(&tab->fib, net);
+
return 1;
}
@@ -2599,6 +3316,10 @@ drop_update:
c->stats.imp_updates_received++;
c->stats.imp_updates_ignored++;
rte_free(new);
+
+ if (!net->routes)
+ fib_delete(&tab->fib, net);
+
return 0;
drop_withdraw:
@@ -2668,9 +3389,15 @@ rt_reload_channel_abort(struct channel *c)
void
rt_prune_sync(rtable *t, int all)
{
- FIB_WALK(&t->fib, net, n)
+ struct fib_iterator fit;
+
+ FIB_ITERATE_INIT(&fit, &t->fib);
+
+again:
+ FIB_ITERATE_START(&t->fib, &fit, net, n)
{
rte *e, **ee = &n->routes;
+
while (e = *ee)
{
if (all || (e->flags & (REF_STALE | REF_DISCARD)))
@@ -2682,8 +3409,15 @@ rt_prune_sync(rtable *t, int all)
else
ee = &e->next;
}
+
+ if (all || !n->routes)
+ {
+ FIB_ITERATE_PUT(&fit);
+ fib_delete(&t->fib, n);
+ goto again;
+ }
}
- FIB_WALK_END;
+ FIB_ITERATE_END;
}
@@ -2749,6 +3483,9 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
if (!old)
goto drop_withdraw;
+ if (!net->routes)
+ fib_delete(&tab->fib, net);
+
return 1;
}
@@ -2808,7 +3545,7 @@ hc_remove(struct hostcache *hc, struct hostentry *he)
#define HC_LO_ORDER 10
static void
-hc_alloc_table(struct hostcache *hc, unsigned order)
+hc_alloc_table(struct hostcache *hc, pool *p, unsigned order)
{
uint hsize = 1 << order;
hc->hash_order = order;
@@ -2816,18 +3553,18 @@ hc_alloc_table(struct hostcache *hc, unsigned order)
hc->hash_max = (order >= HC_HI_ORDER) ? ~0U : (hsize HC_HI_MARK);
hc->hash_min = (order <= HC_LO_ORDER) ? 0U : (hsize HC_LO_MARK);
- hc->hash_table = mb_allocz(rt_table_pool, hsize * sizeof(struct hostentry *));
+ hc->hash_table = mb_allocz(p, hsize * sizeof(struct hostentry *));
}
static void
-hc_resize(struct hostcache *hc, unsigned new_order)
+hc_resize(struct hostcache *hc, pool *p, unsigned new_order)
{
struct hostentry **old_table = hc->hash_table;
struct hostentry *he, *hen;
uint old_size = 1 << hc->hash_order;
uint i;
- hc_alloc_table(hc, new_order);
+ hc_alloc_table(hc, p, new_order);
for (i = 0; i < old_size; i++)
for (he = old_table[i]; he != NULL; he=hen)
{
@@ -2838,7 +3575,7 @@ hc_resize(struct hostcache *hc, unsigned new_order)
}
static struct hostentry *
-hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsigned k)
+hc_new_hostentry(struct hostcache *hc, pool *p, ip_addr a, ip_addr ll, rtable *dep, unsigned k)
{
struct hostentry *he = sl_alloc(hc->slab);
@@ -2854,13 +3591,13 @@ hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsig
hc->hash_items++;
if (hc->hash_items > hc->hash_max)
- hc_resize(hc, hc->hash_order + HC_HI_STEP);
+ hc_resize(hc, p, hc->hash_order + HC_HI_STEP);
return he;
}
static void
-hc_delete_hostentry(struct hostcache *hc, struct hostentry *he)
+hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he)
{
rta_free(he->src);
@@ -2870,20 +3607,20 @@ hc_delete_hostentry(struct hostcache *hc, struct hostentry *he)
hc->hash_items--;
if (hc->hash_items < hc->hash_min)
- hc_resize(hc, hc->hash_order - HC_LO_STEP);
+ hc_resize(hc, p, hc->hash_order - HC_LO_STEP);
}
static void
rt_init_hostcache(rtable *tab)
{
- struct hostcache *hc = mb_allocz(rt_table_pool, sizeof(struct hostcache));
+ struct hostcache *hc = mb_allocz(tab->rp, sizeof(struct hostcache));
init_list(&hc->hostentries);
hc->hash_items = 0;
- hc_alloc_table(hc, HC_DEF_ORDER);
- hc->slab = sl_new(rt_table_pool, sizeof(struct hostentry));
+ hc_alloc_table(hc, tab->rp, HC_DEF_ORDER);
+ hc->slab = sl_new(tab->rp, sizeof(struct hostentry));
- hc->lp = lp_new(rt_table_pool, LP_GOOD_SIZE(1024));
+ hc->lp = lp_new(tab->rp, LP_GOOD_SIZE(1024));
hc->trie = f_new_trie(hc->lp, 0);
tab->hostcache = hc;
@@ -2904,10 +3641,12 @@ rt_free_hostcache(rtable *tab)
log(L_ERR "Hostcache is not empty in table %s", tab->name);
}
+ /* Freed automagically by the resource pool
rfree(hc->slab);
rfree(hc->lp);
mb_free(hc->hash_table);
mb_free(hc);
+ */
}
static void
@@ -3050,7 +3789,7 @@ rt_update_hostcache(rtable *tab)
he = SKIP_BACK(struct hostentry, ln, n);
if (!he->uc)
{
- hc_delete_hostentry(hc, he);
+ hc_delete_hostentry(hc, tab->rp, he);
continue;
}
@@ -3075,7 +3814,7 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
if (ipa_equal(he->addr, a) && (he->tab == dep))
return he;
- he = hc_new_hostentry(hc, a, ipa_zero(ll) ? a : ll, dep, k);
+ he = hc_new_hostentry(hc, tab->rp, a, ipa_zero(ll) ? a : ll, dep, k);
rt_update_hostentry(tab, he);
return he;
}
diff --git a/proto/babel/Makefile b/proto/babel/Makefile
index a5b4a13b..06b58e95 100644
--- a/proto/babel/Makefile
+++ b/proto/babel/Makefile
@@ -3,4 +3,4 @@ obj := $(src-o-files)
$(all-daemon)
$(cf-local)
-tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
+tests_objs := $(tests_objs) $(src-o-files)
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 4b6b9d7f..e43818f5 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -38,6 +38,8 @@
#include <stdlib.h>
#include "babel.h"
+#define LOG_PKT_AUTH(msg, args...) \
+ log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args)
/*
* Is one number greater or equal than another mod 2^16? This is based on the
@@ -56,19 +58,12 @@ static void babel_update_cost(struct babel_neighbor *n);
static inline void babel_kick_timer(struct babel_proto *p);
static inline void babel_iface_kick_timer(struct babel_iface *ifa);
-static inline void babel_lock_neighbor(struct babel_neighbor *nbr)
-{ if (nbr) nbr->uc++; }
-
-static inline void babel_unlock_neighbor(struct babel_neighbor *nbr)
-{ if (nbr && !--nbr->uc) mb_free(nbr); }
-
-
/*
* Functions to maintain data structures
*/
static void
-babel_init_entry(void *E)
+babel_init_entry(struct fib *f UNUSED, void *E)
{
struct babel_entry *e = E;
@@ -316,8 +311,9 @@ babel_add_seqno_request(struct babel_proto *p, struct babel_entry *e,
return;
/* Found older */
- babel_unlock_neighbor(sr->nbr);
rem_node(NODE sr);
+ rem_node(&sr->nbr_node);
+
goto found;
}
@@ -330,7 +326,10 @@ found:
sr->hop_count = hop_count;
sr->count = 0;
sr->expires = current_time() + BABEL_SEQNO_REQUEST_EXPIRY;
- babel_lock_neighbor(sr->nbr = nbr);
+
+ if (sr->nbr = nbr)
+ add_tail(&nbr->requests, &sr->nbr_node);
+
add_tail(&e->requests, NODE sr);
babel_send_seqno_request(p, e, sr);
@@ -339,7 +338,9 @@ found:
static void
babel_remove_seqno_request(struct babel_proto *p, struct babel_seqno_request *sr)
{
- babel_unlock_neighbor(sr->nbr);
+ if (sr->nbr)
+ rem_node(&sr->nbr_node);
+
rem_node(NODE sr);
sl_free(p->seqno_slab, sr);
}
@@ -426,8 +427,9 @@ babel_get_neighbor(struct babel_iface *ifa, ip_addr addr)
nbr->rxcost = BABEL_INFINITY;
nbr->txcost = BABEL_INFINITY;
nbr->cost = BABEL_INFINITY;
+ nbr->init_expiry = current_time() + BABEL_INITIAL_NEIGHBOR_TIMEOUT;
init_list(&nbr->routes);
- babel_lock_neighbor(nbr);
+ init_list(&nbr->requests);
add_tail(&ifa->neigh_list, NODE nbr);
return nbr;
@@ -448,9 +450,16 @@ babel_flush_neighbor(struct babel_proto *p, struct babel_neighbor *nbr)
babel_flush_route(p, r);
}
+ struct babel_seqno_request *sr;
+ WALK_LIST_FIRST2(sr, nbr_node, nbr->requests)
+ {
+ sr->nbr = NULL;
+ rem_node(&sr->nbr_node);
+ }
+
nbr->ifa = NULL;
rem_node(NODE nbr);
- babel_unlock_neighbor(nbr);
+ mb_free(nbr);
}
static void
@@ -501,13 +510,15 @@ babel_expire_neighbors(struct babel_proto *p)
if (nbr->ihu_expiry && nbr->ihu_expiry <= now_)
babel_expire_ihu(p, nbr);
+ if (nbr->init_expiry && nbr->init_expiry <= now_)
+ { babel_flush_neighbor(p, nbr); continue; }
+
if (nbr->hello_expiry && nbr->hello_expiry <= now_)
- babel_expire_hello(p, nbr, now_);
+ { babel_expire_hello(p, nbr, now_); continue; }
}
}
}
-
/*
* Best route selection
*/
@@ -1103,6 +1114,9 @@ babel_update_hello_history(struct babel_neighbor *n, u16 seqno, uint interval)
/* Update expiration */
n->hello_expiry = current_time() + BABEL_HELLO_EXPIRY_FACTOR(interval);
n->last_hello_int = interval;
+
+ /* Disable initial timeout */
+ n->init_expiry = 0;
}
@@ -1382,6 +1396,130 @@ babel_handle_seqno_request(union babel_msg *m, struct babel_iface *ifa)
}
}
+/*
+ * Authentication functions
+ */
+
+/**
+ * babel_auth_reset_index - Reset authentication index on interface
+ * @ifa: Interface to reset
+ *
+ * This function resets the authentication index and packet counter for an
+ * interface, and should be called on interface configuration, or when the
+ * packet counter overflows.
+ */
+void
+babel_auth_reset_index(struct babel_iface *ifa)
+{
+ random_bytes(ifa->auth_index, BABEL_AUTH_INDEX_LEN);
+ ifa->auth_pc = 1;
+}
+
+static void
+babel_auth_send_challenge_request(struct babel_iface *ifa, struct babel_neighbor *n)
+{
+ struct babel_proto *p = ifa->proto;
+ union babel_msg msg = {};
+
+ TRACE(D_PACKETS, "Sending challenge request to %I on %s",
+ n->addr, ifa->ifname);
+
+ random_bytes(n->auth_nonce, BABEL_AUTH_NONCE_LEN);
+ n->auth_nonce_expiry = current_time() + BABEL_AUTH_CHALLENGE_TIMEOUT;
+ n->auth_next_challenge = current_time() + BABEL_AUTH_CHALLENGE_INTERVAL;
+
+ msg.type = BABEL_TLV_CHALLENGE_REQUEST;
+ msg.challenge.nonce_len = BABEL_AUTH_NONCE_LEN;
+ msg.challenge.nonce = n->auth_nonce;
+
+ babel_send_unicast(&msg, ifa, n->addr);
+}
+
+static void
+babel_auth_send_challenge_reply(struct babel_iface *ifa, struct babel_neighbor *n, struct babel_msg_auth *rcv)
+{
+ struct babel_proto *p = ifa->proto;
+ union babel_msg msg = {};
+
+ TRACE(D_PACKETS, "Sending challenge reply to %I on %s",
+ n->addr, ifa->ifname);
+
+ n->auth_next_challenge_reply = current_time() + BABEL_AUTH_CHALLENGE_INTERVAL;
+
+ msg.type = BABEL_TLV_CHALLENGE_REPLY;
+ msg.challenge.nonce_len = rcv->challenge_len;
+ msg.challenge.nonce = rcv->challenge;
+
+ babel_send_unicast(&msg, ifa, n->addr);
+}
+
+int
+babel_auth_check_pc(struct babel_iface *ifa, struct babel_msg_auth *msg)
+{
+ struct babel_proto *p = ifa->proto;
+ struct babel_neighbor *n;
+
+ /*
+ * We create the neighbour entry at this point because it makes it easier to
+ * rate limit challenge replies; this is explicitly allowed by the spec (see
+ * Section 4.3).
+ */
+ n = babel_get_neighbor(ifa, msg->sender);
+
+ /* (3b) Handle challenge request */
+ if (msg->challenge_seen && (n->auth_next_challenge_reply <= current_time()))
+ babel_auth_send_challenge_reply(ifa, n, msg);
+
+ /* (4a) If PC TLV is missing, drop the packet */
+ if (!msg->pc_seen)
+ {
+ LOG_PKT_AUTH("Authentication failed for %I on %s - missing or invalid PC",
+ msg->sender, ifa->ifname);
+ return 0;
+ }
+
+ /* (4b) On successful challenge, update PC and index to current values */
+ if (msg->challenge_reply_seen &&
+ (n->auth_nonce_expiry > current_time()) &&
+ !memcmp(msg->challenge_reply, n->auth_nonce, BABEL_AUTH_NONCE_LEN))
+ {
+ n->auth_index_len = msg->index_len;
+ memcpy(n->auth_index, msg->index, msg->index_len);
+
+ n->auth_pc = msg->pc;
+ n->auth_passed = 1;
+
+ return 1;
+ }
+
+ /* (5) If index differs, send challenge and drop the packet */
+ if ((n->auth_index_len != msg->index_len) ||
+ memcmp(n->auth_index, msg->index, msg->index_len))
+ {
+ TRACE(D_PACKETS, "Index mismatch for packet from %I via %s",
+ msg->sender, ifa->ifname);
+
+ if (n->auth_next_challenge <= current_time())
+ babel_auth_send_challenge_request(ifa, n);
+
+ return 0;
+ }
+
+ /* (6) Index matches; only accept if PC is greater than last */
+ if (n->auth_pc >= msg->pc)
+ {
+ LOG_PKT_AUTH("Authentication failed for %I on %s - "
+ "lower packet counter (rcv %u, old %u)",
+ msg->sender, ifa->ifname, msg->pc, n->auth_pc);
+ return 0;
+ }
+
+ n->auth_pc = msg->pc;
+ n->auth_passed = 1;
+
+ return 1;
+}
+
/*
* Babel interfaces
@@ -1550,6 +1688,8 @@ babel_iface_update_buffers(struct babel_iface *ifa)
sk_set_tbsize(ifa->sk, tbsize);
ifa->tx_length = tbsize - BABEL_OVERHEAD;
+
+ babel_auth_set_tx_overhead(ifa);
}
static struct babel_iface*
@@ -1609,6 +1749,9 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con
init_list(&ifa->neigh_list);
ifa->hello_seqno = 1;
+ if (ic->auth_type != BABEL_AUTH_NONE)
+ babel_auth_reset_index(ifa);
+
ifa->timer = tm_new_init(ifa->pool, babel_iface_timer, ifa, 0, 0);
init_list(&ifa->msg_queue);
@@ -1639,6 +1782,20 @@ babel_remove_iface(struct babel_proto *p, struct babel_iface *ifa)
rfree(ifa->pool); /* contains ifa itself, locks, socket, etc */
}
+static int
+iface_is_valid(struct babel_proto *p, struct iface *iface)
+{
+ if (!(iface->flags & IF_MULTICAST))
+ {
+ log(L_ERR "%s: Interface %s does not support multicast",
+ p->p.name, iface->name);
+
+ return 0;
+ }
+
+ return 1;
+}
+
static void
babel_if_notify(struct proto *P, unsigned flags, struct iface *iface)
{
@@ -1658,16 +1815,13 @@ babel_if_notify(struct proto *P, unsigned flags, struct iface *iface)
if (!(iface->flags & IF_UP))
return;
- /* We only speak multicast */
- if (!(iface->flags & IF_MULTICAST))
- return;
-
/* Ignore ifaces without link-local address */
if (!iface->llv6)
return;
struct babel_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL);
- if (ic)
+
+ if (ic && iface_is_valid(p, iface))
babel_add_iface(p, iface, ic);
return;
@@ -1705,6 +1859,11 @@ babel_reconfigure_iface(struct babel_proto *p, struct babel_iface *ifa, struct b
ifa->next_hop_ip4 = ipa_nonzero(new->next_hop_ip4) ? new->next_hop_ip4 : addr4;
ifa->next_hop_ip6 = ipa_nonzero(new->next_hop_ip6) ? new->next_hop_ip6 : ifa->addr;
+ babel_iface_update_buffers(ifa);
+
+ if ((new->auth_type != BABEL_AUTH_NONE) && (new->auth_type != old->auth_type))
+ babel_auth_reset_index(ifa);
+
if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
log(L_WARN "%s: Missing IPv4 next hop address for %s", p->p.name, ifa->ifname);
@@ -1714,9 +1873,6 @@ babel_reconfigure_iface(struct babel_proto *p, struct babel_iface *ifa, struct b
if (ifa->next_regular > (current_time() + new->update_interval))
ifa->next_regular = current_time() + (random() % new->update_interval);
- if ((new->tx_length != old->tx_length) || (new->rx_buffer != old->rx_buffer))
- babel_iface_update_buffers(ifa);
-
if (new->check_link != old->check_link)
babel_iface_update_state(ifa);
@@ -1736,10 +1892,6 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
if (!(iface->flags & IF_UP))
continue;
- /* Ignore non-multicast ifaces */
- if (!(iface->flags & IF_MULTICAST))
- continue;
-
/* Ignore ifaces without link-local address */
if (!iface->llv6)
continue;
@@ -1747,6 +1899,9 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
struct babel_iface *ifa = babel_find_iface(p, iface);
struct babel_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL);
+ if (ic && iface_is_valid(p, iface))
+ ic = NULL;
+
if (ifa && ic)
{
if (babel_reconfigure_iface(p, ifa, ic))
@@ -1894,8 +2049,8 @@ babel_show_interfaces(struct proto *P, const char *iff)
}
cli_msg(-1023, "%s:", p->p.name);
- cli_msg(-1023, "%-10s %-6s %7s %6s %7s %-15s %s",
- "Interface", "State", "RX cost", "Nbrs", "Timer",
+ cli_msg(-1023, "%-10s %-6s %-5s %7s %6s %7s %-15s %s",
+ "Interface", "State", "Auth", "RX cost", "Nbrs", "Timer",
"Next hop (v4)", "Next hop (v6)");
WALK_LIST(ifa, p->interfaces)
@@ -1908,8 +2063,10 @@ babel_show_interfaces(struct proto *P, const char *iff)
nbrs++;
btime timer = MIN(ifa->next_regular, ifa->next_hello) - current_time();
- cli_msg(-1023, "%-10s %-6s %7u %6u %7t %-15I %I",
+ cli_msg(-1023, "%-10s %-6s %-5s %7u %6u %7t %-15I %I",
ifa->iface->name, (ifa->up ? "Up" : "Down"),
+ (ifa->cf->auth_type == BABEL_AUTH_MAC ?
+ (ifa->cf->auth_permissive ? "Perm" : "Yes") : "No"),
ifa->cf->rxcost, nbrs, MAX(timer, 0),
ifa->next_hop_ip4, ifa->next_hop_ip6);
}
@@ -1930,8 +2087,8 @@ babel_show_neighbors(struct proto *P, const char *iff)
}
cli_msg(-1024, "%s:", p->p.name);
- cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s",
- "IP address", "Interface", "Metric", "Routes", "Hellos", "Expires");
+ cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s %4s",
+ "IP address", "Interface", "Metric", "Routes", "Hellos", "Expires", "Auth");
WALK_LIST(ifa, p->interfaces)
{
@@ -1945,9 +2102,10 @@ babel_show_neighbors(struct proto *P, const char *iff)
rts++;
uint hellos = u32_popcount(n->hello_map);
- btime timer = n->hello_expiry - current_time();
- cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t",
- n->addr, ifa->iface->name, n->cost, rts, hellos, MAX(timer, 0));
+ btime timer = (n->hello_expiry ?: n->init_expiry) - current_time();
+ cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t %-4s",
+ n->addr, ifa->iface->name, n->cost, rts, hellos, MAX(timer, 0),
+ n->auth_passed ? "Yes" : "No");
}
}
}
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index e075024c..84feb085 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -19,6 +19,7 @@
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/locks.h"
+#include "nest/password.h"
#include "lib/resource.h"
#include "lib/lists.h"
#include "lib/socket.h"
@@ -51,6 +52,7 @@
#define BABEL_RXCOST_WIRELESS 256
#define BABEL_INITIAL_HOP_COUNT 255
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
+#define BABEL_INITIAL_NEIGHBOR_TIMEOUT (60 S_)
/* Max interval that will not overflow when carried as 16-bit centiseconds */
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
@@ -60,6 +62,14 @@
#define BABEL_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH)
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
+#define BABEL_AUTH_NONE 0
+#define BABEL_AUTH_MAC 1
+
+#define BABEL_AUTH_NONCE_LEN 10 /* we send 80 bit nonces */
+#define BABEL_AUTH_MAX_NONCE_LEN 192 /* max allowed by spec */
+#define BABEL_AUTH_INDEX_LEN 32 /* max size in spec */
+#define BABEL_AUTH_CHALLENGE_TIMEOUT (30 S_)
+#define BABEL_AUTH_CHALLENGE_INTERVAL (300 MS_) /* used for both challenges and replies */
enum babel_tlv_type {
BABEL_TLV_PAD1 = 0,
@@ -73,13 +83,10 @@ enum babel_tlv_type {
BABEL_TLV_UPDATE = 8,
BABEL_TLV_ROUTE_REQUEST = 9,
BABEL_TLV_SEQNO_REQUEST = 10,
- /* extensions - not implemented
- BABEL_TLV_TS_PC = 11,
- BABEL_TLV_HMAC = 12,
- BABEL_TLV_SS_UPDATE = 13,
- BABEL_TLV_SS_REQUEST = 14,
- BABEL_TLV_SS_SEQNO_REQUEST = 15,
- */
+ BABEL_TLV_MAC = 16,
+ BABEL_TLV_PC = 17,
+ BABEL_TLV_CHALLENGE_REQUEST = 18,
+ BABEL_TLV_CHALLENGE_REPLY = 19,
BABEL_TLV_MAX
};
@@ -137,6 +144,12 @@ struct babel_iface_config {
ip_addr next_hop_ip4;
ip_addr next_hop_ip6;
+
+ u8 auth_type; /* Authentication type (BABEL_AUTH_*) */
+ u8 auth_permissive; /* Don't drop packets failing auth check */
+ uint mac_num_keys; /* Number of configured HMAC keys */
+ uint mac_total_len; /* Total digest length for all configured keys */
+ list *passwords; /* Passwords for authentication */
};
struct babel_proto {
@@ -184,6 +197,10 @@ struct babel_iface {
u16 hello_seqno; /* To be increased on each hello */
+ u32 auth_pc;
+ int auth_tx_overhead;
+ u8 auth_index[BABEL_AUTH_INDEX_LEN];
+
btime next_hello;
btime next_regular;
btime next_triggered;
@@ -198,7 +215,6 @@ struct babel_neighbor {
struct babel_iface *ifa;
ip_addr addr;
- uint uc; /* Reference counter for seqno requests */
u16 rxcost; /* Sent in last IHU */
u16 txcost; /* Received in last IHU */
u16 cost; /* Computed neighbor cost */
@@ -207,11 +223,23 @@ struct babel_neighbor {
u16 hello_map;
u16 next_hello_seqno;
uint last_hello_int;
+
+ u32 auth_pc;
+ u8 auth_passed;
+ u8 auth_index_len;
+ u8 auth_index[BABEL_AUTH_INDEX_LEN];
+ u8 auth_nonce[BABEL_AUTH_NONCE_LEN];
+ btime auth_nonce_expiry;
+ btime auth_next_challenge;
+ btime auth_next_challenge_reply;
+
/* expiry timers */
btime hello_expiry;
btime ihu_expiry;
+ btime init_expiry;
list routes; /* Routes this neighbour has sent us (struct babel_route) */
+ list requests; /* Seqno requests bound to this neighbor */
};
struct babel_source {
@@ -241,6 +269,7 @@ struct babel_route {
struct babel_seqno_request {
node n;
+ node nbr_node;
u64 router_id;
u16 seqno;
u8 hop_count;
@@ -339,6 +368,12 @@ struct babel_msg_seqno_request {
ip_addr sender;
};
+struct babel_msg_challenge {
+ u8 type;
+ u8 nonce_len;
+ u8 *nonce;
+};
+
union babel_msg {
u8 type;
struct babel_msg_ack_req ack_req;
@@ -348,6 +383,7 @@ union babel_msg {
struct babel_msg_update update;
struct babel_msg_route_request route_request;
struct babel_msg_seqno_request seqno_request;
+ struct babel_msg_challenge challenge;
};
struct babel_msg_node {
@@ -355,6 +391,20 @@ struct babel_msg_node {
union babel_msg msg;
};
+/* only used for auth checking, so not a part of union above */
+struct babel_msg_auth {
+ ip_addr sender;
+ u32 pc;
+ u8 pc_seen;
+ u8 index_len;
+ u8 *index;
+ u8 challenge_reply_seen;
+ u8 challenge_reply[BABEL_AUTH_NONCE_LEN];
+ u8 challenge_seen;
+ u8 challenge_len;
+ u8 challenge[BABEL_AUTH_MAX_NONCE_LEN];
+};
+
static inline int babel_sadr_enabled(struct babel_proto *p)
{ return p->ip6_rtable.addr_type == NET_IP6_SADR; }
@@ -373,11 +423,15 @@ void babel_show_neighbors(struct proto *P, const char *iff);
void babel_show_entries(struct proto *P);
void babel_show_routes(struct proto *P);
+void babel_auth_reset_index(struct babel_iface *ifa);
+int babel_auth_check_pc(struct babel_iface *ifa, struct babel_msg_auth *msg);
+
/* packets.c */
void babel_enqueue(union babel_msg *msg, struct babel_iface *ifa);
void babel_send_unicast(union babel_msg *msg, struct babel_iface *ifa, ip_addr dest);
int babel_open_socket(struct babel_iface *ifa);
void babel_send_queue(void *arg);
+void babel_auth_set_tx_overhead(struct babel_iface *ifa);
#endif
diff --git a/proto/babel/config.Y b/proto/babel/config.Y
index 2f3b637b..05210fa4 100644
--- a/proto/babel/config.Y
+++ b/proto/babel/config.Y
@@ -25,7 +25,7 @@ CF_DECLS
CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT,
TYPE, WIRED, WIRELESS, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK, LINK,
NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS,
- ENTRIES, RANDOMIZE, ROUTER, ID)
+ ENTRIES, RANDOMIZE, ROUTER, ID, AUTHENTICATION, NONE, MAC, PERMISSIVE)
CF_GRAMMAR
@@ -59,6 +59,8 @@ babel_iface_start:
this_ipatt = cfg_allocz(sizeof(struct babel_iface_config));
add_tail(&BABEL_CFG->iface_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
+ reset_passwords();
+
BABEL_IFACE->port = BABEL_PORT;
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
@@ -91,6 +93,38 @@ babel_iface_finish:
BABEL_IFACE->ihu_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_IHU_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
BABEL_CFG->hold_time = MAX_(BABEL_CFG->hold_time, BABEL_IFACE->update_interval*BABEL_HOLD_TIME_FACTOR);
+
+ BABEL_IFACE->passwords = get_passwords();
+
+ if (!BABEL_IFACE->auth_type != !BABEL_IFACE->passwords)
+ cf_error("Authentication and password options should be used together");
+
+ if (BABEL_IFACE->passwords)
+ {
+ struct password_item *pass;
+ uint len = 0, i = 0;
+
+ WALK_LIST(pass, *BABEL_IFACE->passwords)
+ {
+ /* Set default crypto algorithm (HMAC-SHA256) */
+ if (!pass->alg)
+ pass->alg = ALG_HMAC_SHA256;
+
+ if (!((pass->alg & ALG_HMAC) ||
+ (pass->alg == ALG_BLAKE2S_128) ||
+ (pass->alg == ALG_BLAKE2S_256) ||
+ (pass->alg == ALG_BLAKE2B_256) ||
+ (pass->alg == ALG_BLAKE2B_512)))
+ cf_error("Only HMAC and Blake2 algorithms are supported");
+
+ len += mac_type_length(pass->alg);
+ i++;
+ }
+
+ BABEL_IFACE->mac_num_keys = i;
+ BABEL_IFACE->mac_total_len = len;
+ }
+
};
@@ -109,6 +143,10 @@ babel_iface_item:
| CHECK LINK bool { BABEL_IFACE->check_link = $3; }
| NEXT HOP IPV4 ipa { BABEL_IFACE->next_hop_ip4 = $4; if (!ipa_is_ip4($4)) cf_error("Must be an IPv4 address"); }
| NEXT HOP IPV6 ipa { BABEL_IFACE->next_hop_ip6 = $4; if (!ipa_is_ip6($4)) cf_error("Must be an IPv6 address"); }
+ | AUTHENTICATION NONE { BABEL_IFACE->auth_type = BABEL_AUTH_NONE; }
+ | AUTHENTICATION MAC { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 0; }
+ | AUTHENTICATION MAC PERMISSIVE { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 1; }
+ | password_list
;
babel_iface_opts:
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index 415ac3f9..f13410e2 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -11,6 +11,7 @@
*/
#include "babel.h"
+#include "lib/mac.h"
struct babel_pkt_header {
@@ -112,6 +113,31 @@ struct babel_subtlv_source_prefix {
u8 addr[0];
} PACKED;
+struct babel_tlv_mac {
+ u8 type;
+ u8 length;
+ u8 mac[0];
+} PACKED;
+
+struct babel_tlv_pc {
+ u8 type;
+ u8 length;
+ u32 pc;
+ u8 index[0];
+} PACKED;
+
+struct babel_tlv_challenge {
+ u8 type;
+ u8 length;
+ u8 nonce[0];
+} PACKED;
+
+struct babel_mac_pseudoheader {
+ u8 src_addr[16];
+ u16 src_port;
+ u8 dst_addr[16];
+ u16 dst_port;
+} PACKED;
/* Hello flags */
#define BABEL_HF_UNICAST 0x8000
@@ -120,8 +146,19 @@ struct babel_subtlv_source_prefix {
#define BABEL_UF_DEF_PREFIX 0x80
#define BABEL_UF_ROUTER_ID 0x40
+struct babel_parse_state;
+struct babel_write_state;
+
+struct babel_tlv_data {
+ u8 min_length;
+ int (*read_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_parse_state *state);
+ uint (*write_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_write_state *state, uint max_len);
+ void (*handle_tlv)(union babel_msg *m, struct babel_iface *ifa);
+};
struct babel_parse_state {
+ const struct babel_tlv_data* (*get_tlv_data)(u8 type);
+ const struct babel_tlv_data* (*get_subtlv_data)(u8 type);
struct babel_proto *proto;
struct babel_iface *ifa;
ip_addr saddr;
@@ -135,6 +172,9 @@ struct babel_parse_state {
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
u8 sadr_enabled;
+ u8 is_unicast;
+
+ struct babel_msg_auth auth;
};
enum parse_result {
@@ -157,6 +197,10 @@ struct babel_write_state {
#define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0)
#define LOG_PKT(msg, args...) \
log_rl(&p->log_pkt_tbf, L_REMOTE "%s: " msg, p->p.name, args)
+#define LOG_WARN(msg, args...) \
+ log_rl(&p->log_pkt_tbf, L_WARN "%s: " msg, p->p.name, args)
+#define LOG_PKT_AUTH(msg, args...) \
+ log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args)
#define FIRST_TLV(p) ((struct babel_tlv *) (((struct babel_pkt_header *) p) + 1))
#define NEXT_TLV(t) ((struct babel_tlv *) (((byte *) t) + TLV_LENGTH(t)))
@@ -167,6 +211,37 @@ struct babel_write_state {
#define NET_SIZE(n) BYTES(net_pxlen(n))
+
+/* Helper macros to loop over a series of TLVs.
+ * @start pointer to first TLV (void * or struct babel_tlv *)
+ * @end byte * pointer to TLV stream end
+ * @tlv struct babel_tlv pointer used as iterator
+ * @frame_err boolean (u8) that will be set to 1 if a frame error occurred
+ * @saddr source addr for use in log output
+ * @ifname ifname for use in log output
+ */
+#define WALK_TLVS(start, end, tlv, frame_err, saddr, ifname) \
+ for (tlv = start; \
+ (byte *)tlv < end; \
+ tlv = NEXT_TLV(tlv)) \
+ { \
+ byte *loop_pos; \
+ /* Ugly special case */ \
+ if (tlv->type == BABEL_TLV_PAD1) \
+ continue; \
+ \
+ /* The end of the common TLV header */ \
+ loop_pos = (byte *)tlv + sizeof(struct babel_tlv); \
+ if ((loop_pos > end) || (loop_pos + tlv->length > end)) \
+ { \
+ LOG_PKT("Bad TLV from %I via %s type %d pos %d - framing error", \
+ saddr, ifname, tlv->type, (int) ((byte *)tlv - (byte *)start)); \
+ frame_err = 1; \
+ break; \
+ }
+
+#define WALK_TLVS_END }
+
static inline uint
bytes_equal(u8 *b1, u8 *b2, uint maxlen)
{
@@ -234,6 +309,19 @@ put_ip6_ll(void *p, ip6_addr addr)
/*
+ * Authentication-related functions
+ */
+
+uint babel_auth_write_challenge(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
+int babel_auth_add_tlvs(struct babel_iface *ifa, struct babel_tlv *tlv, uint max_len);
+int babel_auth_sign(struct babel_iface *ifa, ip_addr dest);
+int babel_auth_check(struct babel_iface *ifa,
+ ip_addr saddr, u16 sport,
+ ip_addr daddr, u16 dport,
+ struct babel_pkt_header *pkt,
+ byte *start, uint len);
+
+/*
* TLV read/write functions
*/
@@ -255,13 +343,6 @@ static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *ms
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
-struct babel_tlv_data {
- u8 min_length;
- int (*read_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_parse_state *state);
- uint (*write_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_write_state *state, uint max_len);
- void (*handle_tlv)(union babel_msg *m, struct babel_iface *ifa);
-};
-
static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = {
[BABEL_TLV_ACK_REQ] = {
sizeof(struct babel_tlv_ack_req),
@@ -317,8 +398,44 @@ static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = {
babel_write_seqno_request,
babel_handle_seqno_request
},
+ [BABEL_TLV_CHALLENGE_REQUEST] = {
+ sizeof(struct babel_tlv_challenge),
+ NULL,
+ babel_auth_write_challenge,
+ NULL
+ },
+ [BABEL_TLV_CHALLENGE_REPLY] = {
+ sizeof(struct babel_tlv_challenge),
+ NULL,
+ babel_auth_write_challenge,
+ NULL
+ },
+};
+
+static const struct babel_tlv_data *get_packet_tlv_data(u8 type)
+{
+ return type < sizeof(tlv_data) / sizeof(*tlv_data) ? &tlv_data[type] : NULL;
+}
+
+static const struct babel_tlv_data source_prefix_tlv_data = {
+ sizeof(struct babel_subtlv_source_prefix),
+ babel_read_source_prefix,
+ NULL,
+ NULL
};
+static const struct babel_tlv_data *get_packet_subtlv_data(u8 type)
+{
+ switch (type)
+ {
+ case BABEL_SUBTLV_SOURCE_PREFIX:
+ return &source_prefix_tlv_data;
+
+ default:
+ return NULL;
+ }
+}
+
static int
babel_read_ack_req(struct babel_tlv *hdr, union babel_msg *m,
struct babel_parse_state *state)
@@ -1016,7 +1133,7 @@ babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg,
if (tlv->plen == 0)
return PARSE_ERROR;
- switch(msg->type)
+ switch (msg->type)
{
case BABEL_TLV_UPDATE:
/* Wildcard updates with source prefix MUST be silently ignored */
@@ -1083,69 +1200,65 @@ babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len)
return len;
}
-
static inline int
babel_read_subtlvs(struct babel_tlv *hdr,
union babel_msg *msg,
struct babel_parse_state *state)
{
+ const struct babel_tlv_data *tlv_data;
+ struct babel_proto *p = state->proto;
struct babel_tlv *tlv;
- byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr);
+ byte *end = (byte *) hdr + TLV_LENGTH(hdr);
+ u8 frame_err = 0;
int res;
- for (tlv = (void *) hdr + state->current_tlv_endpos;
- (byte *) tlv < end;
- tlv = NEXT_TLV(tlv))
+ WALK_TLVS((void *)hdr + state->current_tlv_endpos, end, tlv, frame_err,
+ state->saddr, state->ifa->ifname)
{
- /* Ugly special case */
- if (tlv->type == BABEL_TLV_PAD1)
+ if (tlv->type == BABEL_SUBTLV_PADN)
continue;
- /* The end of the common TLV header */
- pos = (byte *)tlv + sizeof(struct babel_tlv);
- if ((pos > end) || (pos + tlv->length > end))
- return PARSE_ERROR;
-
- /*
- * The subtlv type space is non-contiguous (due to the mandatory bit), so
- * use a switch for dispatch instead of the mapping array we use for TLVs
- */
- switch (tlv->type)
+ if (!state->get_subtlv_data ||
+ !(tlv_data = state->get_subtlv_data(tlv->type)) ||
+ !tlv_data->read_tlv)
{
- case BABEL_SUBTLV_SOURCE_PREFIX:
- res = babel_read_source_prefix(tlv, msg, state);
- if (res != PARSE_SUCCESS)
- return res;
- break;
-
- case BABEL_SUBTLV_PADN:
- default:
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
if (tlv->type >= 128)
- return PARSE_IGNORE;
- break;
+ return PARSE_IGNORE;
+ continue;
}
+
+ res = tlv_data->read_tlv(tlv, msg, state);
+ if (res != PARSE_SUCCESS)
+ return res;
}
+ WALK_TLVS_END;
- return PARSE_SUCCESS;
+ return frame_err ? PARSE_ERROR : PARSE_SUCCESS;
}
-static inline int
+static int
babel_read_tlv(struct babel_tlv *hdr,
union babel_msg *msg,
struct babel_parse_state *state)
{
+ const struct babel_tlv_data *tlv_data;
+
if ((hdr->type <= BABEL_TLV_PADN) ||
- (hdr->type >= BABEL_TLV_MAX) ||
- !tlv_data[hdr->type].read_tlv)
+ (hdr->type >= BABEL_TLV_MAX))
return PARSE_IGNORE;
- if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length)
+ tlv_data = state->get_tlv_data(hdr->type);
+
+ if (!tlv_data || !tlv_data->read_tlv)
+ return PARSE_IGNORE;
+
+ if (TLV_LENGTH(hdr) < tlv_data->min_length)
return PARSE_ERROR;
- state->current_tlv_endpos = tlv_data[hdr->type].min_length;
+ state->current_tlv_endpos = tlv_data->min_length;
- int res = tlv_data[hdr->type].read_tlv(hdr, msg, state);
+ int res = tlv_data->read_tlv(hdr, msg, state);
if (res != PARSE_SUCCESS)
return res;
@@ -1182,6 +1295,8 @@ babel_send_to(struct babel_iface *ifa, ip_addr dest)
struct babel_pkt_header *hdr = (void *) sk->tbuf;
int len = get_u16(&hdr->length) + sizeof(struct babel_pkt_header);
+ len += babel_auth_sign(ifa, dest);
+
DBG("Babel: Sending %d bytes to %I\n", len, dest);
return sk_send_to(sk, len, dest, 0);
}
@@ -1234,6 +1349,8 @@ babel_write_queue(struct babel_iface *ifa, list *queue)
sl_free(p->msg_slab, msg);
}
+ pos += babel_auth_add_tlvs(ifa, (struct babel_tlv *) pos, end - pos);
+
uint plen = pos - (byte *) pkt;
put_u16(&pkt->length, plen - sizeof(struct babel_pkt_header));
@@ -1312,10 +1429,13 @@ babel_enqueue(union babel_msg *msg, struct babel_iface *ifa)
/**
* babel_process_packet - process incoming data packet
+ * @ifa: Interface packet was received on
* @pkt: Pointer to the packet data
* @len: Length of received packet
* @saddr: Address of packet sender
- * @ifa: Interface packet was received on.
+ * @sport: Packet source port
+ * @daddr: Destination address of packet
+ * @dport: Packet destination port
*
* This function is the main processing hook of incoming Babel packets. It
* checks that the packet header is well-formed, then processes the TLVs
@@ -1327,9 +1447,12 @@ babel_enqueue(union babel_msg *msg, struct babel_iface *ifa)
* order.
*/
static void
-babel_process_packet(struct babel_pkt_header *pkt, int len,
- ip_addr saddr, struct babel_iface *ifa)
+babel_process_packet(struct babel_iface *ifa,
+ struct babel_pkt_header *pkt, int len,
+ ip_addr saddr, u16 sport,
+ ip_addr daddr, u16 dport)
{
+ u8 frame_err UNUSED = 0;
struct babel_proto *p = ifa->proto;
struct babel_tlv *tlv;
struct babel_msg_node *msg;
@@ -1337,15 +1460,16 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
int res;
int plen = sizeof(struct babel_pkt_header) + get_u16(&pkt->length);
- byte *pos;
byte *end = (byte *)pkt + plen;
struct babel_parse_state state = {
- .proto = p,
- .ifa = ifa,
- .saddr = saddr,
- .next_hop_ip6 = saddr,
- .sadr_enabled = babel_sadr_enabled(p),
+ .get_tlv_data = &get_packet_tlv_data,
+ .get_subtlv_data = &get_packet_subtlv_data,
+ .proto = p,
+ .ifa = ifa,
+ .saddr = saddr,
+ .next_hop_ip6 = saddr,
+ .sadr_enabled = babel_sadr_enabled(p),
};
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
@@ -1365,27 +1489,15 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
TRACE(D_PACKETS, "Packet received from %I via %s",
saddr, ifa->iface->name);
+ if (!babel_auth_check(ifa, saddr, sport, daddr, dport, pkt, end, len - plen))
+ return;
+
init_list(&msgs);
/* First pass through the packet TLV by TLV, parsing each into internal data
structures. */
- for (tlv = FIRST_TLV(pkt);
- (byte *)tlv < end;
- tlv = NEXT_TLV(tlv))
+ WALK_TLVS(FIRST_TLV(pkt), end, tlv, frame_err, saddr, ifa->iface->name)
{
- /* Ugly special case */
- if (tlv->type == BABEL_TLV_PAD1)
- continue;
-
- /* The end of the common TLV header */
- pos = (byte *)tlv + sizeof(struct babel_tlv);
- if ((pos > end) || (pos + tlv->length > end))
- {
- LOG_PKT("Bad TLV from %I via %s type %d pos %d - framing error",
- saddr, ifa->iface->name, tlv->type, (byte *)tlv - (byte *)pkt);
- break;
- }
-
msg = sl_allocz(p->msg_slab);
res = babel_read_tlv(tlv, &msg->msg, &state);
if (res == PARSE_SUCCESS)
@@ -1400,13 +1512,14 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
else /* PARSE_ERROR */
{
LOG_PKT("Bad TLV from %I via %s type %d pos %d - parse error",
- saddr, ifa->iface->name, tlv->type, (byte *)tlv - (byte *)pkt);
+ saddr, ifa->iface->name, tlv->type, (int) ((byte *)tlv - (byte *)pkt));
sl_free(p->msg_slab, msg);
break;
}
}
+ WALK_TLVS_END;
- /* Parsing done, handle all parsed TLVs */
+ /* Parsing done, handle all parsed TLVs, regardless of any errors */
WALK_LIST_FIRST(msg, msgs)
{
if (tlv_data[msg->msg.type].handle_tlv)
@@ -1469,7 +1582,10 @@ babel_rx_hook(sock *sk, uint len)
if (sk->flags & SKF_TRUNCATED)
DROP("truncated", len);
- babel_process_packet((struct babel_pkt_header *) sk->rbuf, len, sk->faddr, ifa);
+ babel_process_packet(ifa,
+ (struct babel_pkt_header *) sk->rbuf, len,
+ sk->faddr, sk->fport,
+ sk->laddr, sk->dport);
return 1;
drop:
@@ -1519,3 +1635,405 @@ err:
rfree(sk);
return 0;
}
+
+
+/* Authentication checks */
+static int
+babel_read_pc(struct babel_tlv *hdr, union babel_msg *m UNUSED,
+ struct babel_parse_state *state)
+{
+ struct babel_tlv_pc *tlv = (void *) hdr;
+
+ /* RFC 8967 4.3 (3) - If multiple PCs are found, only the first one is used */
+ if (state->auth.pc_seen)
+ return PARSE_IGNORE;
+
+ uint index_len = TLV_OPT_LENGTH(tlv);
+ if (index_len > BABEL_AUTH_INDEX_LEN)
+ return PARSE_IGNORE;
+
+ state->auth.pc = get_u32(&tlv->pc);
+ state->auth.pc_seen = 1;
+ state->auth.index_len = index_len;
+ state->auth.index = tlv->index;
+ state->current_tlv_endpos += index_len;
+
+ return PARSE_SUCCESS;
+}
+
+static const struct babel_tlv_data pc_tlv_data = {
+ .min_length = sizeof(struct babel_tlv_pc),
+ .read_tlv = &babel_read_pc
+};
+
+static int
+babel_read_challenge_req(struct babel_tlv *hdr, union babel_msg *m UNUSED,
+ struct babel_parse_state *state)
+{
+ struct babel_tlv_challenge *tlv = (void *) hdr;
+
+ if (!state->is_unicast)
+ return PARSE_IGNORE;
+
+ uint nonce_len = TLV_OPT_LENGTH(tlv);
+ if (nonce_len > BABEL_AUTH_MAX_NONCE_LEN)
+ return PARSE_IGNORE;
+
+ state->auth.challenge_len = nonce_len;
+ bmemcpy(state->auth.challenge, tlv->nonce, nonce_len);
+ state->auth.challenge_seen = 1;
+ state->current_tlv_endpos += nonce_len;
+
+ return PARSE_SUCCESS;
+}
+
+static const struct babel_tlv_data challenge_req_tlv_data = {
+ .min_length = sizeof(struct babel_tlv_challenge),
+ .read_tlv = &babel_read_challenge_req,
+};
+
+static int
+babel_read_challenge_reply(struct babel_tlv *hdr, union babel_msg *m UNUSED,
+ struct babel_parse_state *state)
+{
+ struct babel_tlv_challenge *tlv = (void *) hdr;
+
+ if (state->auth.challenge_reply_seen)
+ return PARSE_IGNORE;
+
+ uint nonce_len = TLV_OPT_LENGTH(tlv);
+ if (nonce_len != BABEL_AUTH_NONCE_LEN)
+ return PARSE_IGNORE;
+
+ memcpy(state->auth.challenge_reply, tlv->nonce, BABEL_AUTH_NONCE_LEN);
+ state->auth.challenge_reply_seen = 1;
+ state->current_tlv_endpos += nonce_len;
+
+ return PARSE_SUCCESS;
+}
+
+static const struct babel_tlv_data challenge_reply_tlv_data = {
+ .min_length = sizeof(struct babel_tlv_challenge),
+ .read_tlv = &babel_read_challenge_reply,
+};
+
+static const struct babel_tlv_data *
+get_auth_tlv_data(u8 type)
+{
+ switch (type)
+ {
+ case BABEL_TLV_PC:
+ return &pc_tlv_data;
+ case BABEL_TLV_CHALLENGE_REQUEST:
+ return &challenge_req_tlv_data;
+ case BABEL_TLV_CHALLENGE_REPLY:
+ return &challenge_reply_tlv_data;
+ default:
+ return NULL;
+ }
+}
+
+uint
+babel_auth_write_challenge(struct babel_tlv *hdr, union babel_msg *m,
+ struct babel_write_state *state UNUSED, uint max_len)
+{
+ struct babel_tlv_challenge *tlv = (void *) hdr;
+ struct babel_msg_challenge *msg = &m->challenge;
+
+ uint len = sizeof(struct babel_tlv_challenge) + msg->nonce_len;
+
+ if (len > max_len)
+ return 0;
+
+ TLV_HDR(tlv, msg->type, len);
+ bmemcpy(tlv->nonce, msg->nonce, msg->nonce_len);
+
+ return len;
+}
+
+static void
+babel_mac_fill(struct password_item *pass,
+ struct babel_mac_pseudoheader *phdr,
+ byte *pkt, uint pkt_len,
+ byte *mac)
+{
+ struct mac_context ctx;
+
+ mac_init(&ctx, pass->alg, pass->password, pass->length);
+ mac_update(&ctx, (byte *)phdr, sizeof(*phdr));
+ mac_update(&ctx, (byte *)pkt, pkt_len);
+ memcpy(mac, mac_final(&ctx), mac_get_length(&ctx));
+ mac_cleanup(&ctx);
+}
+
+static void
+babel_mac_build_phdr(struct babel_mac_pseudoheader *phdr,
+ ip_addr saddr, u16 sport,
+ ip_addr daddr, u16 dport)
+{
+ memset(phdr, 0, sizeof(*phdr));
+ put_ip6(phdr->src_addr, saddr);
+ put_u16(&phdr->src_port, sport);
+ put_ip6(phdr->dst_addr, daddr);
+ put_u16(&phdr->dst_port, dport);
+ DBG("MAC pseudo-header: %I %d %I %d\n", saddr, sport, daddr, dport);
+}
+
+static int
+babel_auth_check_mac(struct babel_iface *ifa, byte *pkt,
+ byte *trailer, uint trailer_len,
+ ip_addr saddr, u16 sport,
+ ip_addr daddr, u16 dport)
+{
+ struct babel_proto *p = ifa->proto;
+ uint pkt_len = (uint)(trailer - pkt);
+ byte *end = trailer + trailer_len;
+ btime now_ = current_real_time();
+
+ if (trailer_len < sizeof(struct babel_tlv))
+ {
+ LOG_PKT_AUTH("Authentication failed for %I on %s - no MAC signature",
+ saddr, ifa->ifname);
+ return 0;
+ }
+
+ struct babel_mac_pseudoheader phdr;
+ babel_mac_build_phdr(&phdr, saddr, sport, daddr, dport);
+
+ struct password_item *pass;
+ WALK_LIST(pass, *ifa->cf->passwords)
+ {
+ byte mac[MAX_HASH_SIZE];
+ uint mac_len = mac_type_length(pass->alg);
+ uint frame_err = 0;
+
+ if (pass->accfrom > now_ || pass->accto < now_)
+ continue;
+
+ babel_mac_fill(pass, &phdr, pkt, pkt_len, mac);
+
+ struct babel_tlv *tlv0;
+ WALK_TLVS((void *)trailer, end, tlv0, frame_err, saddr, ifa->ifname)
+ {
+ struct babel_tlv_mac *tlv = (void *)tlv0;
+
+ if (tlv->type != BABEL_TLV_MAC)
+ continue;
+
+ if ((TLV_OPT_LENGTH(tlv) == mac_len) && !memcmp(tlv->mac, mac, mac_len))
+ return 1;
+
+ DBG("MAC mismatch key id %d pos %d len %d/%d\n",
+ pass->id, (int) ((byte *)tlv - (byte *)pkt), mac_len, tlv->length);
+ }
+ WALK_TLVS_END;
+
+ if (frame_err)
+ return 0;
+ }
+
+ LOG_PKT_AUTH("Authentication failed for %I on %s - no matching key",
+ saddr, ifa->ifname);
+ return 0;
+}
+
+/**
+ * babel_auth_check - Check authentication for a packet
+ * @ifa: Interface holding the transmission buffer
+ * @saddr: Source address the packet was received from
+ * @sport: Source port the packet was received from
+ * @daddr: Destination address the packet was sent to
+ * @dport: Destination port the packet was sent to
+ * @pkt: Pointer to start of the packet data
+ * @trailer: Pointer to the packet trailer
+ * @trailer_len: Length of the packet trailer
+ *
+ * This function performs any necessary authentication checks on a packet and
+ * returns 0 if the packet should be accepted (either because it has been
+ * successfully authenticated or because authentication is disabled or
+ * configured in permissive mode), or 1 if the packet should be dropped without
+ * further processing.
+ */
+int
+babel_auth_check(struct babel_iface *ifa,
+ ip_addr saddr, u16 sport,
+ ip_addr daddr, u16 dport,
+ struct babel_pkt_header *pkt,
+ byte *trailer, uint trailer_len)
+{
+ uint frame_err UNUSED = 0;
+ struct babel_proto *p = ifa->proto;
+ struct babel_tlv *tlv;
+
+ struct babel_parse_state state = {
+ .get_tlv_data = &get_auth_tlv_data,
+ .proto = p,
+ .ifa = ifa,
+ .saddr = saddr,
+ .is_unicast = !(ipa_classify(daddr) & IADDR_MULTICAST),
+ .auth = {
+ .sender = saddr,
+ },
+ };
+
+ if (ifa->cf->auth_type == BABEL_AUTH_NONE)
+ return 1;
+
+ TRACE(D_PACKETS, "Checking packet authentication signature");
+
+ if (!babel_auth_check_mac(ifa, (byte *)pkt,
+ trailer, trailer_len,
+ saddr, sport,
+ daddr, dport))
+ goto fail;
+
+ /* MAC verified; parse packet to check packet counter and challenge */
+ WALK_TLVS(FIRST_TLV(pkt), trailer, tlv, frame_err, saddr, ifa->ifname)
+ {
+ union babel_msg msg;
+ enum parse_result res;
+
+ res = babel_read_tlv(tlv, &msg, &state);
+ if (res == PARSE_ERROR)
+ {
+ LOG_PKT("Bad TLV from %I via %s type %d pos %d - parse error",
+ saddr, ifa->ifname, tlv->type, (int) ((byte *)tlv - (byte *)pkt));
+ goto fail;
+ }
+ }
+ WALK_TLVS_END;
+
+ if (!babel_auth_check_pc(ifa, &state.auth))
+ goto fail;
+
+ TRACE(D_PACKETS, "Packet from %I via %s authenticated successfully",
+ saddr, ifa->ifname);
+ return 1;
+
+fail:
+ TRACE(D_PACKETS, "Packet from %I via %s failed authentication%s",
+ saddr, ifa->ifname,
+ ifa->cf->auth_permissive ? " but accepted in permissive mode" : "");
+
+ return ifa->cf->auth_permissive;
+}
+
+/**
+ * babel_auth_add_tlvs - Add authentication-related TLVs to a packet
+ * @ifa: Interface holding the transmission buffer
+ * @tlv: Pointer to the place where any new TLVs should be added
+ * @max_len: Maximum length available for adding new TLVs
+ *
+ * This function adds any new TLVs required by the authentication mode to a
+ * packet before it is shipped out. For MAC authentication, this is the packet
+ * counter TLV that must be included in every packet.
+ */
+int
+babel_auth_add_tlvs(struct babel_iface *ifa, struct babel_tlv *hdr, uint max_len)
+{
+ struct babel_proto *p = ifa->proto;
+ struct babel_tlv_pc *tlv;
+ uint len;
+
+ if (ifa->cf->auth_type == BABEL_AUTH_NONE)
+ return 0;
+
+ tlv = (void *) hdr;
+ len = sizeof(struct babel_tlv_pc) + BABEL_AUTH_INDEX_LEN;
+ max_len += ifa->auth_tx_overhead;
+
+ if (len > max_len)
+ {
+ LOG_WARN("Insufficient space to add MAC seqno TLV on iface %s: %d < %d",
+ ifa->ifname, max_len, len);
+ return 0;
+ }
+
+ TLV_HDR(tlv, BABEL_TLV_PC, len);
+ put_u32(&tlv->pc, ifa->auth_pc++);
+ memcpy(tlv->index, ifa->auth_index, BABEL_AUTH_INDEX_LEN);
+
+ /* Reset index on overflow to 0 */
+ if (!ifa->auth_pc)
+ babel_auth_reset_index(ifa);
+
+ return len;
+}
+
+/**
+ * babel_auth_sign - Sign an outgoing packet before transmission
+ * @ifa: Interface holding the transmission buffer
+ * @dest: Destination address of the packet
+ *
+ * This function adds authentication signature(s) to the packet trailer for each
+ * of the configured authentication keys on the interface.
+ */
+int
+babel_auth_sign(struct babel_iface *ifa, ip_addr dest)
+{
+ struct babel_proto *p = ifa->proto;
+ sock *sk = ifa->sk;
+
+ if (ifa->cf->auth_type == BABEL_AUTH_NONE)
+ return 0;
+
+ struct babel_pkt_header *hdr = (void *) sk->tbuf;
+ int len = get_u16(&hdr->length) + sizeof(struct babel_pkt_header);
+
+ byte *pkt = (byte *) hdr;
+ byte *pos = pkt + len;
+ byte *end = pkt + ifa->tx_length + ifa->auth_tx_overhead;
+ btime now_ = current_real_time();
+
+ struct babel_mac_pseudoheader phdr;
+ babel_mac_build_phdr(&phdr, sk->saddr, sk->sport, dest, sk->dport);
+
+ struct password_item *pass;
+ WALK_LIST(pass, *ifa->cf->passwords)
+ {
+ struct babel_tlv_mac *tlv = (void *) pos;
+ uint tlv_len = sizeof(struct babel_tlv_mac) + mac_type_length(pass->alg);
+
+ if (pass->genfrom > now_ || pass->gento < now_)
+ continue;
+
+ if (pos + tlv_len > end)
+ {
+ LOG_WARN("Insufficient space for MAC signatures on iface %s dst %I (%d/%d)",
+ ifa->ifname, dest, tlv_len, (int) (end-pos));
+ break;
+ }
+
+ TLV_HDR(tlv, BABEL_TLV_MAC, tlv_len);
+ babel_mac_fill(pass, &phdr, pkt, len, tlv->mac);
+
+ pos += tlv_len;
+ }
+
+ DBG("Added MAC signatures (%d bytes) on ifa %s for dest %I\n",
+ tot_len, ifa->ifname, dest);
+
+ return pos - (pkt + len);
+}
+
+/**
+ * babel_auth_set_tx_overhead - Set interface TX overhead for authentication
+ * @ifa: Interface to configure
+ *
+ * This function sets the TX overhead for an interface based on its
+ * authentication configuration.
+ */
+void
+babel_auth_set_tx_overhead(struct babel_iface *ifa)
+{
+ if (ifa->cf->auth_type == BABEL_AUTH_NONE)
+ {
+ ifa->auth_tx_overhead = 0;
+ return;
+ }
+
+ ifa->auth_tx_overhead = (sizeof(struct babel_tlv_pc) + BABEL_AUTH_INDEX_LEN +
+ sizeof(struct babel_tlv_mac) * ifa->cf->mac_num_keys +
+ ifa->cf->mac_total_len);
+ ifa->tx_length -= ifa->auth_tx_overhead;
+}
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 6752cb7f..1f927cbd 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -45,9 +45,9 @@
*
* export - Hook that validates and normalizes attribute during export phase.
* Receives eattr, may modify it (e.g., sort community lists for canonical
- * representation), UNSET() it (e.g., skip empty lists), or WITHDRAW() it if
- * necessary. May assume that eattr has value valid w.r.t. its type, but may be
- * invalid w.r.t. BGP constraints. Optional.
+ * representation), UNSET() it (e.g., skip empty lists), or REJECT() the route
+ * if necessary. May assume that eattr has value valid w.r.t. its type, but may
+ * be invalid w.r.t. BGP constraints. Optional.
*
* encode - Hook that converts internal representation to external one during
* packet writing. Receives eattr and puts it in the buffer (including attribute
@@ -88,7 +88,7 @@ bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintp
attrs,
pool,
EA_CODE(PROTOCOL_BGP, code),
- flags,
+ flags & ~BAF_EXT_LEN,
bgp_attr_table[code].type,
val
);
@@ -108,6 +108,9 @@ bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintp
#define UNSET(a) \
({ a->type = EAF_TYPE_UNDEF; return; })
+#define REJECT(msg, args...) \
+ ({ log(L_ERR "%s: " msg, s->proto->p.name, ## args); s->err_reject = 1; return; })
+
#define NEW_BGP "Discarding %s attribute received from AS4-aware neighbor"
#define BAD_EBGP "Discarding %s attribute received from EBGP neighbor"
#define BAD_LENGTH "Malformed %s attribute - invalid length (%u)"
@@ -118,7 +121,7 @@ bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintp
static inline int
bgp_put_attr_hdr3(byte *buf, uint code, uint flags, uint len)
{
- *buf++ = flags;
+ *buf++ = flags & ~BAF_EXT_LEN;
*buf++ = code;
*buf++ = len;
return 3;
@@ -380,7 +383,7 @@ static void
bgp_export_origin(struct bgp_export_state *s, eattr *a)
{
if (a->u.data > 2)
- WITHDRAW(BAD_VALUE, "ORIGIN", a->u.data);
+ REJECT(BAD_VALUE, "ORIGIN", a->u.data);
}
static void
@@ -902,20 +905,20 @@ bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
/* Perhaps we should just ignore it? */
if (!s->mpls)
- WITHDRAW("Unexpected MPLS stack");
+ REJECT("Unexpected MPLS stack");
/* Empty MPLS stack is not allowed */
if (!lnum)
- WITHDRAW("Malformed MPLS stack - empty");
+ REJECT("Malformed MPLS stack - empty");
/* This is ugly, but we must ensure that labels fit into NLRI field */
if ((24*lnum + (net_is_vpn(n) ? 64 : 0) + net_pxlen(n)) > 255)
- WITHDRAW("Malformed MPLS stack - too many labels (%u)", lnum);
+ REJECT("Malformed MPLS stack - too many labels (%u)", lnum);
for (uint i = 0; i < lnum; i++)
{
if (labels[i] > 0xfffff)
- WITHDRAW("Malformed MPLS stack - invalid label (%u)", labels[i]);
+ REJECT("Malformed MPLS stack - invalid label (%u)", labels[i]);
/* TODO: Check for special-purpose label values? */
}
@@ -1196,7 +1199,7 @@ bgp_export_attrs(struct bgp_export_state *s, ea_list *attrs)
for (i = 0; i < count; i++)
bgp_export_attr(s, &new->attrs[i], new);
- if (s->err_withdraw)
+ if (s->err_reject)
return NULL;
return new;
@@ -1394,19 +1397,19 @@ bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
/* Reject routes with our ASN in AS_PATH attribute */
if (bgp_as_path_loopy(p, attrs, p->local_as))
- goto withdraw;
+ goto loop;
/* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */
if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as))
- goto withdraw;
+ goto loop;
/* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */
if (p->is_internal && bgp_originator_id_loopy(p, attrs))
- goto withdraw;
+ goto loop;
/* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */
if (p->rr_client && bgp_cluster_list_loopy(p, attrs))
- goto withdraw;
+ goto loop;
/* If there is no local preference, define one */
if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF))
@@ -1427,6 +1430,10 @@ withdraw:
s->err_withdraw = 1;
return NULL;
+
+loop:
+ /* Loops are handled as withdraws, but ignored silently. Do not set err_withdraw. */
+ return NULL;
}
void
@@ -1676,6 +1683,10 @@ bgp_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
if (src == NULL)
return 0;
+ /* Reject flowspec that failed validation */
+ if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net->n.addr))
+ return -1;
+
/* IBGP route reflection, RFC 4456 */
if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
{
@@ -1845,6 +1856,10 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
{
struct ea_list *attrs = bgp_update_attrs(p, c, new, new->attrs->eattrs, bgp_linpool2);
+ /* Error during attribute processing */
+ if (!attrs)
+ log(L_ERR "%s: Invalid route %N withdrawn", p->p.name, n->n.addr);
+
/* If attributes are invalid, we fail back to withdraw */
buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c);
path = new->attrs->src->global_id;
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 1adb930d..619a816b 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -101,6 +101,7 @@
* RFC 8203 - BGP Administrative Shutdown Communication
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
* RFC 8654 - Extended Message Support for BGP
+ * RFC 9117 - Revised Validation Procedure for BGP Flow Specifications
* draft-ietf-idr-ext-opt-param-07
* draft-uttaro-idr-bgp-persistence-04
* draft-walton-bgp-hostname-capability-02
@@ -157,6 +158,8 @@ bgp_open(struct bgp_proto *p)
ip_addr addr = p->cf->strict_bind ? p->cf->local_ip :
(p->ipv4 ? IPA_NONE4 : IPA_NONE6);
uint port = p->cf->local_port;
+ uint flags = p->cf->free_bind ? SKF_FREEBIND : 0;
+ uint flag_mask = SKF_FREEBIND;
/* FIXME: Add some global init? */
if (!bgp_linpool)
@@ -165,8 +168,11 @@ bgp_open(struct bgp_proto *p)
/* We assume that cf->iface is defined iff cf->local_ip is link-local */
WALK_LIST(bs, bgp_sockets)
- if (ipa_equal(bs->sk->saddr, addr) && (bs->sk->sport == port) &&
- (bs->sk->iface == ifa) && (bs->sk->vrf == p->p.vrf))
+ if (ipa_equal(bs->sk->saddr, addr) &&
+ (bs->sk->sport == port) &&
+ (bs->sk->iface == ifa) &&
+ (bs->sk->vrf == p->p.vrf) &&
+ ((bs->sk->flags & flag_mask) == flags))
{
bs->uc++;
p->sock = bs;
@@ -180,7 +186,7 @@ bgp_open(struct bgp_proto *p)
sk->sport = port;
sk->iface = ifa;
sk->vrf = p->p.vrf;
- sk->flags = 0;
+ sk->flags = flags;
sk->tos = IP_PREC_INTERNET_CONTROL;
sk->rbsize = BGP_RX_BUFFER_SIZE;
sk->tbsize = BGP_TX_BUFFER_SIZE;
@@ -337,6 +343,8 @@ err2:
err1:
p->p.disabled = 1;
bgp_store_error(p, NULL, BE_MISC, err_val);
+
+ p->neigh = NULL;
proto_notify_state(&p->p, PS_DOWN);
return;
@@ -473,6 +481,8 @@ bgp_down(struct bgp_proto *p)
bgp_close(p);
}
+ p->neigh = NULL;
+
BGP_TRACE(D_EVENTS, "Down");
proto_notify_state(&p->p, PS_DOWN);
}
@@ -1731,6 +1741,9 @@ bgp_channel_init(struct channel *C, struct channel_config *CF)
if (cf->igp_table_ip6)
c->igp_table_ip6 = cf->igp_table_ip6->table;
+
+ if (cf->base_table)
+ c->base_table = cf->base_table->table;
}
static int
@@ -1746,6 +1759,12 @@ bgp_channel_start(struct channel *C)
if (c->igp_table_ip6)
rt_lock_table(c->igp_table_ip6);
+ if (c->base_table)
+ {
+ rt_lock_table(c->base_table);
+ rt_flowspec_link(c->base_table, c->c.table);
+ }
+
c->pool = p->p.pool; // XXXX
bgp_init_bucket_table(c);
bgp_init_prefix_table(c);
@@ -1830,6 +1849,12 @@ bgp_channel_cleanup(struct channel *C)
if (c->igp_table_ip6)
rt_unlock_table(c->igp_table_ip6);
+ if (c->base_table)
+ {
+ rt_flowspec_unlink(c->base_table, c->c.table);
+ rt_unlock_table(c->base_table);
+ }
+
c->index = 0;
/* Cleanup rest of bgp_channel starting at pool field */
@@ -1877,6 +1902,25 @@ bgp_default_igp_table(struct bgp_config *cf, struct bgp_channel_config *cc, u32
cf_error("Undefined IGP table");
}
+static struct rtable_config *
+bgp_default_base_table(struct bgp_config *cf, struct bgp_channel_config *cc)
+{
+ /* Expected table type */
+ u32 type = (cc->afi == BGP_AF_FLOW4) ? NET_IP4 : NET_IP6;
+
+ /* First, try appropriate IP channel */
+ u32 afi2 = BGP_AF(BGP_AFI(cc->afi), BGP_SAFI_UNICAST);
+ struct bgp_channel_config *cc2 = bgp_find_channel_config(cf, afi2);
+ if (cc2 && (cc2->c.table->addr_type == type))
+ return cc2->c.table;
+
+ /* Last, try default table of given type */
+ struct rtable_config *tab = cf->c.global->def_tables[type];
+ if (tab)
+ return tab;
+
+ cf_error("Undefined base table");
+}
void
bgp_postconfig(struct proto_config *CF)
@@ -2021,6 +2065,14 @@ bgp_postconfig(struct proto_config *CF)
cf_error("Mismatched IGP table type");
}
+ /* Default value of base table */
+ if ((BGP_SAFI(cc->afi) == BGP_SAFI_FLOW) && cc->validate && !cc->base_table)
+ cc->base_table = bgp_default_base_table(cf, cc);
+
+ if (cc->base_table && !cc->base_table->trie_used)
+ cf_error("Flowspec validation requires base table (%s) with trie",
+ cc->base_table->name);
+
if (cf->multihop && (cc->gw_mode == GW_DIRECT))
cf_error("Multihop BGP cannot use direct gateway mode");
@@ -2089,7 +2141,7 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
return same;
}
-#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
+#define TABLE(cf, NAME) ((cf)->NAME ? (cf)->NAME->table : NULL )
static int
bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed, int *export_changed)
@@ -2100,6 +2152,7 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
struct bgp_channel_config *old = c->cf;
if ((new->secondary != old->secondary) ||
+ (new->validate != old->validate) ||
(new->gr_able != old->gr_able) ||
(new->llgr_able != old->llgr_able) ||
(new->llgr_time != old->llgr_time) ||
@@ -2107,8 +2160,9 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
(new->add_path != old->add_path) ||
(new->import_table != old->import_table) ||
(new->export_table != old->export_table) ||
- (IGP_TABLE(new, ip4) != IGP_TABLE(old, ip4)) ||
- (IGP_TABLE(new, ip6) != IGP_TABLE(old, ip6)))
+ (TABLE(new, igp_table_ip4) != TABLE(old, igp_table_ip4)) ||
+ (TABLE(new, igp_table_ip6) != TABLE(old, igp_table_ip6)) ||
+ (TABLE(new, base_table) != TABLE(old, base_table)))
return 0;
if (new->mandatory && !old->mandatory && (C->channel_state != CS_UP))
@@ -2522,6 +2576,9 @@ bgp_show_proto_info(struct proto *P)
if (c->igp_table_ip6)
cli_msg(-1006, " IGP IPv6 table: %s", c->igp_table_ip6->name);
+
+ if (c->base_table)
+ cli_msg(-1006, " Base table: %s", c->base_table->name);
}
}
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index cca4b448..4969c0b9 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -86,6 +86,7 @@ struct bgp_config {
int peer_type; /* Internal or external BGP (BGP_PT_*, optional) */
int multihop; /* Number of hops if multihop */
int strict_bind; /* Bind listening socket to local address */
+ int free_bind; /* Bind listening socket with SKF_FREEBIND */
int ttl_security; /* Enable TTL security [RFC 5082] */
int compare_path_lengths; /* Use path lengths when selecting best route */
int med_metric; /* Compare MULTI_EXIT_DISC even between routes from differen ASes */
@@ -146,6 +147,7 @@ struct bgp_channel_config {
u8 mandatory; /* Channel is mandatory in capability negotiation */
u8 gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */
u8 secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */
+ u8 validate; /* Validate Flowspec per RFC 8955 (6) */
u8 gr_able; /* Allow full graceful restart for the channel */
u8 llgr_able; /* Allow full long-lived GR for the channel */
uint llgr_time; /* Long-lived graceful restart stale time */
@@ -159,6 +161,7 @@ struct bgp_channel_config {
struct rtable_config *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */
struct rtable_config *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
+ struct rtable_config *base_table; /* Base table for Flowspec validation */
};
#define BGP_PT_INTERNAL 1
@@ -340,6 +343,7 @@ struct bgp_channel {
rtable *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */
rtable *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
+ rtable *base_table; /* Base table for Flowspec validation */
/* Rest are zeroed when down */
pool *pool;
@@ -396,7 +400,7 @@ struct bgp_export_state {
int mpls;
u32 attrs_seen[1];
- uint err_withdraw;
+ uint err_reject;
uint local_next_hop;
};
@@ -422,6 +426,7 @@ struct bgp_parse_state {
int as4_session;
int add_path;
int mpls;
+ int reach_nlri_step;
u32 attrs_seen[256/32];
@@ -449,6 +454,7 @@ struct bgp_parse_state {
jmp_buf err_jmpbuf;
struct hostentry *hostentry;
+ struct rtable *base_table;
adata *mpls_labels;
/* Cached state for bgp_rte_update() */
@@ -515,7 +521,7 @@ struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
static inline int
rte_resolvable(rte *rt)
{
- return rt->attrs->dest == RTD_UNICAST;
+ return rt->attrs->dest != RTD_UNREACHABLE;
}
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 2dfbdca9..241aa7c2 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -31,7 +31,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS,
DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST, ENFORCE,
- FIRST)
+ FIRST, FREE, VALIDATE, BASE)
%type <i> bgp_nh
%type <i32> bgp_afi
@@ -155,6 +155,7 @@ bgp_proto:
}
| bgp_proto DYNAMIC NAME DIGITS expr ';' { BGP_CFG->dynamic_name_digits = $5; if ($5>10) cf_error("Dynamic name digits must be at most 10"); }
| bgp_proto STRICT BIND bool ';' { BGP_CFG->strict_bind = $4; }
+ | bgp_proto FREE BIND bool ';' { BGP_CFG->free_bind = $4; }
| bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
| bgp_proto MED METRIC bool ';' { BGP_CFG->med_metric = $4; }
| bgp_proto IGP METRIC bool ';' { BGP_CFG->igp_metric = $4; }
@@ -255,6 +256,11 @@ bgp_channel_item:
| GATEWAY DIRECT { BGP_CC->gw_mode = GW_DIRECT; }
| GATEWAY RECURSIVE { BGP_CC->gw_mode = GW_RECURSIVE; }
| SECONDARY bool { BGP_CC->secondary = $2; }
+ | VALIDATE bool {
+ BGP_CC->validate = $2;
+ if (BGP_SAFI(BGP_CC->afi) != BGP_SAFI_FLOW)
+ cf_error("Validate option limited to flowspec channels");
+ }
| GRACEFUL RESTART bool { BGP_CC->gr_able = $3; }
| LONG LIVED GRACEFUL RESTART bool { BGP_CC->llgr_able = $5; }
| LONG LIVED STALE TIME expr { BGP_CC->llgr_time = $5; }
@@ -278,6 +284,16 @@ bgp_channel_item:
else
cf_error("Mismatched IGP table type");
}
+ | BASE TABLE rtable {
+ if (BGP_SAFI(BGP_CC->afi) != BGP_SAFI_FLOW)
+ cf_error("Base table option limited to flowspec channels");
+
+ if (((BGP_CC->afi == BGP_AF_FLOW4) && ($3->addr_type == NET_IP4)) ||
+ ((BGP_CC->afi == BGP_AF_FLOW6) && ($3->addr_type == NET_IP6)))
+ BGP_CC->base_table = $3;
+ else
+ cf_error("Mismatched base table type");
+ }
;
bgp_channel_opts:
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index b16ee242..f13625e2 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -932,11 +932,15 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
#define WITHDRAW(msg, args...) \
({ REPORT(msg, ## args); s->err_withdraw = 1; return; })
+#define REJECT(msg, args...) \
+ ({ log(L_ERR "%s: " msg, s->proto->p.name, ## args); s->err_reject = 1; return; })
+
#define BAD_AFI "Unexpected AF <%u/%u> in UPDATE"
#define BAD_NEXT_HOP "Invalid NEXT_HOP attribute"
#define NO_NEXT_HOP "Missing NEXT_HOP attribute"
#define NO_LABEL_STACK "Missing MPLS stack"
+#define MISMATCHED_AF " - mismatched address family (%I for %s)"
static void
bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
@@ -949,13 +953,18 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
neighbor *nbr = NULL;
/* GW_DIRECT -> single_hop -> p->neigh != NULL */
- if (ipa_nonzero(gw))
+ if (ipa_nonzero2(gw))
nbr = neigh_find(&p->p, gw, NULL, 0);
else if (ipa_nonzero(ll))
nbr = neigh_find(&p->p, ll, p->neigh->iface, 0);
+ else
+ WITHDRAW(BAD_NEXT_HOP " - zero address");
+
+ if (!nbr)
+ WITHDRAW(BAD_NEXT_HOP " - address %I not directly reachable", ipa_nonzero(gw) ? gw : ll);
- if (!nbr || (nbr->scope == SCOPE_HOST))
- WITHDRAW(BAD_NEXT_HOP);
+ if (nbr->scope == SCOPE_HOST)
+ WITHDRAW(BAD_NEXT_HOP " - address %I is local", nbr->addr);
a->dest = RTD_UNICAST;
a->nh.gw = nbr->addr;
@@ -964,8 +973,8 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
}
else /* GW_RECURSIVE */
{
- if (ipa_zero(gw))
- WITHDRAW(BAD_NEXT_HOP);
+ if (ipa_zero2(gw))
+ WITHDRAW(BAD_NEXT_HOP " - zero address");
rtable *tab = ipa_is_ip4(gw) ? c->igp_table_ip4 : c->igp_table_ip6;
s->hostentry = rt_get_hostentry(tab, gw, ll, c->c.table);
@@ -1009,6 +1018,23 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 *labels, uint lnum)
}
}
+static void
+bgp_apply_flow_validation(struct bgp_parse_state *s, const net_addr *n, rta *a)
+{
+ struct bgp_channel *c = s->channel;
+ int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
+ a->dest = valid ? RTD_NONE : RTD_UNREACHABLE;
+
+ /* Set rte.bgp.base_table later from this state variable */
+ s->base_table = c->base_table;
+
+ /* Invalidate cached rta if dest changes */
+ if (s->cached_rta && (s->cached_rta->dest != a->dest))
+ {
+ rta_free(s->cached_rta);
+ s->cached_rta = NULL;
+ }
+}
static int
bgp_match_src(struct bgp_export_state *s, int mode)
@@ -1051,7 +1077,8 @@ bgp_use_next_hop(struct bgp_export_state *s, eattr *a)
return 1;
/* Keep it when forwarded between single-hop BGPs on the same iface */
- struct iface *ifa = (s->src && s->src->neigh) ? s->src->neigh->iface : NULL;
+ struct iface *ifa = (s->src && s->src->neigh && (s->src->p.proto_state != PS_DOWN)) ?
+ s->src->neigh->iface : NULL;
return p->neigh && (p->neigh->iface == ifa);
}
@@ -1119,28 +1146,28 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to)
/* Check if next hop is valid */
a = bgp_find_attr(*to, BA_NEXT_HOP);
if (!a)
- WITHDRAW(NO_NEXT_HOP);
+ REJECT(NO_NEXT_HOP);
ip_addr *nh = (void *) a->u.ptr->data;
ip_addr peer = s->proto->remote_ip;
uint len = a->u.ptr->length;
/* Forbid zero next hop */
- if (ipa_zero(nh[0]) && ((len != 32) || ipa_zero(nh[1])))
- WITHDRAW(BAD_NEXT_HOP);
+ if (ipa_zero2(nh[0]) && ((len != 32) || ipa_zero(nh[1])))
+ REJECT(BAD_NEXT_HOP " - zero address");
/* Forbid next hop equal to neighbor IP */
if (ipa_equal(peer, nh[0]) || ((len == 32) && ipa_equal(peer, nh[1])))
- WITHDRAW(BAD_NEXT_HOP);
+ REJECT(BAD_NEXT_HOP " - neighbor address %I", peer);
/* Forbid next hop with non-matching AF */
if ((ipa_is_ip4(nh[0]) != bgp_channel_is_ipv4(s->channel)) &&
!s->channel->ext_next_hop)
- WITHDRAW(BAD_NEXT_HOP);
+ REJECT(BAD_NEXT_HOP MISMATCHED_AF, nh[0], s->channel->desc->name);
/* Just check if MPLS stack */
if (s->mpls && !bgp_find_attr(*to, BA_MPLS_LABEL_STACK))
- WITHDRAW(NO_LABEL_STACK);
+ REJECT(NO_LABEL_STACK);
}
static uint
@@ -1211,7 +1238,7 @@ bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a)
ad->length = 16;
if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
- WITHDRAW(BAD_NEXT_HOP);
+ WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name);
// XXXX validate next hop
@@ -1292,7 +1319,7 @@ bgp_decode_next_hop_vpn(struct bgp_parse_state *s, byte *data, uint len, rta *a)
bgp_parse_error(s, 9);
if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
- WITHDRAW(BAD_NEXT_HOP);
+ WITHDRAW(BAD_NEXT_HOP MISMATCHED_AF, nh[0], c->desc->name);
// XXXX validate next hop
@@ -1334,7 +1361,7 @@ bgp_update_next_hop_none(struct bgp_export_state *s, eattr *a, ea_list **to)
*/
static void
-bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
+bgp_rte_update(struct bgp_parse_state *s, const net_addr *n, u32 path_id, rta *a0)
{
if (path_id != s->last_id)
{
@@ -1347,6 +1374,10 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
if (!a0)
{
+ /* Route update was changed to withdraw */
+ if (s->err_withdraw && s->reach_nlri_step)
+ REPORT("Invalid route %N withdrawn", n);
+
/* Route withdraw */
rte_update3(&s->channel->c, n, NULL, s->last_src);
return;
@@ -1369,6 +1400,7 @@ bgp_rte_update(struct bgp_parse_state *s, net_addr *n, u32 path_id, rta *a0)
e->pflags = 0;
e->u.bgp.suppressed = 0;
e->u.bgp.stale = -1;
+ e->u.bgp.base_table = s->base_table;
rte_update3(&s->channel->c, n, e, s->last_src);
}
@@ -1408,7 +1440,7 @@ bgp_decode_mpls_labels(struct bgp_parse_state *s, byte **pos, uint *len, uint *p
/* RFC 8277 2.4 - withdraw does not have variable-size MPLS stack but
fixed-size 24-bit Compatibility field, which MUST be ignored */
- if (!a && !s->err_withdraw)
+ if (!s->reach_nlri_step)
return;
}
while (!(label & BGP_MPLS_BOS));
@@ -1883,6 +1915,10 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
net_fill_flow4(n, px, pxlen, pos, flen);
ADVANCE(pos, len, flen);
+ /* Apply validation procedure per RFC 8955 (6) */
+ if (a && s->channel->cf->validate)
+ bgp_apply_flow_validation(s, n, a);
+
bgp_rte_update(s, n, path_id, a);
}
}
@@ -1971,6 +2007,10 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
net_fill_flow6(n, px, pxlen, pos, flen);
ADVANCE(pos, len, flen);
+ /* Apply validation procedure per RFC 8955 (6) */
+ if (a && s->channel->cf->validate)
+ bgp_apply_flow_validation(s, n, a);
+
bgp_rte_update(s, n, path_id, a);
}
}
@@ -2424,6 +2464,8 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
s->last_id = 0;
s->last_src = s->proto->p.main_source;
+ s->base_table = NULL;
+
/*
* IPv4 BGP and MP-BGP may be used together in one update, therefore we do not
* add BA_NEXT_HOP in bgp_decode_attrs(), but we add it here independently for
@@ -2542,6 +2584,8 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
if (s.mp_unreach_len)
bgp_decode_nlri(&s, s.mp_unreach_af, s.mp_unreach_nlri, s.mp_unreach_len, NULL, NULL, 0);
+ s.reach_nlri_step = 1;
+
if (s.ip_reach_len)
bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_reach_nlri, s.ip_reach_len,
ea, s.ip_next_hop_data, s.ip_next_hop_len);
diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c
index 838360c2..8d97c860 100644
--- a/proto/mrt/mrt.c
+++ b/proto/mrt/mrt.c
@@ -224,12 +224,15 @@ mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern)
return !tab ? tab_ptr : NULL;
/* Walk routing_tables list, starting after tab (if non-NULL) */
- for (tab = !tab ? HEAD(routing_tables) : NODE_NEXT(tab);
- NODE_VALID(tab);
- tab = NODE_NEXT(tab))
+ for (node *tn = tab ? tab->n.next : HEAD(routing_tables);
+ NODE_VALID(tn);
+ tn = tn->next)
+ {
+ tab = SKIP_BACK(struct rtable, n, tn);
if (patmatch(pattern, tab->name) &&
((tab->addr_type == NET_IP4) || (tab->addr_type == NET_IP6)))
return tab;
+ }
return NULL;
}
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index fd2cfe8a..4b7d5a36 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -85,7 +85,7 @@ ospf_proto_finish(void)
struct ospf_iface_patt *ic;
/* Define default channel */
- if (EMPTY_LIST(this_proto->channels))
+ if (! proto_cf_main_channel(this_proto))
{
uint net_type = this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
channel_config_new(NULL, net_label[net_type], net_type, this_proto);
@@ -248,8 +248,7 @@ ospf_channel_start: net_type ospf_af_mc
$$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
/* Save the multicast flag */
- if (this_channel == proto_cf_main_channel(this_proto))
- OSPF_CFG->af_mc = $2;
+ OSPF_CFG->af_mc = $2;
};
ospf_channel: ospf_channel_start channel_opt_list channel_end;
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index 5a5f76f8..6d33bf8e 100644
--- a/proto/ospf/dbdes.c
+++ b/proto/ospf/dbdes.c
@@ -194,7 +194,7 @@ ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
"DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
sk_set_tbuf(ifa->sk, n->ldd_buffer);
- ospf_send_to(ifa, n->ip);
+ ospf_send_to_nbr(ifa, n);
sk_set_tbuf(ifa->sk, NULL);
}
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 666140b5..f38b8210 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -529,14 +529,14 @@ add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
}
static int
-ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
+ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr, int type)
{
/* vlink cannot be stub */
- if (ip->type == OSPF_IT_VLINK)
+ if (type == OSPF_IT_VLINK)
return 0;
- /* a host address */
- if (addr->flags & IA_HOST)
+ /* Host address on Broadcast/NBMA */
+ if (((type == OSPF_IT_BCAST) || (type == OSPF_IT_NBMA)) && (addr->flags & IA_HOST))
return 1;
/* a loopback iface */
@@ -584,7 +584,6 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->strictnbma = ip->strictnbma;
ifa->waitint = ip->waitint;
ifa->deadint = ip->deadint;
- ifa->stub = ospf_iface_stubby(ip, addr);
ifa->ioprob = OSPF_I_OK;
ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight;
@@ -598,18 +597,19 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->tx_length = ifa_tx_length(ifa);
ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
- ifa->ptp_netmask = !(addr->flags & IA_PEER);
+ ifa->ptp_netmask = !(addr->flags & (IA_HOST | IA_PEER));
if (ip->ptp_netmask < 2)
ifa->ptp_netmask = ip->ptp_netmask;
/* For compatibility, we may use ptp_address even for unnumbered links */
- ifa->ptp_address = !(addr->flags & IA_PEER) || (p->gr_mode != OSPF_GR_ABLE);
+ ifa->ptp_address = !(addr->flags & (IA_HOST | IA_PEER)) || (p->gr_mode != OSPF_GR_ABLE);
if (ip->ptp_address < 2)
ifa->ptp_address = ip->ptp_address;
ifa->drip = ifa->bdrip = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6;
ifa->type = ospf_iface_classify(ip->type, addr);
+ ifa->stub = ospf_iface_stubby(ip, addr, ifa->type);
/* Check validity of interface type */
int old_type = ifa->type;
@@ -647,7 +647,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
should be used). Because OSPFv3 iface is not subnet-specific,
there is no need for ipa_in_net() check */
- if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &addr->prefix))
+ if (ospf_is_v2(p) && !ospf_ipa_local(nb->ip, addr))
continue;
if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
@@ -767,7 +767,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
if (old_type != new_type)
return 0;
- int new_stub = ospf_iface_stubby(new, ifa->addr);
+ int new_stub = ospf_iface_stubby(new, ifa->addr, new_type);
if (ifa->stub != new_stub)
return 0;
@@ -929,7 +929,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
WALK_LIST(nb, new->nbma_list)
{
/* See related note in ospf_iface_new() */
- if (ospf_is_v2(p) && !ipa_in_netX(nb->ip, &ifa->addr->prefix))
+ if (ospf_is_v2(p) && !ospf_ipa_local(nb->ip, ifa->addr))
continue;
if (ospf_is_v3(p) && !ipa_is_link_local(nb->ip))
@@ -1011,7 +1011,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* PtP netmask */
int new_ptp_netmask = (new->ptp_netmask < 2) ? new->ptp_netmask :
- !(ifa->addr->flags & IA_PEER);
+ !(ifa->addr->flags & (IA_HOST | IA_PEER));
if (ifa->ptp_netmask != new_ptp_netmask)
{
OSPF_TRACE(D_EVENTS, "Changing PtP netmask option of %s from %d to %d",
@@ -1021,7 +1021,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
/* PtP address */
int new_ptp_address = (new->ptp_address < 2) ? new->ptp_address :
- (!(ifa->addr->flags & IA_PEER) || (p->gr_mode != OSPF_GR_ABLE));
+ (!(ifa->addr->flags & (IA_HOST | IA_PEER)) || (p->gr_mode != OSPF_GR_ABLE));
if (ifa->ptp_address != new_ptp_address)
{
/* Keep it silent for implicit changes */
diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c
index 5318e50c..4eec536d 100644
--- a/proto/ospf/lsack.c
+++ b/proto/ospf/lsack.c
@@ -110,21 +110,13 @@ ospf_send_lsack_(struct ospf_proto *p, struct ospf_neighbor *n, int queue)
if (queue == ACKL_DIRECT)
{
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent to nbr %R on %s", n->rid, ifa->ifname);
- ospf_send_to(ifa, n->ip);
- return;
+ ospf_send_to_nbr(ifa, n);
}
-
- OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname);
-
- if (ifa->type == OSPF_IT_BCAST)
+ else
{
- if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- ospf_send_to_all(ifa);
- else
- ospf_send_to_des(ifa);
+ OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname);
+ ospf_send_to_iface(ifa);
}
- else
- ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
}
void
diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c
index 45af7533..05c0e039 100644
--- a/proto/ospf/lsreq.c
+++ b/proto/ospf/lsreq.c
@@ -89,7 +89,7 @@ ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n)
pkt->length = htons(length);
OSPF_PACKET(ospf_dump_lsreq, pkt, "LSREQ packet sent to nbr %R on %s", n->rid, ifa->ifname);
- ospf_send_to(ifa, n->ip);
+ ospf_send_to_nbr(ifa, n);
}
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index fafe4872..54c4a069 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -398,15 +398,7 @@ ospf_flood_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint ls
OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa),
"LSUPD packet flooded via %s", ifa->ifname);
- if (ifa->type == OSPF_IT_BCAST)
- {
- if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- ospf_send_to_all(ifa);
- else
- ospf_send_to_des(ifa);
- }
- else
- ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
+ ospf_send_to_iface(ifa);
}
return i;
@@ -428,7 +420,7 @@ ospf_send_lsupd(struct ospf_proto *p, struct top_hash_entry **lsa_list, uint lsa
OSPF_PACKET(ospf_dump_lsupd, ospf_tx_buffer(ifa),
"LSUPD packet sent to nbr %R on %s", n->rid, ifa->ifname);
- ospf_send_to(ifa, n->ip);
+ ospf_send_to_nbr(ifa, n);
}
return i;
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index db55aa6a..3e704ae8 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -946,6 +946,14 @@ struct lsadb_show_data {
#define EA_OSPF_ROUTER_ID EA_CODE(PROTOCOL_OSPF, 3)
+/*
+ * For regular networks, neighbor address must match network prefix.
+ * For unnumbered networks, we consider every address local.
+ */
+static inline int ospf_ipa_local(ip_addr a, const struct ifa *addr)
+{ return ipa_in_netX(a, &addr->prefix) || (addr->flags & IA_HOST); }
+
+
/* ospf.c */
void ospf_schedule_rtcalc(struct ospf_proto *p);
@@ -1056,22 +1064,16 @@ int ospf_rx_hook(sock * sk, uint size);
void ospf_err_hook(sock * sk, int err);
void ospf_verr_hook(sock *sk, int err);
void ospf_send_to(struct ospf_iface *ifa, ip_addr ip);
-void ospf_send_to_agt(struct ospf_iface *ifa, u8 state);
-void ospf_send_to_bdr(struct ospf_iface *ifa);
+void ospf_send_to_iface(struct ospf_iface *ifa);
-static inline uint ospf_pkt_maxsize(struct ospf_iface *ifa)
-{ return ifa->tx_length - ifa->tx_hdrlen; }
+static inline void ospf_send_to_nbr(struct ospf_iface *ifa, struct ospf_neighbor *n)
+{ ospf_send_to(ifa, (ifa->type == OSPF_IT_PTP) ? ifa->all_routers : n->ip); }
static inline void ospf_send_to_all(struct ospf_iface *ifa)
{ ospf_send_to(ifa, ifa->all_routers); }
-static inline void ospf_send_to_des(struct ospf_iface *ifa)
-{
- if (ipa_nonzero(ifa->des_routers))
- ospf_send_to(ifa, ifa->des_routers);
- else
- ospf_send_to_bdr(ifa);
-}
+static inline uint ospf_pkt_maxsize(struct ospf_iface *ifa)
+{ return ifa->tx_length - ifa->tx_hdrlen; }
#ifndef PARSER
#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 85cbbdf0..d7e10f37 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -403,7 +403,7 @@ ospf_rx_hook(sock *sk, uint len)
return 1;
int src_local, dst_local, dst_mcast;
- src_local = ipa_in_netX(sk->faddr, &ifa->addr->prefix);
+ src_local = ospf_ipa_local(sk->faddr, ifa->addr);
dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
@@ -664,21 +664,54 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
}
-void
-ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
+static void
+ospf_send_to_designated(struct ospf_iface *ifa)
+{
+ /* In case of real-broadcast mode */
+ if (ipa_zero(ifa->des_routers))
+ {
+ if (ipa_nonzero2(ifa->drip))
+ ospf_send_to(ifa, ifa->drip);
+
+ if (ipa_nonzero2(ifa->bdrip))
+ ospf_send_to(ifa, ifa->bdrip);
+
+ return;
+ }
+
+ ospf_send_to(ifa, ifa->des_routers);
+}
+
+static void
+ospf_send_to_adjacent(struct ospf_iface *ifa)
{
struct ospf_neighbor *n;
WALK_LIST(n, ifa->neigh_list)
- if (n->state >= state)
+ if (n->state >= NEIGHBOR_EXCHANGE)
ospf_send_to(ifa, n->ip);
}
void
-ospf_send_to_bdr(struct ospf_iface *ifa)
+ospf_send_to_iface(struct ospf_iface *ifa)
{
- if (ipa_nonzero2(ifa->drip))
- ospf_send_to(ifa, ifa->drip);
- if (ipa_nonzero2(ifa->bdrip))
- ospf_send_to(ifa, ifa->bdrip);
+ /*
+ * Send packet to (relevant) neighbors on iface
+ *
+ * On broadcast networks, destination is either AllSPFRouters, or AllDRouters.
+ * On PtP networks, destination is always AllSPFRouters. On non-broadcast
+ * networks, packets are sent as unicast to every adjacent neighbor.
+ */
+
+ if (ifa->type == OSPF_IT_BCAST)
+ {
+ if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
+ ospf_send_to_all(ifa);
+ else
+ ospf_send_to_designated(ifa);
+ }
+ else if (ifa->type == OSPF_IT_PTP)
+ ospf_send_to_all(ifa);
+ else /* Non-broadcast */
+ ospf_send_to_adjacent(ifa);
}
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index b3e49a11..faee49dc 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -1251,7 +1251,7 @@ ospf_rt_abr1(struct ospf_proto *p)
FIB_WALK_END;
- if (ospf_is_v2(p))
+ if (ospf_is_ip4(p))
net_fill_ip4(&default_net, IP4_NONE, 0);
else
net_fill_ip6(&default_net, IP6_NONE, 0);
@@ -1827,7 +1827,12 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
return NULL;
}
- return new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight);
+ struct nexthop *nhs = new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight);
+
+ if (ifa->addr->flags & IA_HOST)
+ nhs->flags = RNF_ONLINK;
+
+ return nhs;
}
/* The third case - bcast or nbma neighbor */
@@ -2031,8 +2036,9 @@ again1:
for (nh = nf->n.nhs; nh; nh = nh->next)
if (ipa_nonzero(nh->gw))
{
- neighbor *ng = neigh_find(&p->p, nh->gw, nh->iface, 0);
- if (!ng || (ng->scope == SCOPE_HOST))
+ neighbor *nbr = neigh_find(&p->p, nh->gw, nh->iface,
+ (nh->flags & RNF_ONLINK) ? NEF_ONLINK : 0);
+ if (!nbr || (nbr->scope == SCOPE_HOST))
{ reset_ri(nf); break; }
}
}
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index 3532f114..f991d09a 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -81,7 +81,10 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o
#ifdef CONFIG_BGP
/* Hack to cleanup cached value */
if (e->attrs->src->proto->proto == &proto_bgp)
+ {
e->u.bgp.stale = -1;
+ e->u.bgp.base_table = NULL;
+ }
#endif
src = a->src;
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index dda9cfcd..8d4a3ab9 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -46,6 +46,7 @@ proto: radv_proto ;
radv_proto_start: proto_start RADV
{
this_proto = proto_config_new(&proto_radv, $1);
+ this_proto->net_type = NET_IP6;
init_list(&RADV_CFG->patt_list);
init_list(&RADV_CFG->pref_list);
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index b4235917..66e8eb4b 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -564,7 +564,7 @@ radv_postconfig(struct proto_config *CF)
// struct radv_config *cf = (void *) CF;
/* Define default channel */
- if (EMPTY_LIST(CF->channels))
+ if (! proto_cf_main_channel(CF))
channel_config_new(NULL, net_label[NET_IP6], NET_IP6, CF);
}
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 8b4719f7..e1a235a0 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -1105,7 +1105,7 @@ rip_postconfig(struct proto_config *CF)
// struct rip_config *cf = (void *) CF;
/* Define default channel */
- if (EMPTY_LIST(CF->channels))
+ if (! proto_cf_main_channel(CF))
channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
}
diff --git a/proto/rpki/packets.c b/proto/rpki/packets.c
index dd11f997..d246dd50 100644
--- a/proto/rpki/packets.c
+++ b/proto/rpki/packets.c
@@ -737,6 +737,33 @@ rpki_handle_prefix_pdu(struct rpki_cache *cache, const struct pdu_header *pdu)
net_addr_union addr = {};
rpki_prefix_pdu_2_net_addr(pdu, &addr);
+ if (type == IPV4_PREFIX)
+ {
+ if ((addr.roa4.pxlen > addr.roa4.max_pxlen) ||
+ (addr.roa4.max_pxlen > IP4_MAX_PREFIX_LENGTH))
+ {
+ RPKI_WARN(cache->p, "Received corrupt packet from RPKI cache server: invalid pxlen or max_pxlen");
+ byte tmp[pdu->len];
+ const struct pdu_header *hton_pdu = rpki_pdu_back_to_network_byte_order((void *) tmp, (const void *) pdu);
+ rpki_send_error_pdu(cache, CORRUPT_DATA, pdu->len, hton_pdu, "Corrupted PDU: invalid pxlen or max_pxlen");
+ rpki_cache_change_state(cache, RPKI_CS_ERROR_FATAL);
+ return RPKI_ERROR;
+ }
+ }
+ else
+ {
+ if ((addr.roa6.pxlen > addr.roa6.max_pxlen) ||
+ (addr.roa6.max_pxlen > IP6_MAX_PREFIX_LENGTH))
+ {
+ RPKI_WARN(cache->p, "Received corrupt packet from RPKI cache server: invalid pxlen or max_pxlen");
+ byte tmp[pdu->len];
+ const struct pdu_header *hton_pdu = rpki_pdu_back_to_network_byte_order((void *) tmp, (const void *) pdu);
+ rpki_send_error_pdu(cache, CORRUPT_DATA, pdu->len, hton_pdu, "Corrupted PDU: invalid pxlen or max_pxlen");
+ rpki_cache_change_state(cache, RPKI_CS_ERROR_FATAL);
+ return RPKI_ERROR;
+ }
+ }
+
if (cf->ignore_max_length)
{
if (type == IPV4_PREFIX)
diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c
index 799cb877..ab0837f3 100644
--- a/proto/rpki/rpki.c
+++ b/proto/rpki/rpki.c
@@ -923,7 +923,7 @@ rpki_postconfig(struct proto_config *CF)
{
/* Define default channel */
if (EMPTY_LIST(CF->channels))
- channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
+ cf_error("Channel not specified");
}
static void
diff --git a/proto/static/static.c b/proto/static/static.c
index 661f1aac..2789c1bb 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -434,7 +434,7 @@ static_postconfig(struct proto_config *CF)
struct static_config *cf = (void *) CF;
struct static_route *r;
- if (EMPTY_LIST(CF->channels))
+ if (! proto_cf_main_channel(CF))
cf_error("Channel not specified");
struct channel_config *cc = proto_cf_main_channel(CF);
diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in
index 1856967d..be67371c 100644
--- a/sysdep/autoconf.h.in
+++ b/sysdep/autoconf.h.in
@@ -54,6 +54,12 @@
/* Define to 1 if you have the <execinfo.h> header file. */
#undef HAVE_EXECINFO_H
+/* Define to 1 if you have the `getentropy' function. */
+#undef HAVE_GETENTROPY
+
+/* Define to 1 if you have the `getrandom' function. */
+#undef HAVE_GETRANDOM
+
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
@@ -66,6 +72,12 @@
/* Define to 1 if you have the `ssh' library (-lssh). */
#undef HAVE_LIBSSH
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if mmap() is available. */
+#undef HAVE_MMAP
+
/* Define to 1 if kernel is MPLS capable */
#undef HAVE_MPLS_KERNEL
@@ -84,15 +96,13 @@
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
-/* Always define to 1, for backward compatibility. You can assume <stdlib.h>
- exists. */
+/* 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
-/* Always define to 1, for backward compatibility. You can assume <string.h>
- exists. */
+/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
@@ -131,8 +141,7 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Always define to 1, for backward compatibility. You can assume the C90
- standard headers exist. */
+/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Which sysdep header to include */
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index c2faa23d..521f43f3 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -366,6 +366,30 @@ krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
}
}
+/**
+ * krt_assume_onlink - check if routes on interface are considered onlink
+ * @iface: The interface of the next hop
+ * @ipv6: Switch to only consider IPv6 or IPv4 addresses.
+ *
+ * The BSD kernel does not support an onlink flag. If the interface has only
+ * host addresses configured, all routes should be considered as onlink and
+ * the function returns 1.
+ */
+static int
+krt_assume_onlink(struct iface *iface, int ipv6)
+{
+ const u8 type = ipv6 ? NET_IP6 : NET_IP4;
+
+ struct ifa *ifa;
+ WALK_LIST(ifa, iface->addrs)
+ {
+ if ((ifa->prefix.type == type) && !(ifa->flags & IA_HOST))
+ return 0;
+ }
+
+ return 1;
+}
+
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
static void
@@ -453,7 +477,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
net_fill_ip4(&ndst, ipa_to_ip4(idst), pxlen);
if ((flags & RTF_GATEWAY) && ipa_zero(igate))
- { log(L_ERR "%s (%N) - missing gateway", errmsg, ndst); return; }
+ { log(L_ERR "%s (%N) - missing gateway", errmsg, &ndst); return; }
u32 self_mask = RTF_PROTO1;
u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
@@ -528,15 +552,21 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
a.dest = RTD_UNICAST;
if (flags & RTF_GATEWAY)
{
- neighbor *ng;
a.nh.gw = igate;
/* Clean up embedded interface ID returned in link-local address */
if (ipa_is_link_local(a.nh.gw))
_I0(a.nh.gw) = 0xfe800000;
- ng = neigh_find(&p->p, a.nh.gw, a.nh.iface, 0);
- if (!ng || (ng->scope == SCOPE_HOST))
+ /* The BSD kernel does not support an onlink flag. We heuristically
+ set the onlink flag, if the iface has only host addresses. */
+ if (krt_assume_onlink(a.nh.iface, ipv6))
+ a.nh.flags |= RNF_ONLINK;
+
+ neighbor *nbr;
+ nbr = neigh_find(&p->p, a.nh.gw, a.nh.iface,
+ (a.nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
+ if (!nbr || (nbr->scope == SCOPE_HOST))
{
/* Ignore routes with next-hop 127.0.0.1, host routes with such
next-hop appear on OpenBSD for address aliases. */
@@ -665,6 +695,9 @@ krt_read_ifinfo(struct ks_msg *msg, int scan)
else
f.flags |= IF_MULTIACCESS; /* NBMA */
+ if (fl & IFF_MULTICAST)
+ f.flags |= IF_MULTICAST;
+
iface = if_update(&f);
if (!scan)
diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h
index c757960a..f1887fb4 100644
--- a/sysdep/bsd/sysio.h
+++ b/sysdep/bsd/sysio.h
@@ -271,3 +271,9 @@ sk_set_priority(sock *s, int prio UNUSED)
{
ERR_MSG("Socket priority not supported");
}
+
+static inline int
+sk_set_freebind(sock *s)
+{
+ ERR_MSG("Freebind is not supported");
+}
diff --git a/sysdep/config.h b/sysdep/config.h
index 55be90f0..b0531844 100644
--- a/sysdep/config.h
+++ b/sysdep/config.h
@@ -13,7 +13,7 @@
#ifdef GIT_LABEL
#define BIRD_VERSION XSTR1(GIT_LABEL)
#else
-#define BIRD_VERSION "2.0.8"
+#define BIRD_VERSION "2.0.9"
#endif
/* Include parameters determined by configure script */
diff --git a/sysdep/linux/krt-sys.h b/sysdep/linux/krt-sys.h
index a8af4c95..8897f889 100644
--- a/sysdep/linux/krt-sys.h
+++ b/sysdep/linux/krt-sys.h
@@ -69,6 +69,7 @@ static inline struct ifa * kif_get_primary_ip(struct iface *i UNUSED) { return N
struct krt_params {
u32 table_id; /* Kernel table ID we sync with */
u32 metric; /* Kernel metric used for all routes */
+ uint netlink_rx_buffer; /* Rx buffer size for the netlink socket */
};
struct krt_state {
diff --git a/sysdep/linux/netlink.Y b/sysdep/linux/netlink.Y
index 7097f577..487ad1d8 100644
--- a/sysdep/linux/netlink.Y
+++ b/sysdep/linux/netlink.Y
@@ -10,7 +10,8 @@ CF_HDR
CF_DECLS
-CF_KEYWORDS(KERNEL, TABLE, METRIC, KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_MTU, KRT_WINDOW,
+CF_KEYWORDS(KERNEL, TABLE, METRIC, NETLINK, RX, BUFFER,
+ KRT_PREFSRC, KRT_REALM, KRT_SCOPE, KRT_MTU, KRT_WINDOW,
KRT_RTT, KRT_RTTVAR, KRT_SSTRESH, KRT_CWND, KRT_ADVMSS, KRT_REORDERING,
KRT_HOPLIMIT, KRT_INITCWND, KRT_RTO_MIN, KRT_INITRWND, KRT_QUICKACK,
KRT_LOCK_MTU, KRT_LOCK_WINDOW, KRT_LOCK_RTT, KRT_LOCK_RTTVAR,
@@ -24,6 +25,7 @@ kern_proto: kern_proto kern_sys_item ';' ;
kern_sys_item:
KERNEL TABLE expr { THIS_KRT->sys.table_id = $3; }
| METRIC expr { THIS_KRT->sys.metric = $2; }
+ | NETLINK RX BUFFER expr { THIS_KRT->sys.netlink_rx_buffer = $4; }
;
dynamic_attr: KRT_PREFSRC { $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } ;
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index fdf3f2db..29b744cb 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -69,6 +69,10 @@
#define RTA_ENCAP 22
#endif
+#ifndef NETLINK_GET_STRICT_CHK
+#define NETLINK_GET_STRICT_CHK 12
+#endif
+
#define krt_ipv4(p) ((p)->af == AF_INET)
#define krt_ecmp6(p) ((p)->af == AF_INET6)
@@ -130,7 +134,7 @@ struct nl_sock
uint last_size;
};
-#define NL_RX_SIZE 8192
+#define NL_RX_SIZE 32768
#define NL_OP_DELETE 0
#define NL_OP_ADD (NLM_F_CREATE|NLM_F_EXCL)
@@ -158,10 +162,46 @@ nl_open_sock(struct nl_sock *nl)
}
static void
+nl_set_strict_dump(struct nl_sock *nl UNUSED, int strict UNUSED)
+{
+ /*
+ * Strict checking is not necessary, it improves behavior on newer kernels.
+ * If it is not available (missing SOL_NETLINK compile-time, or ENOPROTOOPT
+ * run-time), we can just ignore it.
+ */
+#ifdef SOL_NETLINK
+ setsockopt(nl->fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &strict, sizeof(strict));
+#endif
+}
+
+static void
+nl_set_rcvbuf(int fd, uint val)
+{
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &val, sizeof(val)) < 0)
+ log(L_WARN "KRT: Cannot set netlink rx buffer size to %u: %m", val);
+}
+
+static uint
+nl_cfg_rx_buffer_size(struct config *cfg)
+{
+ uint bufsize = 0;
+
+ struct proto_config *pc;
+ WALK_LIST(pc, cfg->protos)
+ if ((pc->protocol == &proto_unix_kernel) && !pc->disabled)
+ bufsize = MAX(bufsize, ((struct krt_config *) pc)->sys.netlink_rx_buffer);
+
+ return bufsize;
+}
+
+
+static void
nl_open(void)
{
nl_open_sock(&nl_scan);
nl_open_sock(&nl_req);
+
+ nl_set_strict_dump(&nl_scan, 1);
}
static void
@@ -180,20 +220,60 @@ nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
}
static void
-nl_request_dump(int af, int cmd)
+nl_request_dump_link(void)
{
struct {
struct nlmsghdr nh;
- struct rtgenmsg g;
+ struct ifinfomsg ifi;
} req = {
- .nh.nlmsg_type = cmd,
- .nh.nlmsg_len = sizeof(req),
+ .nh.nlmsg_type = RTM_GETLINK,
+ .nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
- .g.rtgen_family = af
+ .nh.nlmsg_seq = ++(nl_scan.seq),
+ .ifi.ifi_family = AF_UNSPEC,
};
- nl_send(&nl_scan, &req.nh);
+
+ send(nl_scan.fd, &req, sizeof(req), 0);
+ nl_scan.last_hdr = NULL;
}
+static void
+nl_request_dump_addr(int af)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct ifaddrmsg ifa;
+ } req = {
+ .nh.nlmsg_type = RTM_GETADDR,
+ .nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .nh.nlmsg_seq = ++(nl_scan.seq),
+ .ifa.ifa_family = af,
+ };
+
+ send(nl_scan.fd, &req, sizeof(req), 0);
+ nl_scan.last_hdr = NULL;
+}
+
+static void
+nl_request_dump_route(int af)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct rtmsg rtm;
+ } req = {
+ .nh.nlmsg_type = RTM_GETROUTE,
+ .nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+ .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .nh.nlmsg_seq = ++(nl_scan.seq),
+ .rtm.rtm_family = af,
+ };
+
+ send(nl_scan.fd, &req, sizeof(req), 0);
+ nl_scan.last_hdr = NULL;
+}
+
+
static struct nlmsghdr *
nl_get_reply(struct nl_sock *nl)
{
@@ -681,7 +761,7 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, e
}
static struct nexthop *
-nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr *ra, int af)
+nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, const net_addr *n, struct rtattr *ra, int af, int krt_src)
{
struct rtattr *a[BIRD_RTA_MAX];
struct rtnexthop *nh = RTA_DATA(ra);
@@ -695,9 +775,9 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
{
/* Use RTNH_OK(nh,len) ?? */
if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
- return NULL;
+ goto err;
- if (nh->rtnh_flags & RTNH_F_DEAD)
+ if ((nh->rtnh_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD))
goto next;
*last = rv = lp_allocz(s->pool, NEXTHOP_MAX_SIZE);
@@ -706,7 +786,10 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
rv->weight = nh->rtnh_hops;
rv->iface = if_find_by_index(nh->rtnh_ifindex);
if (!rv->iface)
- return NULL;
+ {
+ log(L_ERR "KRT: Received route %N with unknown ifindex %u", n, nh->rtnh_ifindex);
+ return NULL;
+ }
/* Nonexistent RTNH_PAYLOAD ?? */
nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
@@ -714,18 +797,18 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
{
case AF_INET:
if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a)))
- return NULL;
+ goto err;
break;
case AF_INET6:
if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want6, a, sizeof(a)))
- return NULL;
+ goto err;
break;
#ifdef HAVE_MPLS_KERNEL
case AF_MPLS:
if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want_mpls, a, sizeof(a)))
- return NULL;
+ goto err;
if (a[RTA_NEWDST])
rv->labels = rta_get_mpls(a[RTA_NEWDST], rv->label);
@@ -734,7 +817,7 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
#endif
default:
- return NULL;
+ goto err;
}
if (a[RTA_GATEWAY])
@@ -757,14 +840,19 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
nbr = neigh_find(&p->p, rv->gw, rv->iface,
(rv->flags & RNF_ONLINK) ? NEF_ONLINK : 0);
if (!nbr || (nbr->scope == SCOPE_HOST))
- return NULL;
+ {
+ log(L_ERR "KRT: Received route %N with strange next-hop %I", n, rv->gw);
+ return NULL;
+ }
}
#ifdef HAVE_MPLS_KERNEL
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE])
{
- if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) {
- log(L_WARN "KRT: Unknown encapsulation method %d in multipath", rta_get_u16(a[RTA_ENCAP_TYPE]));
+ if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS)
+ {
+ log(L_WARN "KRT: Received route %N with unknown encapsulation method %d",
+ n, rta_get_u16(a[RTA_ENCAP_TYPE]));
return NULL;
}
@@ -785,6 +873,10 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
first = nexthop_sort(first);
return first;
+
+err:
+ log(L_ERR "KRT: Received strange multipath route %N", n);
+ return NULL;
}
static void
@@ -1139,7 +1231,7 @@ kif_do_scan(struct kif_proto *p UNUSED)
if_start_update();
- nl_request_dump(AF_UNSPEC, RTM_GETLINK);
+ nl_request_dump_link();
while (h = nl_get_scan())
if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
nl_parse_link(h, 1);
@@ -1166,14 +1258,14 @@ kif_do_scan(struct kif_proto *p UNUSED)
}
}
- nl_request_dump(AF_INET, RTM_GETADDR);
+ nl_request_dump_addr(AF_INET);
while (h = nl_get_scan())
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
nl_parse_addr(h, 1);
else
log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
- nl_request_dump(AF_INET6, RTM_GETADDR);
+ nl_request_dump_addr(AF_INET6);
while (h = nl_get_scan())
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
nl_parse_addr(h, 1);
@@ -1523,7 +1615,8 @@ nl_parse_end(struct nl_parse_state *s)
}
-#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
+#define SKIP0(ARG, ...) do { DBG("KRT: Ignoring route - " ARG, ##__VA_ARGS__); return; } while(0)
+#define SKIP(ARG, ...) do { DBG("KRT: Ignoring route %N - " ARG, &dst, ##__VA_ARGS__); return; } while(0)
static void
nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
@@ -1576,10 +1669,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
return;
if (!a[RTA_DST])
- SKIP("MPLS route without RTA_DST");
+ SKIP0("MPLS route without RTA_DST\n");
if (rta_get_mpls(a[RTA_DST], rta_mpls_stack) != 1)
- SKIP("MPLS route with multi-label RTA_DST");
+ SKIP0("MPLS route with multi-label RTA_DST\n");
net_fill_mpls(&dst, rta_mpls_stack[0]);
break;
@@ -1597,6 +1690,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
else
table_id = i->rtm_table;
+ if (i->rtm_flags & RTM_F_CLONED)
+ SKIP("cloned\n");
+
/* Do we know this table? */
p = HASH_FIND(nl_table_map, RTH, i->rtm_family, table_id);
if (!p)
@@ -1675,19 +1771,16 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (a[RTA_MULTIPATH])
{
- struct nexthop *nh = nl_parse_multipath(s, p, a[RTA_MULTIPATH], i->rtm_family);
+ struct nexthop *nh = nl_parse_multipath(s, p, n, a[RTA_MULTIPATH], i->rtm_family, krt_src);
if (!nh)
- {
- log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
- return;
- }
+ SKIP("strange RTA_MULTIPATH\n");
nexthop_link(ra, nh);
break;
}
- if (i->rtm_flags & RTNH_F_DEAD)
- return;
+ if ((i->rtm_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD))
+ SKIP("ignore RTNH_F_DEAD\n");
ra->nh.iface = if_find_by_index(oif);
if (!ra->nh.iface)
@@ -1889,7 +1982,7 @@ krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NUL
struct nl_parse_state s;
nl_parse_begin(&s, 1);
- nl_request_dump(AF_UNSPEC, RTM_GETROUTE);
+ nl_request_dump_route(AF_UNSPEC);
while (h = nl_get_scan())
if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
nl_parse_route(&s, h);
@@ -1904,6 +1997,8 @@ krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NUL
static sock *nl_async_sk; /* BIRD socket for asynchronous notifications */
static byte *nl_async_rx_buffer; /* Receive buffer */
+static uint nl_async_bufsize; /* Kernel rx buffer size for the netlink socket */
+static struct config *nl_last_config; /* For tracking changes to nl_async_bufsize */
static void
nl_async_msg(struct nlmsghdr *h)
@@ -2039,6 +2134,32 @@ nl_open_async(void)
bug("Netlink: sk_open failed");
}
+static void
+nl_update_async_bufsize(void)
+{
+ /* No async socket */
+ if (!nl_async_sk)
+ return;
+
+ /* Already reconfigured */
+ if (nl_last_config == config)
+ return;
+
+ /* Update netlink buffer size */
+ uint bufsize = nl_cfg_rx_buffer_size(config);
+ if (bufsize && (bufsize != nl_async_bufsize))
+ {
+ /* Log message for reconfigurations only */
+ if (nl_last_config)
+ log(L_INFO "KRT: Changing netlink rx buffer size to %u", bufsize);
+
+ nl_set_rcvbuf(nl_async_sk->fd, bufsize);
+ nl_async_bufsize = bufsize;
+ }
+
+ nl_last_config = config;
+}
+
/*
* Interface to the UNIX krt module
@@ -2067,6 +2188,7 @@ krt_sys_start(struct krt_proto *p)
nl_open();
nl_open_async();
+ nl_update_async_bufsize();
return 1;
}
@@ -2074,12 +2196,16 @@ krt_sys_start(struct krt_proto *p)
void
krt_sys_shutdown(struct krt_proto *p)
{
+ nl_update_async_bufsize();
+
HASH_REMOVE2(nl_table_map, RTH, krt_pool, p);
}
int
krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
{
+ nl_update_async_bufsize();
+
return (n->sys.table_id == o->sys.table_id) && (n->sys.metric == o->sys.metric);
}
diff --git a/sysdep/linux/netlink.c.orig b/sysdep/linux/netlink.c.orig
new file mode 100644
index 00000000..7cea5322
--- /dev/null
+++ b/sysdep/linux/netlink.c.orig
@@ -0,0 +1,2179 @@
+/*
+ * BIRD -- Linux Netlink Interface
+ *
+ * (c) 1999--2000 Martin Mares <mj@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <alloca.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#undef LOCAL_DEBUG
+
+#include "nest/bird.h"
+#include "nest/route.h"
+#include "nest/protocol.h"
+#include "nest/iface.h"
+#include "lib/alloca.h"
+#include "sysdep/unix/unix.h"
+#include "sysdep/unix/krt.h"
+#include "lib/socket.h"
+#include "lib/string.h"
+#include "lib/hash.h"
+#include "conf/conf.h"
+
+#include <asm/types.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#ifdef HAVE_MPLS_KERNEL
+#include <linux/lwtunnel.h>
+#endif
+
+#ifndef MSG_TRUNC /* Hack: Several versions of glibc miss this one :( */
+#define MSG_TRUNC 0x20
+#endif
+
+#ifndef IFA_FLAGS
+#define IFA_FLAGS 8
+#endif
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000
+#endif
+
+#ifndef RTA_TABLE
+#define RTA_TABLE 15
+#endif
+
+#ifndef RTA_VIA
+#define RTA_VIA 18
+#endif
+
+#ifndef RTA_NEWDST
+#define RTA_NEWDST 19
+#endif
+
+#ifndef RTA_ENCAP_TYPE
+#define RTA_ENCAP_TYPE 21
+#endif
+
+#ifndef RTA_ENCAP
+#define RTA_ENCAP 22
+#endif
+
+#define krt_ipv4(p) ((p)->af == AF_INET)
+#define krt_ecmp6(p) ((p)->af == AF_INET6)
+
+const int rt_default_ecmp = 16;
+
+/*
+ * Structure nl_parse_state keeps state of received route processing. Ideally,
+ * we could just independently parse received Netlink messages and immediately
+ * propagate received routes to the rest of BIRD, but older Linux kernel (before
+ * version 4.11) represents and announces IPv6 ECMP routes not as one route with
+ * multiple next hops (like RTA_MULTIPATH in IPv4 ECMP), but as a sequence of
+ * routes with the same prefix. More recent kernels work as with IPv4.
+ *
+ * Therefore, BIRD keeps currently processed route in nl_parse_state structure
+ * and postpones its propagation until we expect it to be final; i.e., when
+ * non-matching route is received or when the scan ends. When another matching
+ * route is received, it is merged with the already processed route to form an
+ * ECMP route. Note that merging is done only for IPv6 (merge == 1), but the
+ * postponing is done in both cases (for simplicity). All IPv4 routes or IPv6
+ * routes with RTA_MULTIPATH set are just considered non-matching.
+ *
+ * This is ignored for asynchronous notifications (every notification is handled
+ * as a separate route). It is not an issue for our routes, as we ignore such
+ * notifications anyways. But importing alien IPv6 ECMP routes does not work
+ * properly with older kernels.
+ *
+ * Whatever the kernel version is, IPv6 ECMP routes are sent as multiple routes
+ * for the same prefix.
+ */
+
+struct nl_parse_state
+{
+ struct linpool *pool;
+ int scan;
+ int merge;
+
+ net *net;
+ rta *attrs;
+ struct krt_proto *proto;
+ s8 new;
+ s8 krt_src;
+ u8 krt_type;
+ u8 krt_proto;
+ u32 krt_metric;
+
+ u32 rta_flow; /* Used during parsing */
+};
+
+/*
+ * Synchronous Netlink interface
+ */
+
+struct nl_sock
+{
+ int fd;
+ u32 seq;
+ byte *rx_buffer; /* Receive buffer */
+ struct nlmsghdr *last_hdr; /* Recently received packet */
+ uint last_size;
+};
+
+#define NL_RX_SIZE 8192
+
+#define NL_OP_DELETE 0
+#define NL_OP_ADD (NLM_F_CREATE|NLM_F_EXCL)
+#define NL_OP_REPLACE (NLM_F_CREATE|NLM_F_REPLACE)
+#define NL_OP_APPEND (NLM_F_CREATE|NLM_F_APPEND)
+
+static linpool *nl_linpool;
+
+static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous scan */
+static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */
+
+static void
+nl_open_sock(struct nl_sock *nl)
+{
+ if (nl->fd < 0)
+ {
+ nl->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (nl->fd < 0)
+ die("Unable to open rtnetlink socket: %m");
+ nl->seq = (u32) (current_time() TO_S); /* Or perhaps random_u32() ? */
+ nl->rx_buffer = xmalloc(NL_RX_SIZE);
+ nl->last_hdr = NULL;
+ nl->last_size = 0;
+ }
+}
+
+static void
+nl_open(void)
+{
+ nl_open_sock(&nl_scan);
+ nl_open_sock(&nl_req);
+}
+
+static void
+nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
+{
+ struct sockaddr_nl sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+ nh->nlmsg_pid = 0;
+ nh->nlmsg_seq = ++(nl->seq);
+ nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len);
+ if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
+ die("rtnetlink sendto: %m");
+ nl->last_hdr = NULL;
+}
+
+static void
+nl_request_dump(int af, int cmd)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct rtgenmsg g;
+ } req = {
+ .nh.nlmsg_type = cmd,
+ .nh.nlmsg_len = sizeof(req),
+ .nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .g.rtgen_family = af
+ };
+ nl_send(&nl_scan, &req.nh);
+}
+
+static struct nlmsghdr *
+nl_get_reply(struct nl_sock *nl)
+{
+ for(;;)
+ {
+ if (!nl->last_hdr)
+ {
+ struct iovec iov = { nl->rx_buffer, NL_RX_SIZE };
+ struct sockaddr_nl sa;
+ struct msghdr m = {
+ .msg_name = &sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+ int x = recvmsg(nl->fd, &m, 0);
+ if (x < 0)
+ die("nl_get_reply: %m");
+ if (sa.nl_pid) /* It isn't from the kernel */
+ {
+ DBG("Non-kernel packet\n");
+ continue;
+ }
+ nl->last_size = x;
+ nl->last_hdr = (void *) nl->rx_buffer;
+ if (m.msg_flags & MSG_TRUNC)
+ bug("nl_get_reply: got truncated reply which should be impossible");
+ }
+ if (NLMSG_OK(nl->last_hdr, nl->last_size))
+ {
+ struct nlmsghdr *h = nl->last_hdr;
+ nl->last_hdr = NLMSG_NEXT(h, nl->last_size);
+ if (h->nlmsg_seq != nl->seq)
+ {
+ log(L_WARN "nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
+ h->nlmsg_seq, nl->seq);
+ continue;
+ }
+ return h;
+ }
+ if (nl->last_size)
+ log(L_WARN "nl_get_reply: Found packet remnant of size %d", nl->last_size);
+ nl->last_hdr = NULL;
+ }
+}
+
+static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS;
+
+static int
+nl_error(struct nlmsghdr *h, int ignore_esrch)
+{
+ struct nlmsgerr *e;
+ int ec;
+
+ if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+ {
+ log(L_WARN "Netlink: Truncated error message received");
+ return ENOBUFS;
+ }
+ e = (struct nlmsgerr *) NLMSG_DATA(h);
+ ec = -e->error;
+ if (ec && !(ignore_esrch && (ec == ESRCH)))
+ log_rl(&rl_netlink_err, L_WARN "Netlink: %s", strerror(ec));
+ return ec;
+}
+
+static struct nlmsghdr *
+nl_get_scan(void)
+{
+ struct nlmsghdr *h = nl_get_reply(&nl_scan);
+
+ if (h->nlmsg_type == NLMSG_DONE)
+ return NULL;
+ if (h->nlmsg_type == NLMSG_ERROR)
+ {
+ nl_error(h, 0);
+ return NULL;
+ }
+ return h;
+}
+
+static int
+nl_exchange(struct nlmsghdr *pkt, int ignore_esrch)
+{
+ struct nlmsghdr *h;
+
+ nl_send(&nl_req, pkt);
+ for(;;)
+ {
+ h = nl_get_reply(&nl_req);
+ if (h->nlmsg_type == NLMSG_ERROR)
+ break;
+ log(L_WARN "nl_exchange: Unexpected reply received");
+ }
+ return nl_error(h, ignore_esrch) ? -1 : 0;
+}
+
+/*
+ * Netlink attributes
+ */
+
+static int nl_attr_len;
+
+static void *
+nl_checkin(struct nlmsghdr *h, int lsize)
+{
+ nl_attr_len = h->nlmsg_len - NLMSG_LENGTH(lsize);
+ if (nl_attr_len < 0)
+ {
+ log(L_ERR "nl_checkin: underrun by %d bytes", -nl_attr_len);
+ return NULL;
+ }
+ return NLMSG_DATA(h);
+}
+
+struct nl_want_attrs {
+ u8 defined:1;
+ u8 checksize:1;
+ u8 size;
+};
+
+
+#define BIRD_IFLA_MAX (IFLA_WIRELESS+1)
+
+static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
+ [IFLA_IFNAME] = { 1, 0, 0 },
+ [IFLA_MTU] = { 1, 1, sizeof(u32) },
+ [IFLA_MASTER] = { 1, 1, sizeof(u32) },
+ [IFLA_WIRELESS] = { 1, 0, 0 },
+};
+
+
+#define BIRD_IFA_MAX (IFA_FLAGS+1)
+
+static struct nl_want_attrs ifa_attr_want4[BIRD_IFA_MAX] = {
+ [IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) },
+ [IFA_LOCAL] = { 1, 1, sizeof(ip4_addr) },
+ [IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) },
+ [IFA_FLAGS] = { 1, 1, sizeof(u32) },
+};
+
+static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
+ [IFA_ADDRESS] = { 1, 1, sizeof(ip6_addr) },
+ [IFA_LOCAL] = { 1, 1, sizeof(ip6_addr) },
+ [IFA_FLAGS] = { 1, 1, sizeof(u32) },
+};
+
+
+#define BIRD_RTA_MAX (RTA_ENCAP+1)
+
+static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = {
+ [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
+ [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
+ [RTA_ENCAP] = { 1, 0, 0 },
+};
+
+static struct nl_want_attrs nexthop_attr_want6[BIRD_RTA_MAX] = {
+ [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
+ [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
+ [RTA_ENCAP] = { 1, 0, 0 },
+};
+
+#ifdef HAVE_MPLS_KERNEL
+static struct nl_want_attrs nexthop_attr_want_mpls[BIRD_RTA_MAX] = {
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_NEWDST] = { 1, 0, 0 },
+};
+
+static struct nl_want_attrs encap_mpls_want[BIRD_RTA_MAX] = {
+ [RTA_DST] = { 1, 0, 0 },
+};
+#endif
+
+static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
+ [RTA_DST] = { 1, 1, sizeof(ip4_addr) },
+ [RTA_OIF] = { 1, 1, sizeof(u32) },
+ [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
+ [RTA_PRIORITY] = { 1, 1, sizeof(u32) },
+ [RTA_PREFSRC] = { 1, 1, sizeof(ip4_addr) },
+ [RTA_METRICS] = { 1, 0, 0 },
+ [RTA_MULTIPATH] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
+ [RTA_TABLE] = { 1, 1, sizeof(u32) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
+ [RTA_ENCAP] = { 1, 0, 0 },
+};
+
+static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
+ [RTA_DST] = { 1, 1, sizeof(ip6_addr) },
+ [RTA_SRC] = { 1, 1, sizeof(ip6_addr) },
+ [RTA_IIF] = { 1, 1, sizeof(u32) },
+ [RTA_OIF] = { 1, 1, sizeof(u32) },
+ [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
+ [RTA_PRIORITY] = { 1, 1, sizeof(u32) },
+ [RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) },
+ [RTA_METRICS] = { 1, 0, 0 },
+ [RTA_MULTIPATH] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
+ [RTA_TABLE] = { 1, 1, sizeof(u32) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
+ [RTA_ENCAP] = { 1, 0, 0 },
+};
+
+#ifdef HAVE_MPLS_KERNEL
+static struct nl_want_attrs rtm_attr_want_mpls[BIRD_RTA_MAX] = {
+ [RTA_DST] = { 1, 1, sizeof(u32) },
+ [RTA_IIF] = { 1, 1, sizeof(u32) },
+ [RTA_OIF] = { 1, 1, sizeof(u32) },
+ [RTA_PRIORITY] = { 1, 1, sizeof(u32) },
+ [RTA_METRICS] = { 1, 0, 0 },
+ [RTA_MULTIPATH] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
+ [RTA_TABLE] = { 1, 1, sizeof(u32) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_NEWDST] = { 1, 0, 0 },
+};
+#endif
+
+
+static int
+nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k, int ksize)
+{
+ int max = ksize / sizeof(struct rtattr *);
+ bzero(k, ksize);
+
+ for ( ; RTA_OK(a, nl_attr_len); a = RTA_NEXT(a, nl_attr_len))
+ {
+ if ((a->rta_type >= max) || !want[a->rta_type].defined)
+ continue;
+
+ if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size))
+ {
+ log(L_ERR "nl_parse_attrs: Malformed attribute received");
+ return 0;
+ }
+
+ k[a->rta_type] = a;
+ }
+
+ if (nl_attr_len)
+ {
+ log(L_ERR "nl_parse_attrs: remnant of size %d", nl_attr_len);
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline u16 rta_get_u16(struct rtattr *a)
+{ return *(u16 *) RTA_DATA(a); }
+
+static inline u32 rta_get_u32(struct rtattr *a)
+{ return *(u32 *) RTA_DATA(a); }
+
+static inline ip4_addr rta_get_ip4(struct rtattr *a)
+{ return ip4_ntoh(*(ip4_addr *) RTA_DATA(a)); }
+
+static inline ip6_addr rta_get_ip6(struct rtattr *a)
+{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); }
+
+static inline ip_addr rta_get_ipa(struct rtattr *a)
+{
+ if (RTA_PAYLOAD(a) == sizeof(ip4_addr))
+ return ipa_from_ip4(rta_get_ip4(a));
+ else
+ return ipa_from_ip6(rta_get_ip6(a));
+}
+
+#ifdef HAVE_MPLS_KERNEL
+static inline ip_addr rta_get_via(struct rtattr *a)
+{
+ struct rtvia *v = RTA_DATA(a);
+ switch(v->rtvia_family) {
+ case AF_INET: return ipa_from_ip4(ip4_ntoh(*(ip4_addr *) v->rtvia_addr));
+ case AF_INET6: return ipa_from_ip6(ip6_ntoh(*(ip6_addr *) v->rtvia_addr));
+ }
+ return IPA_NONE;
+}
+
+static u32 rta_mpls_stack[MPLS_MAX_LABEL_STACK];
+static inline int rta_get_mpls(struct rtattr *a, u32 *stack)
+{
+ if (!a)
+ return 0;
+
+ if (RTA_PAYLOAD(a) % 4)
+ log(L_WARN "KRT: Strange length of received MPLS stack: %u", RTA_PAYLOAD(a));
+
+ int labels = mpls_get(RTA_DATA(a), RTA_PAYLOAD(a) & ~0x3, stack);
+
+ if (labels < 0)
+ {
+ log(L_WARN "KRT: Too long MPLS stack received, ignoring");
+ labels = 0;
+ }
+
+ return labels;
+}
+#endif
+
+struct rtattr *
+nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
+{
+ uint pos = NLMSG_ALIGN(h->nlmsg_len);
+ uint len = RTA_LENGTH(dlen);
+
+ if (pos + len > bufsize)
+ bug("nl_add_attr: packet buffer overflow");
+
+ struct rtattr *a = (struct rtattr *)((char *)h + pos);
+ a->rta_type = code;
+ a->rta_len = len;
+ h->nlmsg_len = pos + len;
+
+ if (dlen > 0)
+ memcpy(RTA_DATA(a), data, dlen);
+
+ return a;
+}
+
+static inline struct rtattr *
+nl_open_attr(struct nlmsghdr *h, uint bufsize, uint code)
+{
+ return nl_add_attr(h, bufsize, code, NULL, 0);
+}
+
+static inline void
+nl_close_attr(struct nlmsghdr *h, struct rtattr *a)
+{
+ a->rta_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)a;
+}
+
+static inline void
+nl_add_attr_u16(struct nlmsghdr *h, uint bufsize, int code, u16 data)
+{
+ nl_add_attr(h, bufsize, code, &data, 2);
+}
+
+static inline void
+nl_add_attr_u32(struct nlmsghdr *h, uint bufsize, int code, u32 data)
+{
+ nl_add_attr(h, bufsize, code, &data, 4);
+}
+
+static inline void
+nl_add_attr_ip4(struct nlmsghdr *h, uint bufsize, int code, ip4_addr ip4)
+{
+ ip4 = ip4_hton(ip4);
+ nl_add_attr(h, bufsize, code, &ip4, sizeof(ip4));
+}
+
+static inline void
+nl_add_attr_ip6(struct nlmsghdr *h, uint bufsize, int code, ip6_addr ip6)
+{
+ ip6 = ip6_hton(ip6);
+ nl_add_attr(h, bufsize, code, &ip6, sizeof(ip6));
+}
+
+static inline void
+nl_add_attr_ipa(struct nlmsghdr *h, uint bufsize, int code, ip_addr ipa)
+{
+ if (ipa_is_ip4(ipa))
+ nl_add_attr_ip4(h, bufsize, code, ipa_to_ip4(ipa));
+ else
+ nl_add_attr_ip6(h, bufsize, code, ipa_to_ip6(ipa));
+}
+
+#ifdef HAVE_MPLS_KERNEL
+static inline void
+nl_add_attr_mpls(struct nlmsghdr *h, uint bufsize, int code, int len, u32 *stack)
+{
+ char buf[len*4];
+ mpls_put(buf, len, stack);
+ nl_add_attr(h, bufsize, code, buf, len*4);
+}
+
+static inline void
+nl_add_attr_mpls_encap(struct nlmsghdr *h, uint bufsize, int len, u32 *stack)
+{
+ nl_add_attr_u16(h, bufsize, RTA_ENCAP_TYPE, LWTUNNEL_ENCAP_MPLS);
+
+ struct rtattr *nest = nl_open_attr(h, bufsize, RTA_ENCAP);
+ nl_add_attr_mpls(h, bufsize, RTA_DST, len, stack);
+ nl_close_attr(h, nest);
+}
+
+static inline void
+nl_add_attr_via(struct nlmsghdr *h, uint bufsize, ip_addr ipa)
+{
+ struct rtvia *via = alloca(sizeof(struct rtvia) + 16);
+
+ if (ipa_is_ip4(ipa))
+ {
+ via->rtvia_family = AF_INET;
+ put_ip4(via->rtvia_addr, ipa_to_ip4(ipa));
+ nl_add_attr(h, bufsize, RTA_VIA, via, sizeof(struct rtvia) + 4);
+ }
+ else
+ {
+ via->rtvia_family = AF_INET6;
+ put_ip6(via->rtvia_addr, ipa_to_ip6(ipa));
+ nl_add_attr(h, bufsize, RTA_VIA, via, sizeof(struct rtvia) + 16);
+ }
+}
+#endif
+
+static inline struct rtnexthop *
+nl_open_nexthop(struct nlmsghdr *h, uint bufsize)
+{
+ uint pos = NLMSG_ALIGN(h->nlmsg_len);
+ uint len = RTNH_LENGTH(0);
+
+ if (pos + len > bufsize)
+ bug("nl_open_nexthop: packet buffer overflow");
+
+ h->nlmsg_len = pos + len;
+
+ return (void *)h + pos;
+}
+
+static inline void
+nl_close_nexthop(struct nlmsghdr *h, struct rtnexthop *nh)
+{
+ nh->rtnh_len = (void *)h + NLMSG_ALIGN(h->nlmsg_len) - (void *)nh;
+}
+
+static inline void
+nl_add_nexthop(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af UNUSED)
+{
+#ifdef HAVE_MPLS_KERNEL
+ if (nh->labels > 0)
+ if (af == AF_MPLS)
+ nl_add_attr_mpls(h, bufsize, RTA_NEWDST, nh->labels, nh->label);
+ else
+ nl_add_attr_mpls_encap(h, bufsize, nh->labels, nh->label);
+
+ if (ipa_nonzero(nh->gw))
+ {
+ if (af == (ipa_is_ip4(nh->gw) ? AF_INET : AF_INET6))
+ nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
+ else
+ nl_add_attr_via(h, bufsize, nh->gw);
+ }
+#else
+
+ if (ipa_nonzero(nh->gw))
+ nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
+#endif
+}
+
+static void
+nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs)
+{
+ struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
+ eattr *flow = ea_find(eattrs, EA_KRT_REALM);
+
+ for (; nh; nh = nh->next)
+ {
+ struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
+
+ rtnh->rtnh_flags = 0;
+ rtnh->rtnh_hops = nh->weight;
+ rtnh->rtnh_ifindex = nh->iface->index;
+
+ nl_add_nexthop(h, bufsize, nh, af);
+
+ if (nh->flags & RNF_ONLINK)
+ rtnh->rtnh_flags |= RTNH_F_ONLINK;
+
+ /* Our KRT_REALM is per-route, but kernel RTA_FLOW is per-nexthop.
+ Therefore, we need to attach the same attribute to each nexthop. */
+ if (flow)
+ nl_add_attr_u32(h, bufsize, RTA_FLOW, flow->u.data);
+
+ nl_close_nexthop(h, rtnh);
+ }
+
+ nl_close_attr(h, a);
+}
+
+static struct nexthop *
+nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, const net_addr *n, struct rtattr *ra, int af, int krt_src)
+{
+ struct rtattr *a[BIRD_RTA_MAX];
+ struct rtnexthop *nh = RTA_DATA(ra);
+ struct nexthop *rv, *first, **last;
+ unsigned len = RTA_PAYLOAD(ra);
+
+ first = NULL;
+ last = &first;
+
+ while (len)
+ {
+ /* Use RTNH_OK(nh,len) ?? */
+ if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
+ goto err;
+
+ if ((nh->rtnh_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD))
+ goto next;
+
+ *last = rv = lp_allocz(s->pool, NEXTHOP_MAX_SIZE);
+ last = &(rv->next);
+
+ rv->weight = nh->rtnh_hops;
+ rv->iface = if_find_by_index(nh->rtnh_ifindex);
+ if (!rv->iface)
+ {
+ log(L_ERR "KRT: Received route %N with unknown ifindex %u", n, nh->rtnh_ifindex);
+ return NULL;
+ }
+
+ /* Nonexistent RTNH_PAYLOAD ?? */
+ nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
+ switch (af)
+ {
+ case AF_INET:
+ if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a)))
+ goto err;
+ break;
+
+ case AF_INET6:
+ if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want6, a, sizeof(a)))
+ goto err;
+ break;
+
+#ifdef HAVE_MPLS_KERNEL
+ case AF_MPLS:
+ if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want_mpls, a, sizeof(a)))
+ goto err;
+
+ if (a[RTA_NEWDST])
+ rv->labels = rta_get_mpls(a[RTA_NEWDST], rv->label);
+
+ break;
+#endif
+
+ default:
+ goto err;
+ }
+
+ if (a[RTA_GATEWAY])
+ rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
+
+ if (a[RTA_FLOW])
+ s->rta_flow = rta_get_u32(a[RTA_FLOW]);
+
+#ifdef HAVE_MPLS_KERNEL
+ if (a[RTA_VIA])
+ rv->gw = rta_get_via(a[RTA_VIA]);
+#endif
+
+ if (ipa_nonzero(rv->gw))
+ {
+ if (nh->rtnh_flags & RTNH_F_ONLINK)
+ rv->flags |= RNF_ONLINK;
+
+ neighbor *nbr;
+ nbr = neigh_find(&p->p, rv->gw, rv->iface,
+ (rv->flags & RNF_ONLINK) ? NEF_ONLINK : 0);
+ if (!nbr || (nbr->scope == SCOPE_HOST))
+ {
+ log(L_ERR "KRT: Received route %N with strange next-hop %I", n, rv->gw);
+ return NULL;
+ }
+ }
+
+#ifdef HAVE_MPLS_KERNEL
+ if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE])
+ {
+ if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS)
+ {
+ log(L_WARN "KRT: Received route %N with unknown encapsulation method %d",
+ n, rta_get_u16(a[RTA_ENCAP_TYPE]));
+ return NULL;
+ }
+
+ struct rtattr *enca[BIRD_RTA_MAX];
+ nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
+ nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
+ rv->labels = rta_get_mpls(enca[RTA_DST], rv->label);
+ }
+#endif
+
+ next:
+ len -= NLMSG_ALIGN(nh->rtnh_len);
+ nh = RTNH_NEXT(nh);
+ }
+
+ /* Ensure nexthops are sorted to satisfy nest invariant */
+ if (!nexthop_is_sorted(first))
+ first = nexthop_sort(first);
+
+ return first;
+
+err:
+ log(L_ERR "KRT: Received strange multipath route %N", n);
+ return NULL;
+}
+
+static void
+nl_add_metrics(struct nlmsghdr *h, uint bufsize, u32 *metrics, int max)
+{
+ struct rtattr *a = nl_open_attr(h, bufsize, RTA_METRICS);
+ int t;
+
+ for (t = 1; t < max; t++)
+ if (metrics[0] & (1 << t))
+ nl_add_attr_u32(h, bufsize, t, metrics[t]);
+
+ nl_close_attr(h, a);
+}
+
+static int
+nl_parse_metrics(struct rtattr *hdr, u32 *metrics, int max)
+{
+ struct rtattr *a = RTA_DATA(hdr);
+ int len = RTA_PAYLOAD(hdr);
+
+ metrics[0] = 0;
+ for (; RTA_OK(a, len); a = RTA_NEXT(a, len))
+ {
+ if (a->rta_type == RTA_UNSPEC)
+ continue;
+
+ if (a->rta_type >= max)
+ continue;
+
+ if (RTA_PAYLOAD(a) != 4)
+ return -1;
+
+ metrics[0] |= 1 << a->rta_type;
+ metrics[a->rta_type] = rta_get_u32(a);
+ }
+
+ if (len > 0)
+ return -1;
+
+ return 0;
+}
+
+
+/*
+ * Scanning of interfaces
+ */
+
+static void
+nl_parse_link(struct nlmsghdr *h, int scan)
+{
+ struct ifinfomsg *i;
+ struct rtattr *a[BIRD_IFLA_MAX];
+ int new = h->nlmsg_type == RTM_NEWLINK;
+ struct iface f = {};
+ struct iface *ifi;
+ char *name;
+ u32 mtu, master = 0;
+ uint fl;
+
+ if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a)))
+ return;
+ if (!a[IFLA_IFNAME] || (RTA_PAYLOAD(a[IFLA_IFNAME]) < 2) || !a[IFLA_MTU])
+ {
+ /*
+ * IFLA_IFNAME and IFLA_MTU are required, in fact, but there may also come
+ * a message with IFLA_WIRELESS set, where (e.g.) no IFLA_IFNAME exists.
+ * We simply ignore all such messages with IFLA_WIRELESS without notice.
+ */
+
+ if (a[IFLA_WIRELESS])
+ return;
+
+ log(L_ERR "KIF: Malformed message received");
+ return;
+ }
+
+ name = RTA_DATA(a[IFLA_IFNAME]);
+ mtu = rta_get_u32(a[IFLA_MTU]);
+
+ if (a[IFLA_MASTER])
+ master = rta_get_u32(a[IFLA_MASTER]);
+
+ ifi = if_find_by_index(i->ifi_index);
+ if (!new)
+ {
+ DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name);
+ if (!ifi)
+ return;
+
+ if_delete(ifi);
+ }
+ else
+ {
+ DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags);
+ if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1))
+ if_delete(ifi);
+
+ strncpy(f.name, name, sizeof(f.name)-1);
+ f.index = i->ifi_index;
+ f.mtu = mtu;
+
+ f.master_index = master;
+ f.master = if_find_by_index(master);
+
+ fl = i->ifi_flags;
+ if (fl & IFF_UP)
+ f.flags |= IF_ADMIN_UP;
+ if (fl & IFF_LOWER_UP)
+ f.flags |= IF_LINK_UP;
+ if (fl & IFF_LOOPBACK) /* Loopback */
+ f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE;
+ else if (fl & IFF_POINTOPOINT) /* PtP */
+ f.flags |= IF_MULTICAST;
+ else if (fl & IFF_BROADCAST) /* Broadcast */
+ f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST;
+ else
+ f.flags |= IF_MULTIACCESS; /* NBMA */
+
+ if (fl & IFF_MULTICAST)
+ f.flags |= IF_MULTICAST;
+
+ ifi = if_update(&f);
+
+ if (!scan)
+ if_end_partial_update(ifi);
+ }
+}
+
+static void
+nl_parse_addr4(struct ifaddrmsg *i, int scan, int new)
+{
+ struct rtattr *a[BIRD_IFA_MAX];
+ struct iface *ifi;
+ u32 ifa_flags;
+ int scope;
+
+ if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a)))
+ return;
+
+ if (!a[IFA_LOCAL])
+ {
+ log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)");
+ return;
+ }
+ if (!a[IFA_ADDRESS])
+ {
+ log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
+ return;
+ }
+
+ ifi = if_find_by_index(i->ifa_index);
+ if (!ifi)
+ {
+ log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
+ return;
+ }
+
+ if (a[IFA_FLAGS])
+ ifa_flags = rta_get_u32(a[IFA_FLAGS]);
+ else
+ ifa_flags = i->ifa_flags;
+
+ struct ifa ifa;
+ bzero(&ifa, sizeof(ifa));
+ ifa.iface = ifi;
+ if (ifa_flags & IFA_F_SECONDARY)
+ ifa.flags |= IA_SECONDARY;
+
+ ifa.ip = rta_get_ipa(a[IFA_LOCAL]);
+
+ if (i->ifa_prefixlen > IP4_MAX_PREFIX_LENGTH)
+ {
+ log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
+ new = 0;
+ }
+ if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH)
+ {
+ ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
+ net_fill_ip4(&ifa.prefix, rta_get_ip4(a[IFA_ADDRESS]), i->ifa_prefixlen);
+
+ /* It is either a host address or a peer address */
+ if (ipa_equal(ifa.ip, ifa.brd))
+ ifa.flags |= IA_HOST;
+ else
+ {
+ ifa.flags |= IA_PEER;
+ ifa.opposite = ifa.brd;
+ }
+ }
+ else
+ {
+ net_fill_ip4(&ifa.prefix, ipa_to_ip4(ifa.ip), i->ifa_prefixlen);
+ net_normalize(&ifa.prefix);
+
+ if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 1)
+ ifa.opposite = ipa_opposite_m1(ifa.ip);
+
+ if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 2)
+ ifa.opposite = ipa_opposite_m2(ifa.ip);
+
+ if (ifi->flags & IF_BROADCAST)
+ {
+ /* If kernel offers us a broadcast address, we trust it */
+ if (a[IFA_BROADCAST])
+ ifa.brd = ipa_from_ip4(rta_get_ip4(a[IFA_BROADCAST]));
+ /* Otherwise we create one (except for /31) */
+ else if (i->ifa_prefixlen < (IP4_MAX_PREFIX_LENGTH - 1))
+ ifa.brd = ipa_from_ip4(ip4_or(ipa_to_ip4(ifa.ip),
+ ip4_not(ip4_mkmask(i->ifa_prefixlen))));
+ }
+ }
+
+ scope = ipa_classify(ifa.ip);
+ if (scope < 0)
+ {
+ log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
+ return;
+ }
+ ifa.scope = scope & IADDR_SCOPE_MASK;
+
+ DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
+ ifi->index, ifi->name,
+ new ? "added" : "removed",
+ ifa.ip, ifa.flags, &ifa.prefix, ifa.brd, ifa.opposite);
+
+ if (new)
+ ifa_update(&ifa);
+ else
+ ifa_delete(&ifa);
+
+ if (!scan)
+ if_end_partial_update(ifi);
+}
+
+static void
+nl_parse_addr6(struct ifaddrmsg *i, int scan, int new)
+{
+ struct rtattr *a[BIRD_IFA_MAX];
+ struct iface *ifi;
+ u32 ifa_flags;
+ int scope;
+
+ if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a)))
+ return;
+
+ if (!a[IFA_ADDRESS])
+ {
+ log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
+ return;
+ }
+
+ ifi = if_find_by_index(i->ifa_index);
+ if (!ifi)
+ {
+ log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
+ return;
+ }
+
+ if (a[IFA_FLAGS])
+ ifa_flags = rta_get_u32(a[IFA_FLAGS]);
+ else
+ ifa_flags = i->ifa_flags;
+
+ struct ifa ifa;
+ bzero(&ifa, sizeof(ifa));
+ ifa.iface = ifi;
+ if (ifa_flags & IFA_F_SECONDARY)
+ ifa.flags |= IA_SECONDARY;
+
+ /* Ignore tentative addresses silently */
+ if (ifa_flags & IFA_F_TENTATIVE)
+ return;
+
+ /* IFA_LOCAL can be unset for IPv6 interfaces */
+ ifa.ip = rta_get_ipa(a[IFA_LOCAL] ? : a[IFA_ADDRESS]);
+
+ if (i->ifa_prefixlen > IP6_MAX_PREFIX_LENGTH)
+ {
+ log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
+ new = 0;
+ }
+ if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH)
+ {
+ ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
+ net_fill_ip6(&ifa.prefix, rta_get_ip6(a[IFA_ADDRESS]), i->ifa_prefixlen);
+
+ /* It is either a host address or a peer address */
+ if (ipa_equal(ifa.ip, ifa.brd))
+ ifa.flags |= IA_HOST;
+ else
+ {
+ ifa.flags |= IA_PEER;
+ ifa.opposite = ifa.brd;
+ }
+ }
+ else
+ {
+ net_fill_ip6(&ifa.prefix, ipa_to_ip6(ifa.ip), i->ifa_prefixlen);
+ net_normalize(&ifa.prefix);
+
+ if (i->ifa_prefixlen == IP6_MAX_PREFIX_LENGTH - 1)
+ ifa.opposite = ipa_opposite_m1(ifa.ip);
+ }
+
+ scope = ipa_classify(ifa.ip);
+ if (scope < 0)
+ {
+ log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
+ return;
+ }
+ ifa.scope = scope & IADDR_SCOPE_MASK;
+
+ DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
+ ifi->index, ifi->name,
+ new ? "added" : "removed",
+ ifa.ip, ifa.flags, &ifa.prefix, ifa.brd, ifa.opposite);
+
+ if (new)
+ ifa_update(&ifa);
+ else
+ ifa_delete(&ifa);
+
+ if (!scan)
+ if_end_partial_update(ifi);
+}
+
+static void
+nl_parse_addr(struct nlmsghdr *h, int scan)
+{
+ struct ifaddrmsg *i;
+
+ if (!(i = nl_checkin(h, sizeof(*i))))
+ return;
+
+ int new = (h->nlmsg_type == RTM_NEWADDR);
+
+ switch (i->ifa_family)
+ {
+ case AF_INET:
+ return nl_parse_addr4(i, scan, new);
+
+ case AF_INET6:
+ return nl_parse_addr6(i, scan, new);
+ }
+}
+
+void
+kif_do_scan(struct kif_proto *p UNUSED)
+{
+ struct nlmsghdr *h;
+
+ if_start_update();
+
+ nl_request_dump(AF_UNSPEC, RTM_GETLINK);
+ while (h = nl_get_scan())
+ if (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)
+ nl_parse_link(h, 1);
+ else
+ log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
+
+ /* Re-resolve master interface for slaves */
+ struct iface *i;
+ WALK_LIST(i, iface_list)
+ if (i->master_index)
+ {
+ struct iface f = {
+ .flags = i->flags,
+ .mtu = i->mtu,
+ .index = i->index,
+ .master_index = i->master_index,
+ .master = if_find_by_index(i->master_index)
+ };
+
+ if (f.master != i->master)
+ {
+ memcpy(f.name, i->name, sizeof(f.name));
+ if_update(&f);
+ }
+ }
+
+ nl_request_dump(AF_INET, RTM_GETADDR);
+ while (h = nl_get_scan())
+ if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
+ nl_parse_addr(h, 1);
+ else
+ log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
+
+ nl_request_dump(AF_INET6, RTM_GETADDR);
+ while (h = nl_get_scan())
+ if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
+ nl_parse_addr(h, 1);
+ else
+ log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
+
+ if_end_update();
+}
+
+/*
+ * Routes
+ */
+
+static inline u32
+krt_table_id(struct krt_proto *p)
+{
+ return KRT_CF->sys.table_id;
+}
+
+static HASH(struct krt_proto) nl_table_map;
+
+#define RTH_KEY(p) p->af, krt_table_id(p)
+#define RTH_NEXT(p) p->sys.hash_next
+#define RTH_EQ(a1,i1,a2,i2) a1 == a2 && i1 == i2
+#define RTH_FN(a,i) a ^ u32_hash(i)
+
+#define RTH_REHASH rth_rehash
+#define RTH_PARAMS /8, *2, 2, 2, 6, 20
+
+HASH_DEFINE_REHASH_FN(RTH, struct krt_proto)
+
+int
+krt_capable(rte *e)
+{
+ rta *a = e->attrs;
+
+ switch (a->dest)
+ {
+ case RTD_UNICAST:
+ case RTD_BLACKHOLE:
+ case RTD_UNREACHABLE:
+ case RTD_PROHIBIT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static inline int
+nh_bufsize(struct nexthop *nh)
+{
+ int rv = 0;
+ for (; nh != NULL; nh = nh->next)
+ rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
+ return rv;
+}
+
+static int
+nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
+{
+ eattr *ea;
+ net *net = e->net;
+ rta *a = e->attrs;
+ ea_list *eattrs = a->eattrs;
+ int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(&(a->nh));
+ u32 priority = 0;
+
+ struct {
+ struct nlmsghdr h;
+ struct rtmsg r;
+ char buf[0];
+ } *r;
+
+ int rsize = sizeof(*r) + bufsize;
+ r = alloca(rsize);
+
+ DBG("nl_send_route(%N,op=%x)\n", net->n.addr, op);
+
+ bzero(&r->h, sizeof(r->h));
+ bzero(&r->r, sizeof(r->r));
+ r->h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;
+ r->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
+
+ r->r.rtm_family = p->af;
+ r->r.rtm_dst_len = net_pxlen(net->n.addr);
+ r->r.rtm_protocol = RTPROT_BIRD;
+ r->r.rtm_scope = RT_SCOPE_NOWHERE;
+#ifdef HAVE_MPLS_KERNEL
+ if (p->af == AF_MPLS)
+ {
+ /*
+ * Kernel MPLS code is a bit picky. We must:
+ * 1) Always set RT_SCOPE_UNIVERSE and RTN_UNICAST (even for RTM_DELROUTE)
+ * 2) Never use RTA_PRIORITY
+ */
+
+ u32 label = net_mpls(net->n.addr);
+ nl_add_attr_mpls(&r->h, rsize, RTA_DST, 1, &label);
+ r->r.rtm_scope = RT_SCOPE_UNIVERSE;
+ r->r.rtm_type = RTN_UNICAST;
+ }
+ else
+#endif
+ {
+ nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
+
+ /* Add source address for IPv6 SADR routes */
+ if (net->n.addr->type == NET_IP6_SADR)
+ {
+ net_addr_ip6_sadr *a = (void *) &net->n.addr;
+ nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix);
+ r->r.rtm_src_len = a->src_pxlen;
+ }
+ }
+
+ /*
+ * Strange behavior for RTM_DELROUTE:
+ * 1) rtm_family is ignored in IPv6, works for IPv4
+ * 2) not setting RTA_PRIORITY is different from setting default value (on IPv6)
+ * 3) not setting RTA_PRIORITY is equivalent to setting 0, which is wildcard
+ */
+
+ if (krt_table_id(p) < 256)
+ r->r.rtm_table = krt_table_id(p);
+ else
+ nl_add_attr_u32(&r->h, rsize, RTA_TABLE, krt_table_id(p));
+
+ if (p->af == AF_MPLS)
+ priority = 0;
+ else if (a->source == RTS_DUMMY)
+ priority = e->u.krt.metric;
+ else if (KRT_CF->sys.metric)
+ priority = KRT_CF->sys.metric;
+ else if ((op != NL_OP_DELETE) && (ea = ea_find(eattrs, EA_KRT_METRIC)))
+ priority = ea->u.data;
+
+ if (priority)
+ nl_add_attr_u32(&r->h, rsize, RTA_PRIORITY, priority);
+
+ /* For route delete, we do not specify remaining route attributes */
+ if (op == NL_OP_DELETE)
+ goto dest;
+
+ /* Default scope is LINK for device routes, UNIVERSE otherwise */
+ if (p->af == AF_MPLS)
+ r->r.rtm_scope = RT_SCOPE_UNIVERSE;
+ else if (ea = ea_find(eattrs, EA_KRT_SCOPE))
+ r->r.rtm_scope = ea->u.data;
+ else
+ r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
+
+ if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
+ nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
+
+ if (ea = ea_find(eattrs, EA_KRT_REALM))
+ nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data);
+
+
+ u32 metrics[KRT_METRICS_MAX];
+ metrics[0] = 0;
+
+ struct ea_walk_state ews = { .eattrs = eattrs };
+ while (ea = ea_walk(&ews, EA_KRT_METRICS, KRT_METRICS_MAX))
+ {
+ int id = ea->id - EA_KRT_METRICS;
+ metrics[0] |= 1 << id;
+ metrics[id] = ea->u.data;
+ }
+
+ if (metrics[0])
+ nl_add_metrics(&r->h, rsize, metrics, KRT_METRICS_MAX);
+
+
+dest:
+ switch (dest)
+ {
+ case RTD_UNICAST:
+ r->r.rtm_type = RTN_UNICAST;
+ if (nh->next && !krt_ecmp6(p))
+ nl_add_multipath(&r->h, rsize, nh, p->af, eattrs);
+ else
+ {
+ nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index);
+ nl_add_nexthop(&r->h, rsize, nh, p->af);
+
+ if (nh->flags & RNF_ONLINK)
+ r->r.rtm_flags |= RTNH_F_ONLINK;
+ }
+ break;
+ case RTD_BLACKHOLE:
+ r->r.rtm_type = RTN_BLACKHOLE;
+ break;
+ case RTD_UNREACHABLE:
+ r->r.rtm_type = RTN_UNREACHABLE;
+ break;
+ case RTD_PROHIBIT:
+ r->r.rtm_type = RTN_PROHIBIT;
+ break;
+ case RTD_NONE:
+ break;
+ default:
+ bug("krt_capable inconsistent with nl_send_route");
+ }
+
+ /* Ignore missing for DELETE */
+ return nl_exchange(&r->h, (op == NL_OP_DELETE));
+}
+
+static inline int
+nl_add_rte(struct krt_proto *p, rte *e)
+{
+ rta *a = e->attrs;
+ int err = 0;
+
+ if (krt_ecmp6(p) && a->nh.next)
+ {
+ struct nexthop *nh = &(a->nh);
+
+ err = nl_send_route(p, e, NL_OP_ADD, RTD_UNICAST, nh);
+ if (err < 0)
+ return err;
+
+ for (nh = nh->next; nh; nh = nh->next)
+ err += nl_send_route(p, e, NL_OP_APPEND, RTD_UNICAST, nh);
+
+ return err;
+ }
+
+ return nl_send_route(p, e, NL_OP_ADD, a->dest, &(a->nh));
+}
+
+static inline int
+nl_delete_rte(struct krt_proto *p, rte *e)
+{
+ int err = 0;
+
+ /* For IPv6, we just repeatedly request DELETE until we get error */
+ do
+ err = nl_send_route(p, e, NL_OP_DELETE, RTD_NONE, NULL);
+ while (krt_ecmp6(p) && !err);
+
+ return err;
+}
+
+static inline int
+nl_replace_rte(struct krt_proto *p, rte *e)
+{
+ rta *a = e->attrs;
+ return nl_send_route(p, e, NL_OP_REPLACE, a->dest, &(a->nh));
+}
+
+
+void
+krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
+{
+ int err = 0;
+
+ /*
+ * We use NL_OP_REPLACE for IPv4, it has an issue with not checking for
+ * matching rtm_protocol, but that is OK when dedicated priority is used.
+ *
+ * We do not use NL_OP_REPLACE for IPv6, as it has broken semantics for ECMP
+ * and with some kernel versions ECMP replace crashes kernel. Would need more
+ * testing and checks for kernel versions.
+ *
+ * For IPv6, we use NL_OP_DELETE and then NL_OP_ADD. We also do not trust the
+ * old route value, so we do not try to optimize IPv6 ECMP reconfigurations.
+ */
+
+ if (krt_ipv4(p) && old && new)
+ {
+ err = nl_replace_rte(p, new);
+ }
+ else
+ {
+ if (old)
+ nl_delete_rte(p, old);
+
+ if (new)
+ err = nl_add_rte(p, new);
+ }
+
+ if (new)
+ {
+ if (err < 0)
+ bmap_clear(&p->sync_map, new->id);
+ else
+ bmap_set(&p->sync_map, new->id);
+ }
+}
+
+static int
+nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint priority, uint krt_type, uint rtm_family)
+{
+ /* Route merging is used for IPv6 scans */
+ if (!s->scan || (rtm_family != AF_INET6))
+ return 0;
+
+ /* Saved and new route must have same network, proto/table, and priority */
+ if ((s->net != net) || (s->proto != p) || (s->krt_metric != priority))
+ return 0;
+
+ /* Both must be regular unicast routes */
+ if ((s->krt_type != RTN_UNICAST) || (krt_type != RTN_UNICAST))
+ return 0;
+
+ return 1;
+}
+
+static void
+nl_announce_route(struct nl_parse_state *s)
+{
+ rte *e = rte_get_temp(s->attrs);
+ e->net = s->net;
+ e->u.krt.src = s->krt_src;
+ e->u.krt.proto = s->krt_proto;
+ e->u.krt.seen = 0;
+ e->u.krt.best = 0;
+ e->u.krt.metric = s->krt_metric;
+
+ if (s->scan)
+ krt_got_route(s->proto, e);
+ else
+ krt_got_route_async(s->proto, e, s->new);
+
+ s->net = NULL;
+ s->attrs = NULL;
+ s->proto = NULL;
+ lp_flush(s->pool);
+}
+
+static inline void
+nl_parse_begin(struct nl_parse_state *s, int scan)
+{
+ memset(s, 0, sizeof (struct nl_parse_state));
+ s->pool = nl_linpool;
+ s->scan = scan;
+}
+
+static inline void
+nl_parse_end(struct nl_parse_state *s)
+{
+ if (s->net)
+ nl_announce_route(s);
+}
+
+
+#define SKIP0(ARG, ...) do { DBG("KRT: Ignoring route - " ARG, ##__VA_ARGS__); return; } while(0)
+#define SKIP(ARG, ...) do { DBG("KRT: Ignoring route %N - " ARG, &dst, ##__VA_ARGS__); return; } while(0)
+
+static void
+nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
+{
+ struct krt_proto *p;
+ struct rtmsg *i;
+ struct rtattr *a[BIRD_RTA_MAX];
+ int new = h->nlmsg_type == RTM_NEWROUTE;
+
+ net_addr dst, src = {};
+ u32 oif = ~0;
+ u32 table_id;
+ u32 priority = 0;
+ u32 def_scope = RT_SCOPE_UNIVERSE;
+ int krt_src;
+
+ if (!(i = nl_checkin(h, sizeof(*i))))
+ return;
+
+ switch (i->rtm_family)
+ {
+ case AF_INET:
+ if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want4, a, sizeof(a)))
+ return;
+
+ if (a[RTA_DST])
+ net_fill_ip4(&dst, rta_get_ip4(a[RTA_DST]), i->rtm_dst_len);
+ else
+ net_fill_ip4(&dst, IP4_NONE, 0);
+ break;
+
+ case AF_INET6:
+ if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
+ return;
+
+ if (a[RTA_DST])
+ net_fill_ip6(&dst, rta_get_ip6(a[RTA_DST]), i->rtm_dst_len);
+ else
+ net_fill_ip6(&dst, IP6_NONE, 0);
+
+ if (a[RTA_SRC])
+ net_fill_ip6(&src, rta_get_ip6(a[RTA_SRC]), i->rtm_src_len);
+ else
+ net_fill_ip6(&src, IP6_NONE, 0);
+ break;
+
+#ifdef HAVE_MPLS_KERNEL
+ case AF_MPLS:
+ if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want_mpls, a, sizeof(a)))
+ return;
+
+ if (!a[RTA_DST])
+ SKIP0("MPLS route without RTA_DST\n");
+
+ if (rta_get_mpls(a[RTA_DST], rta_mpls_stack) != 1)
+ SKIP0("MPLS route with multi-label RTA_DST\n");
+
+ net_fill_mpls(&dst, rta_mpls_stack[0]);
+ break;
+#endif
+
+ default:
+ return;
+ }
+
+ if (a[RTA_OIF])
+ oif = rta_get_u32(a[RTA_OIF]);
+
+ if (a[RTA_TABLE])
+ table_id = rta_get_u32(a[RTA_TABLE]);
+ else
+ table_id = i->rtm_table;
+
+ if (i->rtm_flags & RTM_F_CLONED)
+ SKIP("cloned\n");
+
+ /* Do we know this table? */
+ p = HASH_FIND(nl_table_map, RTH, i->rtm_family, table_id);
+ if (!p)
+ SKIP("unknown table %u\n", table_id);
+
+ if (a[RTA_SRC] && (p->p.net_type != NET_IP6_SADR))
+ SKIP("src prefix for non-SADR channel\n");
+
+ if (a[RTA_IIF])
+ SKIP("IIF set\n");
+
+ if (i->rtm_tos != 0) /* We don't support TOS */
+ SKIP("TOS %02x\n", i->rtm_tos);
+
+ if (s->scan && !new)
+ SKIP("RTM_DELROUTE in scan\n");
+
+ if (a[RTA_PRIORITY])
+ priority = rta_get_u32(a[RTA_PRIORITY]);
+
+ int c = net_classify(&dst);
+ if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
+ SKIP("strange class/scope\n");
+
+ switch (i->rtm_protocol)
+ {
+ case RTPROT_UNSPEC:
+ SKIP("proto unspec\n");
+
+ case RTPROT_REDIRECT:
+ krt_src = KRT_SRC_REDIRECT;
+ break;
+
+ case RTPROT_KERNEL:
+ krt_src = KRT_SRC_KERNEL;
+ return;
+
+ case RTPROT_BIRD:
+ if (!s->scan)
+ SKIP("echo\n");
+ krt_src = KRT_SRC_BIRD;
+ break;
+
+ case RTPROT_BOOT:
+ default:
+ krt_src = KRT_SRC_ALIEN;
+ }
+
+ net_addr *n = &dst;
+ if (p->p.net_type == NET_IP6_SADR)
+ {
+ n = alloca(sizeof(net_addr_ip6_sadr));
+ net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst),
+ net6_prefix(&src), net6_pxlen(&src));
+ }
+
+ net *net = net_get(p->p.main_channel->table, n);
+
+ if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type, i->rtm_family))
+ nl_announce_route(s);
+
+ rta *ra = lp_allocz(s->pool, RTA_MAX_SIZE);
+ ra->src = p->p.main_source;
+ ra->source = RTS_INHERIT;
+ ra->scope = SCOPE_UNIVERSE;
+
+ if (a[RTA_FLOW])
+ s->rta_flow = rta_get_u32(a[RTA_FLOW]);
+ else
+ s->rta_flow = 0;
+
+ switch (i->rtm_type)
+ {
+ case RTN_UNICAST:
+ ra->dest = RTD_UNICAST;
+
+ if (a[RTA_MULTIPATH])
+ {
+ struct nexthop *nh = nl_parse_multipath(s, p, n, a[RTA_MULTIPATH], i->rtm_family, krt_src);
+ if (!nh)
+ SKIP("strange RTA_MULTIPATH\n");
+
+ nexthop_link(ra, nh);
+ break;
+ }
+
+ if ((i->rtm_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD))
+ SKIP("ignore RTNH_F_DEAD\n");
+
+ ra->nh.iface = if_find_by_index(oif);
+ if (!ra->nh.iface)
+ {
+ log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif);
+ return;
+ }
+
+ if (a[RTA_GATEWAY])
+ ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
+
+#ifdef HAVE_MPLS_KERNEL
+ if (a[RTA_VIA])
+ ra->nh.gw = rta_get_via(a[RTA_VIA]);
+#endif
+
+ if (ipa_nonzero(ra->nh.gw))
+ {
+ /* Silently skip strange 6to4 routes */
+ const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96);
+ if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit))
+ return;
+
+ if (i->rtm_flags & RTNH_F_ONLINK)
+ ra->nh.flags |= RNF_ONLINK;
+
+ neighbor *nbr;
+ nbr = neigh_find(&p->p, ra->nh.gw, ra->nh.iface,
+ (ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
+ if (!nbr || (nbr->scope == SCOPE_HOST))
+ {
+ log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr,
+ ra->nh.gw);
+ return;
+ }
+ }
+
+ break;
+ case RTN_BLACKHOLE:
+ ra->dest = RTD_BLACKHOLE;
+ break;
+ case RTN_UNREACHABLE:
+ ra->dest = RTD_UNREACHABLE;
+ break;
+ case RTN_PROHIBIT:
+ ra->dest = RTD_PROHIBIT;
+ break;
+ /* FIXME: What about RTN_THROW? */
+ default:
+ SKIP("type %d\n", i->rtm_type);
+ return;
+ }
+
+#ifdef HAVE_MPLS_KERNEL
+ if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !ra->nh.next)
+ ra->nh.labels = rta_get_mpls(a[RTA_NEWDST], ra->nh.label);
+
+ if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !ra->nh.next)
+ {
+ switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
+ {
+ case LWTUNNEL_ENCAP_MPLS:
+ {
+ struct rtattr *enca[BIRD_RTA_MAX];
+ nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
+ nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
+ ra->nh.labels = rta_get_mpls(enca[RTA_DST], ra->nh.label);
+ break;
+ }
+ default:
+ SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
+ break;
+ }
+ }
+#endif
+
+ if (i->rtm_scope != def_scope)
+ {
+ ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
+ ea->next = ra->eattrs;
+ ra->eattrs = ea;
+ ea->flags = EALF_SORTED;
+ ea->count = 1;
+ ea->attrs[0].id = EA_KRT_SCOPE;
+ ea->attrs[0].flags = 0;
+ ea->attrs[0].type = EAF_TYPE_INT;
+ ea->attrs[0].u.data = i->rtm_scope;
+ }
+
+ if (a[RTA_PREFSRC])
+ {
+ ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
+
+ ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
+ ea->next = ra->eattrs;
+ ra->eattrs = ea;
+ ea->flags = EALF_SORTED;
+ ea->count = 1;
+ ea->attrs[0].id = EA_KRT_PREFSRC;
+ ea->attrs[0].flags = 0;
+ ea->attrs[0].type = EAF_TYPE_IP_ADDRESS;
+
+ struct adata *ad = lp_alloc(s->pool, sizeof(struct adata) + sizeof(ps));
+ ad->length = sizeof(ps);
+ memcpy(ad->data, &ps, sizeof(ps));
+
+ ea->attrs[0].u.ptr = ad;
+ }
+
+ /* Can be set per-route or per-nexthop */
+ if (s->rta_flow)
+ {
+ ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
+ ea->next = ra->eattrs;
+ ra->eattrs = ea;
+ ea->flags = EALF_SORTED;
+ ea->count = 1;
+ ea->attrs[0].id = EA_KRT_REALM;
+ ea->attrs[0].flags = 0;
+ ea->attrs[0].type = EAF_TYPE_INT;
+ ea->attrs[0].u.data = s->rta_flow;
+ }
+
+ if (a[RTA_METRICS])
+ {
+ u32 metrics[KRT_METRICS_MAX];
+ ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + KRT_METRICS_MAX * sizeof(eattr));
+ int t, n = 0;
+
+ if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
+ {
+ log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
+ return;
+ }
+
+ for (t = 1; t < KRT_METRICS_MAX; t++)
+ if (metrics[0] & (1 << t))
+ {
+ ea->attrs[n].id = EA_CODE(PROTOCOL_KERNEL, KRT_METRICS_OFFSET + t);
+ ea->attrs[n].flags = 0;
+ ea->attrs[n].type = EAF_TYPE_INT; /* FIXME: Some are EAF_TYPE_BITFIELD */
+ ea->attrs[n].u.data = metrics[t];
+ n++;
+ }
+
+ if (n > 0)
+ {
+ ea->next = ra->eattrs;
+ ea->flags = EALF_SORTED;
+ ea->count = n;
+ ra->eattrs = ea;
+ }
+ }
+
+ /*
+ * Ideally, now we would send the received route to the rest of kernel code.
+ * But IPv6 ECMP routes before 4.11 are sent as a sequence of routes, so we
+ * postpone it and merge next hops until the end of the sequence. Note that
+ * when doing merging of next hops, we expect the new route to be unipath.
+ * Otherwise, we ignore additional next hops in nexthop_insert().
+ */
+
+ if (!s->net)
+ {
+ /* Store the new route */
+ s->net = net;
+ s->attrs = ra;
+ s->proto = p;
+ s->new = new;
+ s->krt_src = krt_src;
+ s->krt_type = i->rtm_type;
+ s->krt_proto = i->rtm_protocol;
+ s->krt_metric = priority;
+ }
+ else
+ {
+ /* Merge next hops with the stored route */
+ rta *oa = s->attrs;
+
+ struct nexthop *nhs = &oa->nh;
+ nexthop_insert(&nhs, &ra->nh);
+
+ /* Perhaps new nexthop is inserted at the first position */
+ if (nhs == &ra->nh)
+ {
+ /* Swap rtas */
+ s->attrs = ra;
+
+ /* Keep old eattrs */
+ ra->eattrs = oa->eattrs;
+ }
+ }
+}
+
+void
+krt_do_scan(struct krt_proto *p UNUSED) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
+{
+ struct nlmsghdr *h;
+ struct nl_parse_state s;
+
+ nl_parse_begin(&s, 1);
+ nl_request_dump(AF_UNSPEC, RTM_GETROUTE);
+ while (h = nl_get_scan())
+ if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)
+ nl_parse_route(&s, h);
+ else
+ log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);
+ nl_parse_end(&s);
+}
+
+/*
+ * Asynchronous Netlink interface
+ */
+
+static sock *nl_async_sk; /* BIRD socket for asynchronous notifications */
+static byte *nl_async_rx_buffer; /* Receive buffer */
+
+static void
+nl_async_msg(struct nlmsghdr *h)
+{
+ struct nl_parse_state s;
+
+ switch (h->nlmsg_type)
+ {
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);
+ nl_parse_begin(&s, 0);
+ nl_parse_route(&s, h);
+ nl_parse_end(&s);
+ break;
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);
+ if (kif_proto)
+ nl_parse_link(h, 0);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);
+ if (kif_proto)
+ nl_parse_addr(h, 0);
+ break;
+ default:
+ DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);
+ }
+}
+
+static int
+nl_async_hook(sock *sk, uint size UNUSED)
+{
+ struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
+ struct sockaddr_nl sa;
+ struct msghdr m = {
+ .msg_name = &sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+ struct nlmsghdr *h;
+ int x;
+ uint len;
+
+ x = recvmsg(sk->fd, &m, 0);
+ if (x < 0)
+ {
+ if (errno == ENOBUFS)
+ {
+ /*
+ * Netlink reports some packets have been thrown away.
+ * One day we might react to it by asking for route table
+ * scan in near future.
+ */
+ log(L_WARN "Kernel dropped some netlink messages, will resync on next scan.");
+ return 1; /* More data are likely to be ready */
+ }
+ else if (errno != EWOULDBLOCK)
+ log(L_ERR "Netlink recvmsg: %m");
+ return 0;
+ }
+ if (sa.nl_pid) /* It isn't from the kernel */
+ {
+ DBG("Non-kernel packet\n");
+ return 1;
+ }
+ h = (void *) nl_async_rx_buffer;
+ len = x;
+ if (m.msg_flags & MSG_TRUNC)
+ {
+ log(L_WARN "Netlink got truncated asynchronous message");
+ return 1;
+ }
+ while (NLMSG_OK(h, len))
+ {
+ nl_async_msg(h);
+ h = NLMSG_NEXT(h, len);
+ }
+ if (len)
+ log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);
+ return 1;
+}
+
+static void
+nl_async_err_hook(sock *sk, int e UNUSED)
+{
+ nl_async_hook(sk, 0);
+}
+
+static void
+nl_open_async(void)
+{
+ sock *sk;
+ struct sockaddr_nl sa;
+ int fd;
+
+ if (nl_async_sk)
+ return;
+
+ DBG("KRT: Opening async netlink socket\n");
+
+ fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (fd < 0)
+ {
+ log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");
+ return;
+ }
+
+ bzero(&sa, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+ sa.nl_groups = RTMGRP_LINK |
+ RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
+ RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
+
+ if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ {
+ log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");
+ close(fd);
+ return;
+ }
+
+ nl_async_rx_buffer = xmalloc(NL_RX_SIZE);
+
+ sk = nl_async_sk = sk_new(krt_pool);
+ sk->type = SK_MAGIC;
+ sk->rx_hook = nl_async_hook;
+ sk->err_hook = nl_async_err_hook;
+ sk->fd = fd;
+ if (sk_open(sk) < 0)
+ bug("Netlink: sk_open failed");
+}
+
+
+/*
+ * Interface to the UNIX krt module
+ */
+
+void
+krt_sys_io_init(void)
+{
+ nl_linpool = lp_new_default(krt_pool);
+ HASH_INIT(nl_table_map, krt_pool, 6);
+}
+
+int
+krt_sys_start(struct krt_proto *p)
+{
+ struct krt_proto *old = HASH_FIND(nl_table_map, RTH, p->af, krt_table_id(p));
+
+ if (old)
+ {
+ log(L_ERR "%s: Kernel table %u already registered by %s",
+ p->p.name, krt_table_id(p), old->p.name);
+ return 0;
+ }
+
+ HASH_INSERT2(nl_table_map, RTH, krt_pool, p);
+
+ nl_open();
+ nl_open_async();
+
+ return 1;
+}
+
+void
+krt_sys_shutdown(struct krt_proto *p)
+{
+ HASH_REMOVE2(nl_table_map, RTH, krt_pool, p);
+}
+
+int
+krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o)
+{
+ return (n->sys.table_id == o->sys.table_id) && (n->sys.metric == o->sys.metric);
+}
+
+void
+krt_sys_init_config(struct krt_config *cf)
+{
+ cf->sys.table_id = RT_TABLE_MAIN;
+ cf->sys.metric = 32;
+}
+
+void
+krt_sys_copy_config(struct krt_config *d, struct krt_config *s)
+{
+ d->sys.table_id = s->sys.table_id;
+ d->sys.metric = s->sys.metric;
+}
+
+static const char *krt_metrics_names[KRT_METRICS_MAX] = {
+ NULL, "lock", "mtu", "window", "rtt", "rttvar", "sstresh", "cwnd", "advmss",
+ "reordering", "hoplimit", "initcwnd", "features", "rto_min", "initrwnd", "quickack"
+};
+
+static const char *krt_features_names[KRT_FEATURES_MAX] = {
+ "ecn", NULL, NULL, "allfrag"
+};
+
+int
+krt_sys_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
+{
+ switch (a->id)
+ {
+ case EA_KRT_PREFSRC:
+ bsprintf(buf, "prefsrc");
+ return GA_NAME;
+
+ case EA_KRT_REALM:
+ bsprintf(buf, "realm");
+ return GA_NAME;
+
+ case EA_KRT_SCOPE:
+ bsprintf(buf, "scope");
+ return GA_NAME;
+
+ case EA_KRT_LOCK:
+ buf += bsprintf(buf, "lock:");
+ ea_format_bitfield(a, buf, buflen, krt_metrics_names, 2, KRT_METRICS_MAX);
+ return GA_FULL;
+
+ case EA_KRT_FEATURES:
+ buf += bsprintf(buf, "features:");
+ ea_format_bitfield(a, buf, buflen, krt_features_names, 0, KRT_FEATURES_MAX);
+ return GA_FULL;
+
+ default:;
+ int id = (int)EA_ID(a->id) - KRT_METRICS_OFFSET;
+ if (id > 0 && id < KRT_METRICS_MAX)
+ {
+ bsprintf(buf, "%s", krt_metrics_names[id]);
+ return GA_NAME;
+ }
+
+ return GA_UNKNOWN;
+ }
+}
+
+
+
+void
+kif_sys_start(struct kif_proto *p UNUSED)
+{
+ nl_open();
+ nl_open_async();
+}
+
+void
+kif_sys_shutdown(struct kif_proto *p UNUSED)
+{
+}
+
+int
+kif_update_sysdep_addr(struct iface *i UNUSED)
+{
+ return 0;
+}
diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h
index e21ff487..f13eda7c 100644
--- a/sysdep/linux/sysio.h
+++ b/sysdep/linux/sysio.h
@@ -10,6 +10,10 @@
#define IPV6_MINHOPCOUNT 73
#endif
+#ifndef IPV6_FREEBIND
+#define IPV6_FREEBIND 78
+#endif
+
#ifndef TCP_MD5SIG_EXT
#define TCP_MD5SIG_EXT 32
#endif
@@ -266,3 +270,18 @@ sk_set_priority(sock *s, int prio)
return 0;
}
+static inline int
+sk_set_freebind(sock *s)
+{
+ int y = 1;
+
+ if (sk_is_ipv4(s))
+ if (setsockopt(s->fd, SOL_IP, IP_FREEBIND, &y, sizeof(y)) < 0)
+ ERR("IP_FREEBIND");
+
+ if (sk_is_ipv6(s))
+ if (setsockopt(s->fd, SOL_IPV6, IPV6_FREEBIND, &y, sizeof(y)) < 0)
+ ERR("IPV6_FREEBIND");
+
+ return 0;
+}
diff --git a/sysdep/unix/Makefile b/sysdep/unix/Makefile
index f592399c..d0d36b5f 100644
--- a/sysdep/unix/Makefile
+++ b/sysdep/unix/Makefile
@@ -1,4 +1,4 @@
-src := io.c krt.c log.c main.c random.c
+src := alloc.c io.c krt.c log.c main.c random.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
diff --git a/sysdep/unix/alloc.c b/sysdep/unix/alloc.c
new file mode 100644
index 00000000..0e944d57
--- /dev/null
+++ b/sysdep/unix/alloc.c
@@ -0,0 +1,130 @@
+/*
+ * BIRD Internet Routing Daemon -- Raw allocation
+ *
+ * (c) 2020 Maria Matejka <mq@ucw.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "nest/bird.h"
+#include "lib/resource.h"
+#include "lib/lists.h"
+#include "lib/event.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+#ifdef HAVE_MMAP
+#define KEEP_PAGES 512
+
+static u64 page_size = 0;
+static _Bool use_fake = 0;
+
+uint pages_kept = 0;
+static list pages_list;
+
+static void cleanup_pages(void *data);
+static event page_cleanup_event = { .hook = cleanup_pages };
+
+#else
+static const u64 page_size = 4096; /* Fake page size */
+#endif
+
+u64 get_page_size(void)
+{
+ if (page_size)
+ return page_size;
+
+#ifdef HAVE_MMAP
+ if (page_size = sysconf(_SC_PAGESIZE))
+ {
+ if ((u64_popcount(page_size) > 1) || (page_size > 16384))
+ {
+ /* Too big or strange page, use the aligned allocator instead */
+ page_size = 4096;
+ use_fake = 1;
+ }
+ return page_size;
+ }
+
+ bug("Page size must be non-zero");
+#endif
+}
+
+void *
+alloc_page(void)
+{
+#ifdef HAVE_MMAP
+ if (pages_kept)
+ {
+ node *page = TAIL(pages_list);
+ rem_node(page);
+ pages_kept--;
+ memset(page, 0, get_page_size());
+ return page;
+ }
+
+ if (!use_fake)
+ {
+ void *ret = mmap(NULL, get_page_size(), PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (ret == MAP_FAILED)
+ bug("mmap(%lu) failed: %m", (long unsigned int) page_size);
+ return ret;
+ }
+ else
+#endif
+ {
+ void *ptr = NULL;
+ int err = posix_memalign(&ptr, page_size, page_size);
+ if (err || !ptr)
+ bug("posix_memalign(%lu) failed", (long unsigned int) page_size);
+ return ptr;
+ }
+}
+
+void
+free_page(void *ptr)
+{
+#ifdef HAVE_MMAP
+ if (!use_fake)
+ {
+ if (!pages_kept)
+ init_list(&pages_list);
+
+ memset(ptr, 0, sizeof(node));
+ add_tail(&pages_list, ptr);
+
+ if (++pages_kept > KEEP_PAGES)
+ ev_schedule(&page_cleanup_event);
+ }
+ else
+#endif
+ free(ptr);
+}
+
+#ifdef HAVE_MMAP
+static void
+cleanup_pages(void *data UNUSED)
+{
+ for (uint seen = 0; (pages_kept > KEEP_PAGES) && (seen < KEEP_PAGES); seen++)
+ {
+ void *ptr = HEAD(pages_list);
+ rem_node(ptr);
+ if (munmap(ptr, get_page_size()) == 0)
+ pages_kept--;
+#ifdef ENOMEM
+ else if (errno == ENOMEM)
+ add_tail(&pages_list, ptr);
+#endif
+ else
+ bug("munmap(%p) failed: %m", ptr);
+ }
+
+ if (pages_kept > KEEP_PAGES)
+ ev_schedule(&page_cleanup_event);
+}
+#endif
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 3d67d0a7..4fd77453 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -1436,6 +1436,10 @@ sk_open(sock *s)
if (sk_set_high_port(s) < 0)
log(L_WARN "Socket error: %s%#m", s->err);
+ if (s->flags & SKF_FREEBIND)
+ if (sk_set_freebind(s) < 0)
+ log(L_WARN "Socket error: %s%#m", s->err);
+
sockaddr_fill(&sa, s->af, bind_addr, s->iface, bind_port);
if (bind(fd, &sa.sa, SA_LEN(sa)) < 0)
ERR2("bind");
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index c00c660d..7c2614b1 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -317,7 +317,7 @@ static void
krt_learn_scan(struct krt_proto *p, rte *e)
{
net *n0 = e->net;
- net *n = net_get(&p->krt_table, n0->n.addr);
+ net *n = net_get(p->krt_table, n0->n.addr);
rte *m, **mm;
e->attrs = rta_lookup(e->attrs);
@@ -354,7 +354,7 @@ krt_learn_scan(struct krt_proto *p, rte *e)
static void
krt_learn_prune(struct krt_proto *p)
{
- struct fib *fib = &p->krt_table.fib;
+ struct fib *fib = &p->krt_table->fib;
struct fib_iterator fit;
KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
@@ -430,7 +430,7 @@ static void
krt_learn_async(struct krt_proto *p, rte *e, int new)
{
net *n0 = e->net;
- net *n = net_get(&p->krt_table, n0->n.addr);
+ net *n = net_get(p->krt_table, n0->n.addr);
rte *g, **gg, *best, **bestp, *old_best;
e->attrs = rta_lookup(e->attrs);
@@ -511,8 +511,9 @@ krt_learn_init(struct krt_proto *p)
struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config));
cf->name = "Inherited";
cf->addr_type = p->p.net_type;
+ cf->internal = 1;
- rt_setup(p->p.pool, &p->krt_table, cf);
+ p->krt_table = rt_setup(p->p.pool, cf);
}
}
@@ -524,7 +525,7 @@ krt_dump(struct proto *P)
if (!KRT_CF->learn)
return;
debug("KRT: Table of inheritable routes\n");
- rt_dump(&p->krt_table);
+ rt_dump(p->krt_table);
}
static void
@@ -1012,7 +1013,7 @@ krt_postconfig(struct proto_config *CF)
if (cf->c.class == SYM_TEMPLATE)
return;
- if (EMPTY_LIST(CF->channels))
+ if (! proto_cf_main_channel(CF))
cf_error("Channel not specified");
#ifdef CONFIG_ALL_TABLES_AT_ONCE
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index 4a5d10d2..62228f08 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -49,7 +49,7 @@ struct krt_proto {
struct krt_state sys; /* Sysdep state */
#ifdef KRT_ALLOW_LEARN
- struct rtable krt_table; /* Internal table of inherited routes */
+ struct rtable *krt_table; /* Internal table of inherited routes */
#endif
#ifndef CONFIG_ALL_TABLES_AT_ONCE
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 67e76655..392aff9d 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -125,11 +125,11 @@ add_num_const(char *name, int val, const char *file, const uint line)
/* the code of read_iproute_table() is based on
rtnl_tab_initialize() from iproute2 package */
static void
-read_iproute_table(char *file, char *prefix, int max)
+read_iproute_table(char *file, char *prefix, uint max)
{
char buf[512], namebuf[512];
char *name;
- int val;
+ uint val;
FILE *fp;
strcpy(namebuf, prefix);
@@ -151,11 +151,11 @@ read_iproute_table(char *file, char *prefix, int max)
if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
sscanf(p, "0x%x %s #", &val, name) != 2 &&
- sscanf(p, "%d %s\n", &val, name) != 2 &&
- sscanf(p, "%d %s #", &val, name) != 2)
+ sscanf(p, "%u %s\n", &val, name) != 2 &&
+ sscanf(p, "%u %s #", &val, name) != 2)
continue;
- if (val < 0 || val > max)
+ if (val > max)
continue;
for(p = name; *p; p++)
@@ -191,10 +191,10 @@ sysdep_preconfig(struct config *c)
c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING;
#ifdef PATH_IPROUTE_DIR
- read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
- read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
- read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
- read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 255);
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 0xffffffff);
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 255);
+ read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 0xffffffff);
#endif
}
@@ -867,6 +867,7 @@ main(int argc, char **argv)
parse_args(argc, argv);
log_switch(1, NULL, NULL);
+ random_init();
net_init();
resource_init();
timer_init();
diff --git a/sysdep/unix/random.c b/sysdep/unix/random.c
index b1f5086f..4e64e56b 100644
--- a/sysdep/unix/random.c
+++ b/sysdep/unix/random.c
@@ -7,9 +7,20 @@
*/
#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include "sysdep/config.h"
#include "nest/bird.h"
+#ifdef HAVE_GETRANDOM
+#include <sys/random.h>
+#endif
+
+
u32
random_u32(void)
{
@@ -19,3 +30,66 @@ random_u32(void)
rand_high = random();
return (rand_low & 0xffff) | ((rand_high & 0xffff) << 16);
}
+
+
+/* If there is no getrandom() / getentropy(), use /dev/urandom */
+#if !defined(HAVE_GETRANDOM) && !defined(HAVE_GETENTROPY)
+
+#define HAVE_URANDOM_FD 1
+static int urandom_fd = -1;
+
+int
+read_urandom_fd(void *buf, uint count)
+{
+ if (urandom_fd < 0)
+ {
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (urandom_fd < 0)
+ die("Cannot open /dev/urandom: %m");
+ }
+
+ return read(urandom_fd, buf, count);
+}
+#endif
+
+
+void
+random_init(void)
+{
+ uint seed;
+
+ /* Get random bytes to trip any errors early and to seed random() */
+ random_bytes(&seed, sizeof(seed));
+
+ srandom(seed);
+}
+
+void
+random_bytes(void *buf, size_t count)
+{
+ ASSERT(count <= 256);
+
+ while (count > 0)
+ {
+ int n = -1;
+
+#if defined(HAVE_GETRANDOM)
+ n = getrandom(buf, count, 0);
+#elif defined(HAVE_GETENTROPY)
+ n = getentropy(buf, count);
+ n = !n ? (int) count : n;
+#elif defined(HAVE_URANDOM_FD)
+ n = read_urandom_fd(buf, count);
+#endif
+
+ if (n < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ die("Cannot get random bytes: %m");
+ }
+
+ buf += n;
+ count -= n;
+ }
+}
diff --git a/test/birdtest.c b/test/birdtest.c
index a1da078f..6ad743ce 100644
--- a/test/birdtest.c
+++ b/test/birdtest.c
@@ -309,6 +309,12 @@ bt_log_suite_case_result(int result, const char *fmt, ...)
}
}
+void
+bt_reset_suite_case_timer(void)
+{
+ clock_gettime(CLOCK_MONOTONIC, &bt_suite_case_begin);
+}
+
int
bt_test_suite_base(int (*fn)(const void *), const char *id, const void *fn_arg, int forked, int timeout, const char *dsc, ...)
{
@@ -501,6 +507,15 @@ bt_fmt_ipa(char *buf, size_t size, const void *data)
bsnprintf(buf, size, "(null)");
}
+void
+bt_format_net(char *buf, size_t size, const void *data)
+{
+ if (data)
+ bsnprintf(buf, size, "%N", (const net_addr *) data);
+ else
+ bsnprintf(buf, size, "(null)");
+}
+
int
bt_is_char(byte c)
{
diff --git a/test/birdtest.h b/test/birdtest.h
index caec529b..ad5f8f9c 100644
--- a/test/birdtest.h
+++ b/test/birdtest.h
@@ -32,6 +32,7 @@ extern const char *bt_test_id;
void bt_init(int argc, char *argv[]);
int bt_exit_value(void);
+void bt_reset_suite_case_timer(void);
int bt_test_suite_base(int (*test_fn)(const void *), const char *test_id, const void *test_fn_argument, int forked, int timeout, const char *dsc, ...);
static inline u64 bt_random(void)
{ return ((u64) random() & 0xffffffff) | ((u64) random() << 32); }
@@ -165,6 +166,8 @@ struct bt_batch {
void bt_fmt_str(char *buf, size_t size, const void *data);
void bt_fmt_unsigned(char *buf, size_t size, const void *data);
void bt_fmt_ipa(char *buf, size_t size, const void *data);
+void bt_format_net(char *buf, size_t size, const void *data);
+
int bt_assert_batch__(struct bt_batch *opts);
int bt_is_char(byte c);
diff --git a/tools/gendist b/tools/gendist
index 2d915a9f..2dc42ba9 100755
--- a/tools/gendist
+++ b/tools/gendist
@@ -2,6 +2,7 @@
#
# Generate BIRD Distribution Archive
# (c) 2000--2004 Martin Mares <mj@ucw.cz>
+# (c) 2005--2022 Ondrej Filip <feela@network.cz>
#
VERSION=`grep 'BIRD_VERSION \"' sysdep/config.h | sed '/BIRD_VERSION/!d;s/^.*"\(.*\)"$/\1/'`
@@ -33,8 +34,6 @@ rm -rf `find $T/$REL -name CVS -o -name tmp` $T/$REL/{misc,rfc,doc/slides,doc/sl
rm -rf $T/$REL $T/$DREL
echo -n "OK? "
read OK
-#echo Uploading to Atrey...
-#scp $T/$REL.tar.gz $T/$DREL.tar.gz atrey.karlin.mff.cuni.cz:~ftp/pub/bird/
echo Uploading to Trubka...
scp $T/$REL.tar.gz $T/$DREL.tar.gz bird.network.cz:~ftp/pub/bird/
echo Done.
diff --git a/tools/linuxdoc b/tools/linuxdoc
new file mode 100755
index 00000000..58f5cbc4
--- /dev/null
+++ b/tools/linuxdoc
@@ -0,0 +1,80 @@
+#!/usr/bin/perl
+#
+# linuxdoc.in
+#
+# LinuxDoc-Tools driver. Calls all other LinuxDoc-Tools components,
+# contains configuration information, etcetera.
+# -------------------------------------------------------------------
+
+package main;
+
+sub BEGIN {
+ require 5.004;
+}
+
+use strict;
+
+use vars qw($prefix
+ $isoentities_prefix
+ $DataDir
+ $AuxBinDir
+ $progs);
+
+use FindBin;
+
+$prefix = "/usr";
+$isoentities_prefix = "/usr";
+$DataDir = "$FindBin::Bin/../doc/sbase";
+if (-d "/usr/lib/linuxdoc-tools")
+{
+ $AuxBinDir = "/usr/lib/linuxdoc-tools";
+} else
+{
+ $AuxBinDir = "/usr/bin";
+}
+use lib "$FindBin::Bin/linuxdoc-tools";
+
+# ---------------------------------------------------------------------
+sub ldt_which {
+# ---------------------------------------------------------------------
+# ---------------------------------------------------------------------
+ die "ldt_which: No filename(s) array given. Aborting ...\n" unless scalar @_;
+
+ foreach my $file ( @_ ){
+ if ( $file =~ m/\// ) {
+ return $file if -x $file;
+ } else {
+ foreach my $path ( split(':',$ENV{'PATH'}) ){
+ $path =~ s/\/+$//;
+ return $file if -x "$path/$file";
+ }
+ }
+ }
+ die "No executable found in path for (", join(' ',@_) ,"). Aborting ...\n";
+}
+
+$progs = {
+ "SGMLSASP" => ldt_which("sgmlsasp"),
+ "NSGMLS" => ldt_which("nsgmls","onsgmls"),
+ "GROFF" => ldt_which("groff"),
+ "GROFFMACRO" => "-ms",
+# "NKF" => "@NKF@"
+};
+
+$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
+ (defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
+
+require LinuxDocTools;
+&LinuxDocTools::init;
+
+my @FileList = LinuxDocTools::process_options ($0, @ARGV);
+
+foreach my $curfile (@FileList) {
+ &LinuxDocTools::process_file ($curfile);
+}
+
+exit 0;
+
+# Local Variables:
+# mode: perl
+# End:
diff --git a/tools/linuxdoc-tools/LinuxDocTools.pm b/tools/linuxdoc-tools/LinuxDocTools.pm
new file mode 100644
index 00000000..12b77319
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools.pm
@@ -0,0 +1,668 @@
+#! /usr/bin/perl
+#
+# LinuxDocTools.pm
+#
+# LinuxDoc-Tools driver core. This contains all the basic functionality
+# we need to control all other components.
+#
+# Copyright 1996, Cees de Groot.
+# Copyright 2000, Taketoshi Sano
+# Copyright 2006-2018, Agustin Martin
+# --------------------------------------------------------------------------------
+
+package LinuxDocTools;
+
+require 5.006;
+use strict;
+
+=head1 NAME
+
+LinuxDocTools - SGML conversion utilities for LinuxDoc DTD.
+
+=head1 SYNOPSIS
+
+ use LinuxDocTools;
+ LinuxDocTools::init;
+ @files = LinuxDocTools::process_options ($0, @ARGV);
+ for $curfile (@files) {
+ LinuxDocTools::process_file ($curfile);
+ }
+
+=head1 DESCRIPTION
+
+The LinuxDocTools package encapsulates all the functionality offered by
+LinuxDoc-Tools. It is used, of course, by LinuxDoc-Tools;
+but the encapsulation should provide for a simple interface for other users as well.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+use File::Copy;
+use File::Temp qw(tempdir);
+use File::Basename qw(fileparse);
+use LinuxDocTools::Lang;
+use LinuxDocTools::Utils qw(usage cleanup trap_signals remove_tmpfiles create_temp);
+use LinuxDocTools::Vars;
+
+sub BEGIN
+{
+ #
+ # Make sure we're always looking here. Note that "use lib" adds
+ # on the front of the search path, so we first push dist, then
+ # site, so that site is searched first.
+ #
+ use lib "$main::DataDir/dist";
+ use lib "$main::DataDir/site";
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_searchfile {
+# -----------------------------------------------------------------------------------
+# Look for a readable file in the locations. Return first math.
+# -----------------------------------------------------------------------------------
+ my $files = shift;
+ foreach my $file ( @$files ){
+ return $file if -r $file;
+ }
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_getdtd_v1 {
+# -----------------------------------------------------------------------------------
+# Get the dtd
+# -----------------------------------------------------------------------------------
+ my $file = shift;
+ my $error_header = "LinuxdocTools::ldt_getdtd_v1";
+ my $dtd;
+
+ open ( my $FILE, "< $file")
+ or die "$error_header: Could not open \"$file\" for reading. Aborting ...\n";
+
+ while ( <$FILE> ) {
+ tr/A-Z/a-z/;
+ # check for [<!doctype ... system] type definition
+ if ( /<!doctype\s*(\w*)\s*system/ ) {
+ $dtd = $1;
+ last;
+ # check for <!doctype ... PUBLIC ... DTD ...
+ } elsif ( /<!doctype\s*\w*\s*public\s*.*\/\/dtd\s*(\w*)/mi ) {
+ $dtd = $1;
+ last;
+ # check for <!doctype ...
+ # PUBLIC ... DTD ...
+ # (multi-line version)
+ } elsif ( /<!doctype\s*(\w*)/ ) {
+ $dtd = "precheck";
+ next;
+ } elsif ( /\s*public\s*.*\/\/dtd\s*(\w*)/ && $dtd eq "precheck" ) {
+ $dtd = $1;
+ last;
+ }
+ }
+ close $FILE;
+
+ return $dtd;
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_getdtd_v2 {
+# -----------------------------------------------------------------------------------
+# Second way of getting dtd, fron nsgmls output.
+# -----------------------------------------------------------------------------------
+ my $preaspout = shift;
+ my $error_header = "LinuxdocTools::ldt_getdtd_v2";
+ my $dtd2;
+
+ open (my $TMP,"< $preaspout")
+ or die "%error_header: Could not open $preaspout for reading. Aborting ...\n";
+ while ( defined ($dtd2 = <$TMP>) && ! ( $dtd2 =~ /^\(/) ) { };
+ close $TMP;
+ $dtd2 =~ s/^\(//;
+ $dtd2 =~ tr/A-Z/a-z/;
+ chomp $dtd2;
+ return $dtd2;
+}
+
+# -----------------------------------------------------------------------------------
+sub ldt_latin1tosgml {
+# -----------------------------------------------------------------------------------
+# Convert latin1 chars in input filehandle to sgml entities in the returned string
+# -----------------------------------------------------------------------------------
+ my $FILE = shift;
+ my $sgmlout;
+
+ while (<$FILE>){
+ # Outline these commands later on - CdG
+ #change latin1 characters to SGML
+ #by Farzad Farid, adapted by Greg Hankins
+ s//\&Agrave;/g;
+ s//\&Aacute;/g;
+ s//\&Acirc;/g;
+ s//\&Atilde;/g;
+ s//\&Auml;/g;
+ s//\&Aring;/g;
+ s//\&AElig;/g;
+ s//\&Ccedil;/g;
+ s//\&Egrave;/g;
+ s//\&Eacute;/g;
+ s//\&Ecirc;/g;
+ s//\&Euml;/g;
+ s//\&Igrave;/g;
+ s//\&Iacute;/g;
+ s//\&Icirc;/g;
+ s//\&Iuml;/g;
+ s//\&Ntilde;/g;
+ s//\&Ograve;/g;
+ s//\&Oacute;/g;
+ s//\&Ocirc;/g;
+ s//\&Otilde;/g;
+ s//\&Ouml;/g;
+ s//\&Oslash;/g;
+ s//\&Ugrave;/g;
+ s//\&Uacute;/g;
+ s//\&Ucirc;/g;
+ s//\&Uuml;/g;
+ s//\&Yacute;/g;
+ s//\&THORN;/g;
+ s//\&szlig;/g;
+ s//\&agrave;/g;
+ s//\&aacute;/g;
+ s//\&acirc;/g;
+ s//\&atilde;/g;
+ s//\&auml;/g;
+ s//\&aring;/g;
+ s//\&aelig;/g;
+ s//\&ccedil;/g;
+ s//\&egrave;/g;
+ s//\&eacute;/g;
+ s//\&ecirc;/g;
+ s//\&euml;/g;
+ s//\&igrave;/g;
+ s//\&iacute;/g;
+ s//\&icirc;/g;
+ s//\&iuml;/g;
+ s//\&mu;/g;
+ s//\&eth;/g;
+ s//\&ntilde;/g;
+ s//\&ograve;/g;
+ s//\&oacute;/g;
+ s//\&ocirc;/g;
+ s//\&otilde;/g;
+ s//\&ouml;/g;
+ s//\&oslash;/g;
+ s//\&ugrave;/g;
+ s//\&uacute;/g;
+ s//\&ucirc;/g;
+ s//\&uuml;/g;
+ s//\&yacute;/g;
+ s//\&thorn;/g;
+ s//\&yuml;/g;
+ $sgmlout .= $_;
+ }
+ return $sgmlout;
+}
+
+# ------------------------------------------------------------------------
+
+=item LinuxDocTools::init
+
+Takes care of initialization of package-global variables (which are actually
+defined in L<LinuxDocTools::Vars>). The package-global variables are I<$global>,
+a reference to a hash containing numerous settings, I<%Formats>, a hash
+containing all the formats, and I<%FmtList>, a hash containing the currently
+active formats for help texts.
+
+Apart from this, C<LinuxDocTools::init> also finds all distributed and site-local
+formatting backends and C<require>s them.
+
+=cut
+
+# -----------------------------------------------------------------------------------
+sub init {
+# -----------------------------------------------------------------------------------
+ trap_signals;
+
+ # Register the ``global'' pseudoformat. Apart from the global settings, we
+ # also use $global to keep the global variable name space clean everything
+ # that we need to provide to other modules is stuffed into $global.
+ $global = {};
+ $global->{NAME} = "global";
+ $global->{HELP} = "";
+ $global->{OPTIONS} = [
+ { option => "backend",
+ type => "l",
+ 'values' => [ "html", "info", "latex", "lyx", "rtf", "txt", "check" ],
+ short => "B" },
+ { option => "papersize",
+ type => "l",
+ 'values' => [ "a4", "letter" ],
+ short => "p" },
+ { option => "language",
+ type => "l",
+ 'values' => [ @LinuxDocTools::Lang::Languages ],
+ short => "l" },
+ { option => "charset", type => "l",
+ 'values' => [ "latin", "ascii", "nippon", "euc-kr" ], short => "c" },
+ { option => "style", type => "s", short => "S" },
+ { option => "tabsize", type => "i", short => "t" },
+ # { option => "verbose", type => "f", short => "v" },
+ { option => "debug", type => "f", short => "d" },
+ { option => "define", type => "s", short => "D" },
+ { option => "include", type => "s", short => "i" },
+ { option => "pass", type => "s", short => "P" }
+ ];
+ $global->{backend} = "linuxdoc";
+ $global->{papersize} = "a4";
+ $global->{language} = "en";
+ $global->{charset} = "ascii";
+ $global->{style} = "";
+ $global->{tabsize} = 8;
+ $global->{verbose} = 0;
+ $global->{define} = "";
+ $global->{debug} = 0;
+ $global->{include} = "";
+ $global->{pass} = "";
+ $global->{InFiles} = [];
+ $global->{fmtlist} = ""; # List of loaded fmt files
+ $Formats{$global->{NAME}} = $global; # All formats we know.
+ $FmtList{$global->{NAME}} = $global; # List of formats for help msgs.
+
+ $global->{sgmlpre} = "$main::AuxBinDir/sgmlpre";
+ my $error_header = "LinuxdocTools::init";
+
+ if ( -e "/etc/papersize" ){
+ open (my $PAPERSIZE,"< /etc/papersize") ||
+ die "$error_header: Count not open \"/etc/papersize\" for reading\n";
+ chomp (my $paper = <$PAPERSIZE>);
+ $global->{papersize} = "letter" if ( $paper eq "letter");
+ close $PAPERSIZE;
+ }
+
+ # automatic language detection: disabled by default
+ # {
+ # my $lang;
+ # foreach $lang (@LinuxDocTools::Lang::Languages)
+ # {
+ # if (($ENV{"LC_ALL"} =~ /^$lang/i) ||
+ # ($ENV{"LC_CTYPE"} =~ /^$lang/i) ||
+ # ($ENV{"LANG"} =~ /^$lang/i)) {
+ # $global->{language} = Any2ISO($lang);
+ # }
+ # }
+ # }
+
+ # --------------------------------------------------------------------------------
+ $global->{preNSGMLS} = sub {
+ # ------------------------------------------------------------------------------
+ # Define a fallback preNSGMLS. Used when the format is "global" (from sgmlcheck).
+ # ------------------------------------------------------------------------------
+ $global->{NsgmlsOpts} .= " -s ";
+ $global->{NsgmlsPrePipe} = "cat $global->{file}";
+ };
+
+ # We need to load all fmt files here, so the allowed options for all
+ # format are put into $global and a complete usage message is built,
+ # including options for all formats.
+ my %locations = ();
+ foreach my $path ("$main::DataDir/site",
+ "$main::DataDir/dist",
+ "$main::DataDir/fmt"){
+ foreach my $location (<$path/fmt_*.pl>){
+ my $fmt = $location;
+ $fmt =~ s/^.*_//;
+ $fmt =~ s/\.pl$//;
+ $locations{$fmt} = $location unless defined $locations{$fmt};
+ }
+ }
+
+ foreach my $fmt ( keys %locations ){
+ $global->{fmtlist} .= " Loading $locations{$fmt}\n";
+ require $locations{$fmt};
+ }
+}
+
+# ------------------------------------------------------------------------
+
+=item LinuxDocTools::process_options ($0, @ARGV)
+
+This function contains all initialization that is bound to the current
+invocation of LinuxDocTools. It looks in C<$0> to deduce the backend that
+should be used (ld2txt activates the I<txt> backend) and parses the
+options array. It returns an array of filenames it encountered during
+option processing.
+
+As a side effect, the environment variable I<SGML_CATALOG_FILES> is
+modified and, once I<$global->{format}> is known, I<SGMLDECL> is set.
+
+=cut
+
+# ------------------------------------------------------------------------
+sub process_options {
+# ------------------------------------------------------------------------
+ my $progname = shift;
+ my @tmpargs = @_;
+ my @args = ();
+ my $format = '';
+
+ # Try getting the format. We need to do this here so process_options
+ # knows which is the format and which format options are allowed
+
+ # First, see if we have an explicit backend option by looping over command line.
+ # Do not shift in the while condition itself, 0 in options like '-s 0' will
+ # otherwise stop looping
+ while ( @tmpargs ){
+ $_ = shift @tmpargs;
+ if ( s/--backend=// ){
+ $format = $_;
+ } elsif ( $_ eq "-B" ){
+ $format = shift @tmpargs;
+ } else {
+ push @args, $_;
+ }
+ }
+
+ unless ( $format ){
+ my ($tmpfmt, $dummy1, $dummy2) = fileparse($progname, "");
+ if ( $tmpfmt =~ s/^sgml2// ) { # Calling program through sgml2xx symlinks
+ $format = $tmpfmt;
+ } elsif ( $tmpfmt eq "sgmlcheck" ) { # Calling program through sgmlcheck symlink
+ $format = "global";
+ }
+ }
+
+ if ( $format ) {
+ if ( $format eq "check" ){
+ $format = "global";
+ } elsif ( $format eq "latex" ){
+ $format = "latex2e";
+ }
+ $FmtList{$format} = $Formats{$format} or
+ usage("$format: Unknown format");
+ $global->{format} = $format;
+ } else {
+ usage("");
+ }
+
+ # Parse all the options from @args, and return files.
+ my @files = LinuxDocTools::Utils::process_options(@args);
+
+ # Check the number of given files
+ $#files > -1 || usage("No filenames given");
+
+ # Normalize language string
+ $global->{language} = Any2ISO($global->{language});
+
+ # Setup the SGML environment.
+ my @sgmlcatalogs =
+ (# SGML iso-entities catalog location in Debian sgml-data package
+ "$main::isoentities_prefix/share/sgml/entities/sgml-iso-entities-8879.1986/catalog",
+ # SGML iso-entities catalog location in ArchLinux, Fedora and Gentoo
+ "$main::isoentities_prefix/share/sgml/sgml-iso-entities-8879.1986/catalog",
+ # SGML iso-entities catalog location when installed from linuxdoc-tools
+ "$main::isoentities_prefix/share/sgml/iso-entities-8879.1986/iso-entities.cat",
+ # dtd/catalog for SGML-Tools
+ "$main::DataDir/linuxdoc-tools.catalog",
+ # The super catalog
+ "/etc/sgml/catalog");
+
+ @sgmlcatalogs = ($ENV{SGML_CATALOG_FILES}, @sgmlcatalogs) if defined $ENV{SGML_CATALOG_FILES};
+
+ $ENV{SGML_CATALOG_FILES} = join(':', @sgmlcatalogs);
+
+ # Set to one of these if readable, nil otherwise
+ $ENV{SGMLDECL} = ldt_searchfile(["$main::DataDir/dtd/$global->{format}.dcl",
+ "$main::DataDir/dtd/$global->{style}.dcl",
+ "$main::DataDir/dtd/sgml.dcl"]);
+
+ # Show the list of loaded fmt_*.pl files if debugging
+ print STDERR $global->{fmtlist} if $global->{debug};
+
+ # Return the list of files to be processed
+ return @files;
+}
+
+# ------------------------------------------------------------------------
+
+=item LinuxDocTools::process_file
+
+With all the configuration done, this routine will take a single filename
+and convert it to the currently active backend format. The conversion is
+done in a number of steps in tight interaction with the currently active
+backend (see also L<LinuxDocTools::BackEnd>):
+
+=over
+
+=item 1. Backend: set NSGMLS options and optionally create a pre-NSGMLS pipe.
+
+=item 2. Here: Run the preprocessor to handle conditionals.
+
+=item 3. Here: Run NSGMLS.
+
+=item 4. Backend: run pre-ASP conversion.
+
+=item 5. Here: Run SGMLSASP.
+
+=item 6. Backend: run post-ASP conversion, generating the output.
+
+=back
+
+All stages are influenced by command-line settings, currently active format,
+etcetera. See the code for details.
+
+=cut
+
+# ------------------------------------------------------------------------
+sub process_file {
+# ------------------------------------------------------------------------
+ my $file = $global->{origfile} = shift (@_);
+ my $saved_umask = umask;
+ my $error_header = "LinuxdocTools::process_file";
+
+ print "Processing file $file\n";
+ umask 0077;
+
+ my ($filename, $filepath, $filesuffix) = fileparse($file, "\.sgml");
+ $global->{filename} = $filename;
+ $global->{filepath} = $filepath;
+ $global->{file} = ldt_searchfile(["$filepath/$filename.sgml",
+ "$filepath/$filename.SGML"])
+ or die "$error_header: Cannot find $file. Aborting ...\n";
+
+ my $dtd = ldt_getdtd_v1("$global->{file}");
+ print STDERR "DTD: " . $dtd . "\n" if $global->{debug};
+
+ # Prepare temporary directory
+ my $tmpdir = $ENV{'TMPDIR'} || '/tmp';
+ $tmpdir = tempdir("linuxdoc-tools.XXXXXXXXXX", DIR => "$tmpdir");
+
+ # Set common base name for temp files and temp file names
+ my $tmpbase = $global->{tmpbase} = $tmpdir . '/sgmltmp.' . $filename;
+ my $precmdout = "$tmpbase.01.precmdout";
+ my $nsgmlsout = "$tmpbase.02.nsgmlsout"; # Was $tmpbase.1
+ my $preaspout = "$tmpbase.03.preaspout"; # Was $tmpbase.2
+ my $aspout = "$tmpbase.04.aspout"; # Was $tmpbase.3
+
+ # Set up the preprocessing command. Conditionals have to be
+ # handled here until they can be moved into the DTD, otherwise
+ # a validating SGML parser will choke on them.
+
+ # Check if output option for latex is pdf or not
+ if ($global->{format} eq "latex2e") {
+ if ($Formats{$global->{format}}{output} eq "pdf") {
+ $global->{define} .= " pdflatex=yes";
+ }
+ }
+
+ # Set the actual pre-processing command
+ my($precmd) = "| $global->{sgmlpre} output=$global->{format} $global->{define}";
+
+ # Make sure path of file to be processed is in SGML_SEARCH_PATH
+ $ENV{"SGML_SEARCH_PATH"} .= ":$filepath";
+
+ # You can hack $NsgmlsOpts here, etcetera.
+ $global->{NsgmlsOpts} .= "-D $main::prefix/share/sgml -D $main::DataDir";
+ $global->{NsgmlsOpts} .= "-i$global->{include}" if ($global->{include});
+
+ # If a preNSGMLS function is defined in the fmt file, pipe its output to $FILE,
+ # otherwise just open $global->{file} as $IFILE
+ # ----------------------------------------------------------------------------
+ my $IFILE;
+ if ( defined $Formats{$global->{format}}{preNSGMLS} ) {
+ $global->{NsgmlsPrePipe} = &{$Formats{$global->{format}}{preNSGMLS}};
+ open ($IFILE,"$global->{NsgmlsPrePipe} |")
+ || die "$error_header: Could not open pipe from $global->{NsgmlsPrePipe}. Aborting ...\n";
+ } else {
+ open ($IFILE,"< $global->{file}")
+ || die "$error_header: Could not open $global->{file} for reading. Aborting ...\n";
+ }
+
+ # Create a temp file with $precmd output
+ my $precmd_command = "$precmd > $precmdout";
+
+ open (my $PRECMDOUT, "$precmd_command")
+ or die "$error_header: Could not open pipe to $precmdout. Aborting ...\n";
+
+ if ($global->{charset} eq "latin") {
+ print $PRECMDOUT ldt_latin1tosgml($IFILE);
+ } else {
+ copy($IFILE,$PRECMDOUT);
+ }
+
+ close $IFILE;
+ close $PRECMDOUT;
+
+ # Process with nsgmls.
+ my $nsgmls_command = "$main::progs->{NSGMLS} $global->{NsgmlsOpts} $ENV{SGMLDECL} $precmdout > $nsgmlsout";
+ system($nsgmls_command) == 0
+ or die "Error: \"$nsgmls_command\" failed with exit status: ",$? >> 8,"\n";
+
+ # Special case: if format is global, we're just checking.
+ cleanup if ( $global->{format} eq "global");
+
+ # If output file does not exists or is empty, something went wrong.
+ if ( ! -e "$nsgmlsout" ) {
+ die "$error_header: Can't create file $nsgmlsout. Aborting ...\n";
+ } elsif ( -z "$nsgmlsout" ){
+ die "$error_header: $nsgmlsout empty, SGML parsing error. Aborting ...\n";
+ }
+
+ print "- Nsgmls stage finished.\n" if $global->{debug};
+
+ # If a preASP stage is defined, let the format handle it.
+ # --------------------------------------------------------
+ open (my $PREASP_IN, "< $nsgmlsout")
+ or die "$error_header: Could not open $nsgmlsout for reading. Aborting ...\n";
+ open (my $PREASP_OUT, "> $preaspout")
+ or die "$error_header: Could not open $preaspout for writing. Aborting ...\n";
+
+ if (defined $Formats{$global->{format}}{preASP}) {
+ # Usage: preASP ($INHANDLE, $OUTHANDLE);
+ &{$Formats{$global->{format}}{preASP}}($PREASP_IN, $PREASP_OUT) == 0
+ or die "$error_header: Error pre-processing $global->{format}.\n";
+ } else {
+ copy ($PREASP_IN, $PREASP_OUT);
+ }
+
+ close $PREASP_IN;
+ close $PREASP_OUT;
+
+ die "$error_header: Can't create $preaspout file. Aborting ...\n"
+ unless -e "$preaspout";
+
+ print "- PreASP stage finished.\n" if ( $global->{debug} );
+
+ # Run sgmlsasp, with an optional style if specified.
+ # -----------------------------------------------------------
+ my $dtd2 = ldt_getdtd_v2($preaspout)
+ or die "$error_header: Could not read dtd from $preaspout. Aborting ...\n";
+
+ unless ( $dtd eq $dtd2 ){
+ print STDERR "Warning: Two different values for dtd, dtd1: $dtd, dtd2: $dtd2\n";
+ $dtd = $dtd2;
+ }
+
+ $global->{'dtd'} = $dtd;
+
+ # Search order:
+ # - datadir/site/<dtd>/<format>
+ # - datadir/dist/<dtd>/<format>
+
+ my $style = ($global->{style}) ?
+ ldt_searchfile(["$main::DataDir/site/$dtd/$global->{format}/$global->{style}mapping",
+ "$main::DataDir/dist/$dtd/$global->{format}/$global->{style}mapping",
+ "$main::DataDir/mappings/$global->{format}/$global->{style}mapping"])
+ :
+ '';
+
+ my $mapping = ldt_searchfile(["$main::DataDir/site/$dtd/$global->{format}/mapping",
+ "$main::DataDir/dist/$dtd/$global->{format}/mapping",
+ "$main::DataDir/mappings/$global->{format}/mapping"])
+ or die "$error_header: Could not find mapping file for $dtd/$global->{format}. Aborting ...\n";
+
+ $mapping = "$style $mapping" if $style;
+
+ $global->{charset} = "nippon" if ($global->{language} eq "ja");
+
+ # We don't have Korean groff so charset should be latin1.
+ if ($global->{language} eq "ko") {
+ if ($global->{format} eq "groff") {
+ $global->{charset} = "latin1";
+ } else {
+ $global->{charset} = "euc-kr";
+ }
+ }
+
+ if ($global->{format} eq "groff"){
+ if ($dtd eq "linuxdoctr") {
+ $mapping = "$main::DataDir/mappings/$global->{format}/tr-mapping";
+ }
+ }
+
+ my $sgmlsasp_command = "$main::progs->{SGMLSASP} $mapping < $preaspout |
+ expand -t $global->{tabsize} > $aspout";
+ system ($sgmlsasp_command) == 0
+ or die "$error_header: Error running $sgmlsasp_command. Aborting ...\n";
+
+ die "$error_header: Can't create $aspout file. Aborting ...\n"
+ unless -e "$aspout";
+
+ print "- ASP stage finished.\n" if ( $global->{debug} );
+
+ # If a postASP stage is defined, let the format handle it.
+ # ----------------------------------------------------------------
+ umask $saved_umask;
+
+ open (my $INPOSTASP, "< $aspout" )
+ or die "$error_header: Could not open $aspout for reading. Aborting ...\n";
+ if (defined $Formats{$global->{format}}{postASP}) {
+ # Usage: postASP ($INHANDLE)
+ # Should leave whatever it thinks is right based on $INHANDLE.
+ &{$Formats{$global->{format}}{postASP}}($INPOSTASP) == 0
+ or die "$error_header: Error post-processing $global->{format}. Aborting ...\n";
+ }
+ close $INPOSTASP;
+
+ print "- postASP stage finished.\n" if ( $global->{debug} );
+
+ # All done, remove the temporaries.
+ remove_tmpfiles($tmpbase) unless ( $global->{debug} );
+}
+
+=pod
+
+=back
+
+=head1 SEE ALSO
+
+Documentation for various sub-packages of LinuxDocTools.
+
+=head1 AUTHOR
+SGMLTools are written by Cees de Groot, C<E<lt>cg@cdegroot.comE<gt>>,
+and various SGML-Tools contributors as listed in C<CONTRIBUTORS>.
+Taketoshi Sano C<E<lt>sano@debian.org<gt>> rename to LinuxDocTools.
+
+=cut
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm b/tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm
new file mode 100644
index 00000000..e402cc5d
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/BackEnd.pm
@@ -0,0 +1,185 @@
+#
+# BackEnd.pm
+#
+# $Id: BackEnd.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Dummy module containing backend specification.
+#
+# Copyright 1997, Cees de Groot
+#
+package LinuxDocTools::BackEnd;
+
+die "This is a documentation package only!";
+
+=head1 NAME
+
+LinuxDocTools::BackEnd - LinuxDocTools back-end specification
+
+=head1 SYNOPSIS
+
+ require LinuxDocTools::BackEnd;
+ $BackEnd->{...};
+
+=head1 DESCRIPTION
+
+LinuxDoc-Tools backend modules need to conform to a certain interface which is
+detailed in this document. The interface makes sure that new backend modules
+(or customer overrides) are compatible with what the main B<LinuxDocTools>
+package expects. Note that this interface is still subject to change, you
+should check this document on new releases of LinuxDoc-Tools.
+
+=head1 INTERFACE
+
+The interface between the main package and individual backends is very
+minimal - only one global variable is modified, everything else is local. It
+relies heavily on references and complex datatypes, so you want to make
+sure that you're up-to-date with Perl5.
+
+Every backend creates a reference to a hash and stores this reference in
+the global I<%Formats> hash:
+
+ my $BackEnd = {};
+ $Formats{"BackEnd"} = $BackEnd;
+
+The rest of this document will deal with the entries in the local hash
+referenced by I<$BackEnd>.
+
+=head1 HASH ENTRIES
+
+=over 4
+
+=item NAME
+
+Specify the name of the backend, for help messages etcetera.
+
+ $BackEnd->{NAME} = "BackEnd";
+
+=item HELP
+
+Specify an optional extra help message printed when the default usage
+function is executed (see L<LinuxDocTools::Utils>).
+
+ $BackEnd->{HELP} = "This is just and example message";
+
+=item OPTIONS
+
+This specifies the local set of options, which is added to the global set
+of options (available in I<$global>). The options are specified as an
+array of hashes containing a number of keys:
+
+=over 4
+
+=item option
+
+The long option name
+
+=item type
+
+The type of the option, one of B<f> (flag), B<l> (list of allowed values),
+B<s> (string), or B<i> (integer).
+
+=item values
+
+An array of allowed values, in case the option is of the list type.
+
+=item short
+
+A short (single-letter) version of the option name.
+
+=back
+
+Options can be specified as long options:
+
+ --papersize=a4
+
+or as short options:
+
+ -p a4
+
+Note that both the long options as the short options must not conflict with
+the global options (an override is not - yet - possible) and should not
+conflict with other backends.
+
+ $BackEnd->{OPTIONS} = [
+ { option => "split", type => "l",
+ 'values' => [ "0", "1", "2" ], short => "s" },
+ { option => "dosnames", type => "f", short => "D" },
+ { option => "imagebuttons", type => "f", short => "I"}
+ ];
+
+The long names themselves function as hash keys; a default can be given
+here and the option processing function will store any values found
+at the same place:
+
+ $BackEnd->{'split'} = 1;
+ $BackEnd->{dosnames} = 0;
+ $BackEnd->{imagebuttons} = 0;
+
+=item preNSGMLS
+
+If defined, this should contain a subroutine that normally does two things: it
+can modify the global value C<$global-E<gt>{NsgmlsOpts}> and it can set the
+global value C<$global-E<gt>{NsgmlsPrePipe}>. The first variable contains
+the option string passed to B<nsgmls>, and the second variable can contain
+a command that generates the input for B<nsgmls>, presumably using the
+current input file in some way (the current input file can be found
+in C<$global-E<gt>{file}>).
+
+ $BackEnd->{preNSGMLS} = sub {
+ $global->{NsgmlsOpts} .= " -ifmtBackEnd ";
+ $global->{NsgmlsPrePipe} = "sed 's/\@/\@\@/g' $global->{file}";
+ };
+
+=item preASP
+
+If defined, this should contain a subroutine accepting an input and an output
+file descriptor. The input file descriptor contains the raw output from
+B<nsgmls>, and the output file descriptor should be filled with input
+to B<sgmlsasp>. This stage is often used to munch character entities
+before they're fed to B<sgmlsasp>, see L<LinuxDocTools::CharEnts>. If the routine
+doesn't return C<0>, LinuxDocTools aborts.
+
+ $BackEnd->{preASP} = sub
+ {
+ my ($infile, $outfile) = @_;
+
+ while (<$infile>)
+ {
+ s/([^\\])\\n/$1 \\n/g;
+ print $outfile $_;
+ }
+ return 0;
+ };
+
+=item postASP
+
+This entry should always be defined, because it needs to contain a routine
+that receives the output from B<sgmlsasp> which normally needs finalization.
+LinuxDocTools itself doesn't know about file-naming conventions, etcetera, of
+the backend so writing the final file is left to the backend. The subroutine
+receives a reference to a filehandle (containing B<sgmlsasp> output) and
+should do whatever it likes with this datastream.
+
+ $BackEnd->{postASP} = sub
+ {
+ my $infile = shift;
+
+ copy ($infile, "$global->{filename}.ext");
+ return 0;
+ };
+
+=back
+
+=head1 SEE ALSO
+
+L<LinuxDocTools> and subpackages.
+
+=head1 AUTHOR
+
+SGML-Tools are written by Cees de Groot, C<E<lt>cg@cdegroot.comE<gt>>,
+and various SGML-Tools contributors as listed in C<CONTRIBUTORS>.
+Taketoshi Sano C<E<lt>sano@debian.org<gt>> rename it to LinuxDocTools,
+and do some bug-fixes and updates on it.
+
+=cut
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm b/tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm
new file mode 100644
index 00000000..b0bcd532
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/CharEnts.pm
@@ -0,0 +1,176 @@
+#
+# CharEnts.pm
+#
+# $Id: CharEnts.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# SGML Character Entity utilities -- interface to Perl module
+# Text::EntityMap.
+#
+package LinuxDocTools::CharEnts;
+use strict;
+
+=head1 NAME
+
+LinuxDocTools::CharEnts - Interface to Text::EntityMap
+
+=head1 SYNOPSIS
+
+ my $char_maps = load_char_maps ('.2ext', [ Text::EntityMap::sdata_dirs() ]);
+
+ $value = parse_data ($value, $char_maps, $escape_sub);
+
+=head1 DESCRIPTION
+
+This module provides a simple interface to the entity map handling provided by
+B<Text::EntityMap>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+use Text::EntityMap;
+use Exporter;
+
+use vars qw(@ISA @EXPORT $VERSION);
+@ISA = qw(Exporter);
+@EXPORT = qw(load_char_maps parse_data);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
+
+# `%warn_map' tracks entities that were not able to be mapped so they
+# are only warned once.
+my %warn_map = ();
+
+=item parse_data ($data, $char_map, $escape_sub)
+
+B<parse_data> takes a string of I<$data> in the output format of
+B<nsgmls> (see SP's C<sgmlsout.htm> document) without the leading dash.
+B<parse_data> calls I<$char_map>'s lookup method for each sdata
+entity reference. If the entity reference is undefined, it is
+left alone (without the (n)sgmls C<\|>). For all remaining data,
+B<parse_data> calls back into I<$escape_sub> to properly escape
+characters for the backend formatter. Strings returned from the
+lookup method are assumed to be already escaped.
+
+This routine is derived from David Megginson's SGMLSpm.
+
+=cut
+
+sub parse_data {
+ my ($data, $char_map, $escape_sub) = @_;
+ my ($result) = "";
+
+ my $sdata_flag = 0;
+ my $out = '';
+
+ while ($data =~ /\\(\\|n|\||[0-7]{1,3})/) {
+ $out .= $`;
+ $data = $';
+
+ if ($1 eq '|') {
+ # beginning or end of SDATA
+ if ("$out" ne '') {
+ if ($sdata_flag) {
+ my ($mapping) = $char_map->lookup ($out);
+ if (defined $mapping) {
+ # escape `\' in mapping for ASP
+ $mapping =~ s/\\/\\\\/g;
+ $result .= $mapping;
+ } else {
+ if (!$warn_map{$out}) {
+ warn "parse_data: no entity map for \`$out'\n";
+ $warn_map{$out} = 1;
+ }
+ # output the entity reference inside of `{}'
+ $result .= &$escape_sub ("{" . $out . "}");
+ }
+ } else {
+ $result .= &$escape_sub ($out);
+ }
+ $out = '';
+ }
+ $sdata_flag = !$sdata_flag;
+
+ } elsif ($1 eq 'n') {
+ # record end
+
+ # pass '\\n' through to ASP
+ $result .= &$escape_sub ($out) . '\\n';
+ $out = '';
+ } elsif ($1 eq '\\') {
+ # backslash
+
+ $result .= &$escape_sub ($out);
+
+ $out = '[bsol ]'; # bsol == entity name for backslash
+ my ($mapping) = $char_map->lookup ($out);
+ if (defined $mapping) {
+ # escape `\' in mapping for ASP
+ $mapping =~ s/\\/\\\\/g;
+ $result .= $mapping;
+ } else {
+ if (!$warn_map{$out}) {
+ warn "parse_data: no entity map for \`$out'\n";
+ $warn_map{$out} = 1;
+ }
+ # output the entity reference inside of `{}'
+ $result .= &$escape_sub ("{" . $out . "}");
+ }
+ $out = '';
+ } else {
+ # other octal character
+ $result .= &$escape_sub ($out . chr(oct($1)));
+ $out = '';
+ }
+ }
+ $out .= $data;
+ if ("$out" ne '') {
+ $result .= &$escape_sub ($out);
+ }
+
+ return ($result);
+}
+
+=item load_char_maps ($format, $paths)
+
+B<load_char_maps> takes an EntityMap format suffix and loads all of the
+character entity replacement sets for that suffix into an EntityMapGroup.
+It searches every directory in I<@{$path}>.
+
+=cut
+
+sub load_char_maps {
+ my ($format, $paths) = @_;
+
+ my (@char_maps) = ();
+ my ($path, $file_name, $char_map);
+
+ foreach $path (@{$paths}) {
+ if (-d $path) {
+ opendir (SDATADIR, $path)
+ || die "load_char_map: opening directory \`$path' for reading: $!\n";
+ foreach $file_name (readdir (SDATADIR)) {
+ next if ($file_name !~ /$format$/);
+ eval {$char_map = Text::EntityMap->load ("$path/$file_name")}
+ || die "load_char_map: loading \`$path/$file_name'\n$@\n";
+ push (@char_maps, $char_map);
+ }
+ closedir (SDATADIR);
+ }
+ }
+
+ warn "load_char_maps: no entity maps found\n"
+ if ($#char_maps == -1);
+
+ return (Text::EntityMap->group (@char_maps));
+}
+
+=back
+
+=head1 AUTHOR
+
+Ken MacLeod, C<E<lt>ken@bitsko.slc.ut.usE<gt>>
+
+=cut
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/FixRef.pm b/tools/linuxdoc-tools/LinuxDocTools/FixRef.pm
new file mode 100644
index 00000000..d2549857
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/FixRef.pm
@@ -0,0 +1,76 @@
+#
+# FixRef.pm
+#
+# $Id: FixRef.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Start conversion from parsed linuxdoc-sgml to html.
+# - Identify references and file count
+#
+# Rules based on fixref.l
+#
+package LinuxDocTools::FixRef;
+
+# Externally visible variables
+$fixref = {};
+
+# Initialize: set splitlevel before using rules
+# Usage: &{$fixref->{init}}(<split level>);
+ # 0 - super page mode
+ # 1 - big page mode
+ # 2 - small page mode
+$fixref->{init} = sub {
+ $splitlevel = shift;
+};
+
+# Outputs: Read after using rules
+$fixref->{filenum} = 0; # Count of files we will create
+$fixref->{lrec} = {}; # label -> filenum
+
+# Package variables
+$chapter_mode = 0; # <report> vs. <article>
+$splitlevel = 0; # See $fixref->{init} above;
+ # Automatically reduced by 1 for chapter mode
+
+# Finalize parsing
+$fixref->{finish} = sub { }; # Do nothing when we're done
+
+# Ruleset
+$fixref->{rules} = {}; # Individual parsing rules
+$fixref->{defaultrule} = sub { }; # If line does not match any rules
+
+# Set the rules
+# <@@ssect> - split file if necessary
+$fixref->{rules}->{'^<@@ssect>.*$'} = sub { &splitfile(2); };
+
+# <@@sect> - split file if necessary
+$fixref->{rules}->{'^<@@sect>.*$'} = sub { &splitfile(1); };
+
+# <@@chapt> - set chapter mode; reduce splitlevel if needed; split file
+$fixref->{rules}->{'^<@@chapt>.*$'} = sub {
+ $splitlevel-- if (!$chapter_mode);
+ $chapter_mode = 1; &splitfile(0);
+};
+
+# <@@label> - Identify label location
+$fixref->{rules}->{'^<@@label>(.*)$'} = sub {
+ $fixref->{lrec}->{$1} = $fixref->{filenum};
+};
+
+#==============================
+# Split the file (-split option; level in parentheses):
+# non-chapter mode: -0 -> don't split
+# -1 -> split at sect (1)
+# -2 -> split at sect (1) and ssect (2)
+# chapter mode: -0 -> split at chapt (0)
+# -1 -> split at chapt (0)
+# -2 -> split at chapt (0) and sect (1)
+sub splitfile
+{
+ my ($level) = @_;
+ if (($level == 0) || ($splitlevel >= $level)) {
+ $fixref->{filenum}++;
+ }
+}
+
+1;
+
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm b/tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm
new file mode 100644
index 00000000..9ff2e4cc
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Html2Html.pm
@@ -0,0 +1,583 @@
+#
+# Html2Html.pm
+#
+# $Id: Html2Html.pm,v 1.4 2001/08/31 23:09:10 sano Exp $
+#
+# Convert parsed linuxdoc-sgml to html.
+# - Split files; match references, generate TOC and navigation
+# aids, etc.
+#
+# Rules based on html2html.l
+#
+package LinuxDocTools::Html2Html;
+
+use FileHandle;
+use LinuxDocTools::Lang;
+
+# Externally visible variables
+$html2html = {};
+
+# Initialize: set splitlevel, extension, images, filename,
+# filenumber, label, header, footer, toclevel,
+# tmpbase, debug.
+# Usage:
+# &{$html2html->{init}}(split,ext,img,filename,filenum,label,hdr,ftr,toc,tmpbase, debug);
+# split level: 0 - super page mode
+# 1 - big page mode
+# 2 - small page mode
+$html2html->{init} = sub {
+ $splitlevel = shift;
+ SWITCH: {
+ $super_page_mode = 0, $big_page_mode = 1, last SWITCH
+ if ($splitlevel == 1);
+ $super_page_mode = 0, $big_page_mode = 0, last SWITCH
+ if ($splitlevel == 2);
+ }
+
+ $fileext = shift;
+ $use_imgs = shift;
+ $firstname = shift;
+ $filecount = 1 + shift;
+ $lprec = shift;
+
+ $header = shift;
+ $footer = shift;
+
+ $toclevel = shift;
+ if ($toclevel == -1) {
+ if ($splitlevel == 0) {
+ $toclevel = 0;
+ } else {
+ $toclevel = 2;
+ }
+ }
+
+ $tmpbase = shift;
+ $content_file = $tmpbase . ".content";
+
+ $debug = shift;
+
+ $nextlabel = Xlat ("Next");
+ $prevlabel = Xlat ("Previous");
+ $toclabel = Xlat ("Contents");
+};
+
+# Package variables
+$big_page_mode = 0; # '-2' subsection splitting
+$super_page_mode = 1; # One page vs. page/section
+$chapter_mode = 0; # <article> vs. <report>
+$current = ""; # State of section/subsection/etc.
+$filenum = 1; # Current output file number
+$filecount = 1;
+$firstname = "$$"; # Base name for file
+$headbuf = ""; # Buffer for URL's
+$fileext = "html"; # "html" vs. "htm" for 8.3
+$in_appendix = 0; # n.n vs. a.n section numbers
+$in_section_list = 0; # List of sections flag
+$language = ""; # Default English; use '-Lname'
+# $lprec{label} # Label record
+$nextlabel = ""; # Link string
+$outfh = STDOUT; # Output filehandle
+$outname = ""; # Output file name
+$prevlabel = ""; # Link string
+$refname = ""; # Ref string
+$sectname = ""; # Section name
+$secnr = 0; # Section count
+$ssectname = ""; # Subsection name
+$ssecnr = 0; # Subsection count
+$skipnewline = 0; # Flag to ignore new line
+$toclabel = ""; # Link string
+$titlename = ""; # Title of document
+$use_imgs = 0; # '-img' pictorial links
+$urlname = ""; # Name for url links
+$header = "";
+$footer = "";
+$toclevel = -1;
+$tmpbase = "/tmp/sgmltmp" . $$;
+$debug = 0;
+$content_file = $tmpbase . ".content.init";
+
+# Ruleset
+$html2html->{rules} = {}; # Individual parsing rules
+
+$html2html->{rules}->{'^<@@appendix>.*$'} = sub {
+ $in_appendix = 1; $secnr = 0; $ssecnr = 0;
+};
+
+$html2html->{rules}->{'^<@@url>(.*)$'} = sub {
+ $skipnewline = 1; $urlname = $1; $headbuf = qq(<A HREF="$1">);
+};
+
+$html2html->{rules}->{'^<@@urlnam>(.*)$'} = sub {
+ $headbuf = $headbuf . "$urlname</A>";
+};
+
+$html2html->{rules}->{'^<@@endurl>.*$'} = sub {
+ $skipnewline = -1; $outfh->print($headbuf); $headbuf = "";
+};
+
+$html2html->{rules}->{'^<@@title>(.*)$'} = sub {
+ $titlename = $1; &heading(STDOUT); print(STDOUT "<H1>$1</H1>\n\n");
+};
+
+$html2html->{rules}->{'^<@@head>(.*)$'} = sub {
+ $skipnewline = 1; $headbuf = $1;
+};
+
+$html2html->{rules}->{'^<@@part>.*$'} = sub { $current = "PART"; };
+
+$html2html->{rules}->{'^<@@endhead>.*$'} = sub {
+ SWITCH: {
+ $outfh->print("<H1>$headbuf</H1>\n\n"), last SWITCH
+ if ($current eq "PART");
+ $outfh->print("<H1>$headbuf</H1>\n\n"), last SWITCH
+ if ($current eq "CHAPTER");
+ $outfh->print("<H2>$headbuf</H2>\n\n"), last SWITCH
+ if ($current eq "SECTION");
+ $outfh->print("<H2>$headbuf</H2>\n\n"), last SWITCH
+ if ($current eq "SUBSECT");
+ $outfh->print("<H3>$headbuf</H3>\n\n"), last SWITCH;
+ }
+ $current = ""; $headbuf = ""; $skipnewline = 0;
+};
+
+$html2html->{rules}->{'^<@@chapt>(.*)$'} = sub {
+ $chapter_mode = 1; $skipnewline = 1; $sectname = $1;
+ &start_chapter($sectname);
+};
+
+$html2html->{rules}->{'^<@@sect>(.*)$'} = sub {
+ $skipnewline = 1; $ssectname = $1;
+ if ($chapter_mode) {
+ &start_section($ssectname);
+ } else {
+ $sectname = $ssectname; &start_chapter($ssectname);
+ }
+};
+
+$html2html->{rules}->{'^<@@ssect>(.*)$'} = sub {
+ $skipnewline = 1; $ssectname = $1;
+ if (!$chapter_mode) {
+ &start_section($ssectname);
+ } else {
+ $current = ""; $headbuf = $ssectname;
+ }
+};
+
+$html2html->{rules}->{'^<@@endchapt>.*$'} = sub {
+ STDOUT->print("</UL>\n") if ($in_section_list);
+ if ($outfh->fileno != STDOUT->fileno) {
+ &footing($outfh) if (!$super_page_mode);
+ $outfh->close; $outfh = STDOUT;
+ }
+};
+
+$html2html->{rules}->{'^<@@endsect>.*$'} = sub {
+ STDOUT->print("</UL>\n") if (!$chapter_mode && $in_section_list);
+ if (($outfh->fileno != STDOUT->fileno)
+ && ((!$chapter_mode) || (!$big_page_mode))) {
+ &footing($outfh) if (!$super_page_mode);
+ $outfh->close; $outfh = STDOUT;
+ }
+};
+
+$html2html->{rules}->{'^<@@endssect>.*$'} = sub {
+ if (($outfh->fileno != STDOUT->fileno)
+ && (!$chapter_mode) && (!$big_page_mode) && (!$super_page_mode)) {
+ &footing($outfh); $outfh->close; $outfh = STDOUT;
+ }
+};
+
+$html2html->{rules}->{'^<@@enddoc>.*$'} = sub { };
+
+$html2html->{rules}->{'^<@@label>(.*)$'} = sub {
+ if (!defined($lprec->{$1})) {
+ STDERR->print(qq(html2html: Problem with label "$1"\n)); next;
+ }
+ if ($skipnewline) {
+ $headbuf = sprintf(qq(<A NAME="%s"></A> %s), $1, $headbuf);
+ } else {
+ $outfh->print(qq(<A NAME="$1"></A> ));
+ }
+};
+
+$html2html->{rules}->{'^<@@ref>(.*)$'} = sub {
+ my $tmp;
+
+ $refname = $1;
+ if (!defined($lprec->{$1})) {
+ STDERR->print(qq(html2html: Problem with ref "$1"\n));
+ $skipnewline++; next;
+ }
+ SWITCH: {
+ $tmp = qq(<A HREF="#$1">), last SWITCH
+ if ($lprec->{$1} == $filenum - 1);
+ $tmp = qq(<A HREF="$firstname.$fileext#$1">), last SWITCH
+ if ($lprec->{$1} == 0);
+ $tmp = qq(<A HREF="$firstname-$lprec->{$1}.$fileext#$1">),
+ last SWITCH;
+ }
+ if ($skipnewline) {
+ $headbuf = "$headbuf$tmp";
+ } else {
+ $headbuf = $tmp;
+ }
+ $skipnewline++;
+};
+
+$html2html->{rules}->{'^<@@refnam>.*$'} = sub {
+ $headbuf = "$headbuf$refname</A>\n";
+};
+
+$html2html->{rules}->{'^<@@endref>.*$'} = sub {
+ if ($skipnewline == 1) {
+ $outfh->print($headbuf); $skipnewline = -1;
+ } elsif ($skipnewline == 2) {
+ $skipnewline--;
+ } else {
+ STDERR->print("html2html: Problem with endref\n");
+ $skipnewline--;
+ }
+};
+
+# Default parsing rule
+$html2html->{defaultrule} = sub {
+ $skipnewline++ if ($skipnewline < 0);
+ if ($skipnewline) {
+ chop; $headbuf = "$headbuf$_";
+ } else {
+ $outfh->print($_);
+ }
+};
+
+# Finalize parsing process
+$html2html->{finish} = sub {
+ # Finish footers
+ if ($outfh->fileno != STDOUT->fileno) {
+ if (!$super_page_mode) {
+ &footing($outfh);
+ $outfh->close;
+ }
+ }
+ #
+ if ($super_page_mode) {
+ if ($toclevel > 0) { STDOUT->print("\n<HR>\n"); }
+ $outfh->close if ($outfh->fileno != STDOUT->fileno);
+ if ( -r $content_file ) {
+ open CONTENT, "<$content_file"
+ or die "Can't open content file\n";
+ while (<CONTENT>) {
+ STDOUT->print($_);
+ }
+ close CONTENT;
+ unlink $content_file if (! $debug);
+ }
+ }
+ # Finish the TOC; ensure "next" points to the first page.
+ &browse_links(STDOUT, 1, 0) if (!$super_page_mode);
+ #
+ # add Footer
+ if ( -r "$footer" ) {
+ open FTRFILE, "<$footer" or die "Cannot open footer file\n";
+ while (<FTRFILE>) {
+ STDOUT->print($_);
+ }
+ close FTRFILE;
+ } else {
+ STDOUT->print("</BODY>\n</HTML>\n");
+ }
+};
+
+
+###################################################################
+# Secondary Functions
+###################################################################
+
+# Print standard links
+sub browse_links {
+ my ($outfh, $myfilenum, $top) = @_;
+
+ return if ($super_page_mode);
+
+ $outfh->print("<HR>\n") unless ($top);
+
+ # NOTE: For pages where a next or prev button isn't appropriate, include
+ # the graphic anyway - just don't make it a link. That way, the mouse
+ # position of each button is unchanged from page to page.
+ # Use the passed myfilenum since filenum may already be incremented
+
+ # Next link (first)
+ my $next = $use_imgs
+ ? qq(<IMG SRC="next.png" ALT="$nextlabel">)
+ : qq($nextlabel);
+ $next = qq(<A HREF="$firstname-$myfilenum.$fileext">$next</A>)
+ if ($myfilenum < $filecount);
+ $next = join "", $next, "\n";
+ $outfh->print($next);
+
+ # Previous link
+ my $prev = $use_imgs
+ ? qq(<IMG SRC="prev.png" ALT="$prevlabel">)
+ : qq($prevlabel);
+ $prev = join "", qq(<A HREF="$firstname-), ($myfilenum - 2),
+ qq(.$fileext">$prev</A>)
+ if ($myfilenum >= 3);
+ $prev = join "", $prev, "\n";
+ $outfh->print($prev);
+
+ # Table of contents link
+ my $toc = $use_imgs
+ ? qq(<IMG SRC="toc.png" ALT="$toclabel">)
+ : qq($toclabel);
+ $toc = join "", qq(<A HREF="$firstname.$fileext#toc),
+ &section_num($secnr, 0), qq(">$toc</A>)
+ if ($outfh->fileno != STDOUT->fileno);
+ $toc = join "", $toc, "\n";
+ $outfh->print($toc);
+
+ print($outfh "<HR>\n") if ($top);
+}
+
+# Print end-of-file markup
+sub footing {
+ my $outfh = shift;
+ &browse_links($outfh, $filenum, 0);
+ if ( -r "$footer" ) {
+ open FTRFILE, "<$footer" or die "Cannot open footer file\n";
+ while (<FTRFILE>) {
+ $outfh->print($_);
+ }
+ close FTRFILE;
+ } else {
+ $outfh->print("</BODY>\n</HTML>\n");
+ }
+}
+
+# Print top-of-file markup
+sub heading {
+ my $outfh = shift; my $match;
+
+ # Emit 3.2 HTML until somebody comes up with a better idea - CdG
+ if ( -r "$header" ) {
+ open HDRFILE, "<$header" or die "Cannot open header file\n";
+ while (<HDRFILE>) {
+ $outfh->print($_);
+ }
+ close HDRFILE;
+ } else {
+ $outfh->print(
+ qq(<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n));
+ $outfh->print("<HTML>\n<HEAD>\n");
+ }
+ open VERSFILE, "<$main::DataDir/VERSION" or die "Cannot open version file\n";
+ $version = <VERSFILE>;
+ close VERSFILE;
+ chop $version;
+ $outfh->print(
+ " <META NAME=\"GENERATOR\" CONTENT=\"LinuxDoc-Tools $version\">\n");
+
+ $outfh->print(" <TITLE>");
+ $match = $titlename;
+ $match =~ s/<[^>]*>//g;
+ $outfh->print($match);
+ if ($secnr > 0) {
+ $match = $sectname;
+ $match =~ s/<[^>]*>//g;
+ $outfh->print(": $match");
+ }
+ if ($ssecnr > 0) {
+ $match = $ssectname;
+ $match =~ s/<[^>]*>//g;
+ $outfh->print(": $match");
+ }
+ $outfh->print("</TITLE>\n");
+
+ if (!$super_page_mode) {
+ #
+ # <LINK> Information for next, previous, contents, etc...
+ #
+ $outfh->print(qq( <LINK HREF="$firstname-$filenum.$fileext" REL=next>),"\n")
+ if ($filenum < $filecount);
+ my $prev;
+ $prev = join "", qq( <LINK HREF="$firstname-), ($filenum - 2),
+ qq(.$fileext" REL=previous>)
+ if ($filenum >= 3);
+ $outfh->print($prev,"\n");
+
+ #
+ # Table of contents link
+ #
+ my $toc ;
+ $toc = join "", qq( <LINK HREF="$firstname.$fileext#toc),
+ &section_num($secnr, 0), qq(" REL=contents>)
+ if ($outfh->fileno != STDOUT->fileno);
+ $outfh->print($toc,"\n");
+ } # (!$super_page_mode)
+
+ $outfh->print("</HEAD>\n<BODY>\n");
+ &browse_links($outfh, $filenum, 1);
+}
+
+# Return the section and subsection as a dotted string
+sub section_num {
+ my ($sec, $ssec) = @_;
+ my $l = "A";
+
+ if ($in_appendix) {
+ $sec--;
+ while ($sec) { $l++; $sec--; }
+ return("$l.$ssec") if ($ssec > 0);
+ return("$l");
+ } else {
+ return("$sec.$ssec") if ($ssec > 0);
+ return("$sec");
+ }
+}
+
+# Create a chapter head; start a new file, etc.
+sub start_chapter {
+ my $sectname = shift;
+
+ if (!$super_page_mode && $outfh->fileno != STDOUT->fileno) {
+ &footing($outfh); $outfh->close;
+ }
+ $current = "SECTION"; $secnr++; $ssecnr = 0;
+ if ($super_page_mode) {
+ $outname = $content_file;
+ $outfh = new FileHandle ">>$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ if ($toclevel > 0) {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s.</A> <A HREF="#toc%s">%s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ &section_num($secnr, 0),
+ $sectname);
+ STDOUT->printf(
+ qq(<P>\n<H2><A NAME="toc%s">%s.</A> <A HREF="%s#s%s">%s</A></H2>\n\n),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ "$firstname.$fileext", &section_num($secnr, 0), $sectname);
+ } else {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s. %s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ $sectname);
+ }
+ } else {
+ $outname = "$firstname-$filenum.$fileext"; $filenum++;
+ $outfh = new FileHandle ">$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ &heading($outfh);
+ if ($toclevel > 0) {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s.</A> <A HREF="%s#toc%s">%s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ "$firstname.$fileext", &section_num($secnr, 0),
+ $sectname);
+ STDOUT->printf(
+ qq(<P>\n<H2><A NAME="toc%s">%s.</A> <A HREF="%s">%s</A></H2>\n\n),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ $outname, $sectname);
+ } else {
+ $headbuf = sprintf(
+ qq(<A NAME="s%s">%s. %s</A>),
+ &section_num($secnr, 0), &section_num($secnr, 0),
+ $sectname);
+ }
+ }
+ $in_section_list = 0;
+}
+
+# Create a section; start a new file, etc.
+sub start_section {
+ my $ssectname = shift;
+
+ $current = "SUBSECT"; $ssecnr++;
+ if ($toclevel > 1) {
+ if (!$in_section_list) {
+ STDOUT->print("<UL>\n"); $in_section_list = 1;
+ }
+ }
+ if ($super_page_mode) {
+ if ($outfh->fileno != STDOUT->fileno && !$chapter_mode) {
+ $outfh->close;
+ }
+ $outname = $content_file;
+ $outfh = new FileHandle ">>$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ if ($toclevel > 1) {
+ $headbuf = sprintf(qq(<A NAME="ss%s">%s</A> <A HREF="#toc%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ STDOUT->printf(
+ qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s#ss%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ "$firstname.$fileext",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ } else {
+ $headbuf = sprintf(qq(<A NAME="ss%s">%s %s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ }
+ } else {
+ if (!$big_page_mode) {
+ if ($outfh->fileno != STDOUT->fileno) {
+ &footing($outfh); $outfh->close;
+ }
+ $outname = "$firstname-$filenum.$fileext"; $filenum++;
+ $outfh = new FileHandle ">$outname"
+ or die qq(html2html: Fatal: Could not open file "$outname"\n);
+ heading($outfh);
+
+ # Since only one section is on any page,
+ # don't use # so that when we
+ # jump to this page, we see the browse
+ # links at the top of the page.
+ if ($toclevel > 1) {
+ $headbuf = sprintf("%s <A HREF=\"%s#toc%s\">%s</A>",
+ &section_num($secnr, $ssecnr),
+ "$firstname.$fileext",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ STDOUT->printf(
+ qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $outname, $ssectname);
+ } else {
+ $headbuf = sprintf("%s %s</A>",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ }
+ } else {
+ # Since many sections are on one page, we need to use #
+ if ($toclevel > 1) {
+ $headbuf = sprintf(
+ qq(<A NAME="ss%s">%s</A> <A HREF="%s#toc%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ "$firstname.$fileext",
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ STDOUT->printf(
+ qq(<LI><A NAME="toc%s">%s</A> <A HREF="%s#ss%s">%s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $outname,
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ } else {
+ $headbuf = sprintf(
+ qq(<A NAME="ss%s">%s %s</A>\n),
+ &section_num($secnr, $ssecnr),
+ &section_num($secnr, $ssecnr),
+ $ssectname);
+ }
+ }
+ }
+}
+
diff --git a/tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm b/tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm
new file mode 100644
index 00000000..b4bd50bd
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/InfoUtils.pm
@@ -0,0 +1,357 @@
+# InfoUtils.pm
+#
+# Some utils for the linuxdoc info backend.
+#
+# * Create menus
+# * Normalize node names and associated text
+# * Point references to the associated node as needed
+#
+# Copyright (C) 2009 Agustn Martn Domingo, agmartin at debian 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 3 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/>.
+# --------------------------------------------------------------------
+
+
+package LinuxDocTools::InfoUtils;
+
+use base qw(Exporter);
+
+# List all exported symbols here.
+our @EXPORT_OK = qw(info_process_texi);
+
+# Import :all to get everything.
+our %EXPORT_TAGS = (all => [@EXPORT_OK]);
+
+=head1 NAME
+
+ InfoUtils - Some utils for the linuxdoc info backend.
+
+=head1 SYNOPSIS
+
+use InfoUtils q{:all};
+
+info_process_texi($infile, $outfile, $infoname)
+
+=head1 DESCRIPTION
+
+This module contains some utils to process the raw texinfo file
+creating menus, normalizing node names and associated text and
+pointing references to the associated node as needed.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+# -------------------------------------------------------------------------
+sub info_normalize_node_text {
+# -------------------------------------------------------------------------
+# Filter characters not allowed in section names
+# -------------------------------------------------------------------------
+ my $text = shift;
+
+ $text =~ s/\s+/ /g;
+ $text =~ s/\@[A-Za-z][A-Za-z0-9]*//g;
+ $text =~ s/(\{|\})//g;
+ $text =~ s/\,//g;
+# $text =~ s/\.+$//g;
+ $text =~ s/\./-/g;
+ $text =~ s/\s+$//g;
+
+ return $text;
+}
+
+# -------------------------------------------------------------------------
+sub info_normalize_node_name {
+# -------------------------------------------------------------------------
+# Filter characters not allowed in node names. Previous filtering of
+# characters not allowed in section names is supposed.
+# -------------------------------------------------------------------------
+ my $text = shift;
+# my $tmpnodedata = shift;
+
+ $text =~ s/\://g;
+ $text =~ s/\;//g;
+
+# die "Error: Reference \"$text\" already used"
+# if defined $tmpnodedata->{$text};
+
+ return $text;
+}
+
+# -------------------------------------------------------------------------
+sub info_parse_raw_file {
+# -------------------------------------------------------------------------
+# Parse raw texinfo file. It does not yet contain section names, menus,
+# correct references or title.
+# -------------------------------------------------------------------------
+ my $inputfile = shift;
+ my $INPUT;
+
+ my @inputtext = (); # Copy of input file with some preprocessing
+ my %nodedata = # A hash of hashes with all node info
+ ( 'Top' =>
+ { 'text' => "Top",
+ 'depth' => 0,
+ 'up' => "",
+ 'next' => '',
+ 'previous' => "",
+ 'sort' => 0,
+ 'debug' => "",
+ 'menu' => []}
+ );
+
+ my %levellast = (0 => "Top");
+ my %labels = ();
+ my %docdata = # Some misc data for the document
+ ( 'title' => "",
+ 'author' => "",
+ 'subtitle' => ""
+ );
+
+ my $depth = my $lastdepth = 0;
+ my $lastnode = "";
+ my $sort = 0;
+
+ my $inauthor;
+ my $authorline;
+
+ open ($INPUT, "< $inputfile")
+ or die "info-postASP: Could not open $inputfile for read. Aborting ...\n";
+
+ while (<$INPUT>){
+ chomp;
+ if ( s/^\@SUB\s+// ){
+ my $updepth = $depth;
+ my $uppernode = $levellast{$updepth};
+ $depth++;
+ $sort++;
+
+ my @levelmenu = ();
+
+ if ( defined $nodedata{$uppernode}->{'menu'} ){
+ @levelmenu = @{ $nodedata{$uppernode}->{'menu'} };
+ }
+
+ my $nodetext = info_normalize_node_text($_);
+ my $nodename = info_normalize_node_name($nodetext,\%nodedata);
+
+ # Make first appearing node the next node for top node
+ $nodedata{'Top'}->{'next'} = $nodename if ( $lastdepth eq 0);
+
+ # Fill info for current node (and 'next' for last one in level)
+ $nodedata{$nodename}->{'orig'} = $_;
+ $nodedata{$nodename}->{'text'} = $nodetext;
+ $nodedata{$nodename}->{'depth'} = $depth;
+ $nodedata{$nodename}->{'previous'} =
+ defined $levellast{$depth} ? $levellast{$depth} : "";
+ $nodedata{$levellast{$depth}}->{'next'} = $nodename
+ if defined $levellast{$depth};
+ $nodedata{$nodename}->{'up'} = $uppernode;
+ $nodedata{$nodename}->{'sort'} = $sort;
+ $nodedata{$nodename}->{'debug'} =
+ "updepth: $updepth, lastdepth: $lastdepth, up: $uppernode";
+
+ # Keep this defined in case tbere is no next node in the same level.
+ $nodedata{$nodename}->{'next'} = "";
+
+ push @inputtext, "\@SUB $nodename"; # Rewrite @SUB with the new name
+ push @levelmenu, $nodename; # Add $nodename to the level menu list
+
+ # Prepare things for next @SUB entry found
+ $levellast{$depth} = $lastnode = $nodename;
+ $lastdepth = $depth;
+ $nodedata{$uppernode}->{'menu'} = \@levelmenu;
+
+ } elsif ( s/^\@ENDSUB// ){
+ $depth--;
+ push @inputtext, $_;
+ } elsif (s/^\@LABEL\s+//){
+ # Keep record of node labels vs nodenames. Will use the last.
+ $labels{$_} = $lastnode;
+ } elsif (s/^\@title\s+//){
+ $docdata{'title'} = $_;
+ } elsif (/^\@ldt_endauthor/){
+ $inauthor = '';
+ my @authors;
+ if ( @$docdata{'authors'} ){
+ @authors = @$docdata{'authors'};
+ }
+ push @authors, $authorline;
+ $docdata{'authors'} = \@authors;
+ $authorline = "";
+ } elsif ( s/^\@author\s+// ){
+ $inauthor = 1;
+ $authorline = $_;
+ } elsif ( $inauthor ){
+ next if m/^\s*$/;
+ s/^\s+//;
+ $authorline .= " $_ ";
+ } elsif (s/^\@subtitle\s+//){
+ $docdata{'subtitle'} = $_;
+ } elsif (s/^\@ldt_translator\s+//){
+ $docdata{'translator'} = $_;
+ } elsif (s/^\@ldt_tdate\s+//){
+ $docdata{'tdate'} = $_;
+ } else {
+ push @inputtext, $_;
+ }
+ }
+ close $INPUT;
+
+ $docdata{'nodedata'} = \%nodedata;
+ $docdata{'labels'} = \%labels;
+ $docdata{'inputtext'} = \@inputtext;
+
+ return \%docdata;
+}
+
+# -------------------------------------------------------------------------
+sub info_write_preprocessed_file {
+# -------------------------------------------------------------------------
+# Write processed texinfo file. Add section names, menus, correct
+# references and title.
+# -------------------------------------------------------------------------
+ my $docdata = shift;
+ my $infoname = shift;
+ my $texiout = shift;
+
+ die "InfoUtils.pm: No info file name $infoname.\n" unless $infoname;
+ die "InfoUtils.pm: No output texi file $texiout\n" unless $texiout;
+
+ my $nodedata = $docdata->{'nodedata'};
+ my $labels = $docdata->{'labels'};
+ my $inputtext = $docdata->{'inputtext'};
+
+ my $OUTFILE;
+
+ # info_check_parsed_data($nodedata);
+
+ my %sections = ( 1 => "\@chapter",
+ 2 => "\@section",
+ 3 => "\@subsection",
+ 4 => "\@subsubsection");
+
+ my $lastdepth = 0;
+ my $lastnode = "Top";
+ my $texinfo = "\@c %** START OF HEADER
+\@setfilename $infoname
+\@c %** END OF HEADER\n";
+
+ foreach ( @$inputtext ) {
+ if ( s/^\@SUB\s+// ){
+ my $key = $_;
+ my $depth = $nodedata->{$key}->{'depth'};
+ my $name = $nodedata->{$key}->{'text'};
+
+ if ( $depth le 4 ){
+ my $next = $nodedata->{$key}->{'next'};
+ my $previous = $nodedata->{$key}->{'previous'};
+ my $up = $nodedata->{$key}->{'up'};
+ # my $txt = "\@comment nodename, next, previous, up\n";
+ my $txt = "";
+
+ # $txt .= "\@node $key, $previous, $next, $up\n";
+ $txt .= "\@node $key\n";
+ $txt .= "$sections{$depth} $name\n";
+
+ if ( $depth gt $lastdepth && defined $nodedata->{$lastnode}->{'menu'}){
+ $txt = "\n\@menu\n\* "
+ . join("::\n\* ",@{$nodedata->{$lastnode}->{'menu'}})
+ . "::\n\@end menu\n"
+ . "\n$txt";
+ }
+
+ $texinfo .= $txt;
+ $lastdepth = $depth;
+ $lastnode = $key;
+ } elsif ( $depth eq 5 ){
+ $texinfo .= "\@subsubheading $nodedata->{$key}->{'text'}\n";
+ } else {
+ die "info-postASP: Entry \"$key\" has wrong depth $depth\n";
+ }
+ } elsif (s/^\@REF\s+//){
+ if ( defined $labels->{$_} ){
+ # If this reference is to a node, use its nodename
+ $texinfo .= "\@ref{" . $labels->{$_} . "}\n";
+ } else {
+ $texinfo .= "\@ref{$_}\n";
+ }
+ } elsif (s/^\@TOP//){
+ $texinfo .= "\@node top\n"
+ . "\@top " . $docdata->{'title'} . "\n"
+ . "\@example\n";
+
+ $texinfo .= join(' and ',@{$docdata->{'authors'}}) . "\n"
+ if ( @{$docdata->{'authors'}} );
+
+ $texinfo .= $docdata->{'subtitle'} . "\n"
+ if ( defined $docdata->{'subtitle'} );
+
+ $texinfo .= $docdata->{'translator'} . "\n"
+ if ( defined $docdata->{'translator'} );
+
+ $texinfo .= $docdata->{'tdate'} . "\n"
+ if ( defined $docdata->{'tdate'} );
+
+ $texinfo .= "\@end example\n";
+ } else {
+ $texinfo .= "$_\n";
+ }
+ }
+
+ open ($OUTFILE, "> $texiout")
+ or die "Could not open \"$texiout\" for write. Aborting ...\n";
+ print $OUTFILE $texinfo;
+ close $OUTFILE;
+}
+
+# -------------------------------------------------------------------------
+sub info_check_parsed_data {
+# -------------------------------------------------------------------------
+# -------------------------------------------------------------------------
+ my $tmpnodedata = shift;
+ my @sections = sort {
+ $tmpnodedata->{$a}->{'sort'} <=> $tmpnodedata->{$b}->{'sort'}
+ } keys %$tmpnodedata;
+
+ foreach ( @sections ){
+ my $ref = $tmpnodedata->{$_};
+ print STDERR "Node: $_\n";
+ print STDERR " orig: $ref->{'orig'}\n";
+ print STDERR " text: $ref->{'text'}\n";
+ print STDERR " debug: $ref->{'debug'}\n";
+ print STDERR " up: $ref->{'up'}\n";
+ print STDERR " depth: $ref->{'depth'}\n";
+ print STDERR " previous: $ref->{'previous'}\n";
+ print STDERR " next: $ref->{'next'}\n";
+ print STDERR " sort: $ref->{'sort'}\n";
+ print STDERR " menu:\n * " . join("\n * ",@{$ref->{'menu'}}) . "\n" if defined $ref->{'menu'};
+ }
+}
+
+# -------------------------------------------------------------------------
+sub info_process_texi {
+# -------------------------------------------------------------------------
+# info_process_texi($infile, $outfile, $infoname)
+#
+# Call the other functions.
+# -------------------------------------------------------------------------
+ my $infile = shift;
+ my $outfile = shift;
+ my $infoname = shift;
+
+ info_write_preprocessed_file(info_parse_raw_file($infile),$infoname,$outfile);
+}
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Lang.pm b/tools/linuxdoc-tools/LinuxDocTools/Lang.pm
new file mode 100644
index 00000000..2b0e99d6
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Lang.pm
@@ -0,0 +1,238 @@
+#
+# Lang.pm
+#
+# $Id: Lang.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Language support.
+#
+# Copyright 1997, Cees de Groot
+#
+
+package LinuxDocTools::Lang;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT @Languages $translations);
+
+require 5.0004;
+use Exporter;
+use LinuxDocTools::Vars;
+
+$VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
+@ISA = qw(Exporter);
+@EXPORT = qw(Any2ISO ISO2Native ISO2English Xlat);
+
+=head1 NAME
+
+LinuxDocTools::Lang - language name and translation functions
+
+=head1 SYNOPSIS
+
+ $isoname = Any2ISO ('deutsch');
+ $native = ISO2Native ('de');
+ $engname = ISO2English ('nederlands');
+
+ $global->{language} = 'nl';
+ $dutch = Xlat ('Table of Contents');
+
+=head1 DESCRIPTION
+
+B<LinuxDocTools::Lang> gives a simple interface to various forms of language
+names, and provides a translation service. Languages can be specified in
+three different ways: by their native name, by their english name, and
+by their 2-letter ISO code. For example, you can specify the German
+language as C<deutsch>, as C<german> or as C<de>.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+@Languages = qw(
+ en english english
+ de deutsch german
+ nl nederlands dutch
+ fr franais french
+ es espaol spanish
+ da dansk danish
+ no norsk norwegian
+ se svenska swedish
+ pt portuges portuguese
+ ca catal catalan
+ it italiano italian
+ ro romn romanian
+ ja japanese japanese
+ pl polski polish
+ ko korean korean
+ fi suomi finnish
+);
+
+
+=item Any2ISO
+
+Maps any of the three forms of languages to the ISO name. So either of
+these invocations:
+
+ Any2ISO ('dutch');
+ Any2ISO ('nederlands');
+ Any2ISO ('nl');
+
+will return the string C<"nl">.
+
+=cut
+
+sub Any2ISO
+{
+ my $lang = shift (@_);
+
+ my $i = 0;
+ foreach my $l (@Languages)
+ {
+ ($l eq $lang) && last;
+ $i++;
+ }
+ return $Languages[(int $i / 3) * 3];
+}
+
+
+=item ISO2Native
+
+Maps the ISO code to the native name of the language.
+
+=cut
+
+sub ISO2Native
+{
+ my $iso = shift (@_);
+
+ my $i = 0;
+ foreach my $l (@Languages)
+ {
+ ($l eq $iso) && last;
+ $i++;
+ }
+ return $Languages[$i + 1];
+
+}
+
+
+=item ISO2English
+
+Maps the ISO code to the english name of the language.
+
+=cut
+
+sub ISO2English
+{
+ my $iso = shift (@_);
+
+ my $i = 0;
+ foreach my $l (@Languages)
+ {
+ ($l eq $iso) && last;
+ $i++;
+ }
+ return $Languages[$i + 2];
+}
+
+=item Xlat
+
+Translates its (English) argument to the language specified by the
+current value of C<$gobal-E<gt>{language}>. The module, in its source
+file, contains a data structure, indexed by the English strings, that
+has all available translations.
+
+=cut
+
+sub Xlat
+{
+ my ($txt) = @_;
+
+ return $txt if ($global->{language} eq "en");
+ return $translations->{$txt}{$global->{language}};
+};
+
+
+#
+# By the time this grows big, we'll make up something else.
+#
+$translations = {
+ "Previous" => {
+ "nl" => "Terug",
+ "de" => "Zurck",
+ "es" => "Pgina anterior",
+ "fr" => "Page prcdente",
+ "da" => "Forrige",
+ "no" => "Forrige",
+ "se" => "Fregende",
+ "pt" => "Pgina anterior",
+ "ca" => "Pgina anterior",
+ "it" => "Indietro",
+ "ro" => "napoi",
+ "ja" => "Υڡ",
+ "pl" => "Poprzedni",
+ "ko" => "",
+ "fi" => "Edellinen"
+ },
+ "Next" => {
+ "nl" => "Verder",
+ "de" => "Weiter",
+ "es" => "Pgina siguiente",
+ "fr" => "Page suivante",
+ "da" => "Nste",
+ "no" => "Neste",
+ "se" => "Nsta",
+ "pt" => "Pgina seguinte",
+ "ca" => "Pgina segent",
+ "it" => "Avanti",
+ "ro" => "nainte",
+ "ja" => "Υڡ",
+ "pl" => "Nastny",
+ "ko" => "",
+ "fi" => "Seuraava"
+ },
+ "Contents" => {
+ "nl" => "Inhoud",
+ "de" => "Inhalt",
+ "es" => "ndice general",
+ "fr" => "Table des matires",
+ "da" => "Indhold",
+ "no" => "Innhold",
+ "se" => "Innehllsfrteckning",
+ "pt" => "ndice",
+ "ca" => "ndex",
+ "it" => "Indice",
+ "ro" => "Cuprins",
+ "ja" => "ܼ",
+ "pl" => "Spis Trei",
+ "ko" => "",
+ "fi" => "Sisllys"
+ },
+ "Table of Contents" => {
+ "nl" => "Inhoudsopgave",
+ "de" => "Inhaltsverzeichnis",
+ "es" => "ndice general",
+ "fr" => "Table des matires",
+ "da" => "Indholdsfortegnelse",
+ "no" => "Innholdsfortegnelse",
+ "se" => "Innehllsfrteckning",
+ "pt" => "ndice geral",
+ "ca" => "ndex general",
+ "it" => "Indice Generale",
+ "ro" => "Cuprins",
+ "ja" => "ܼ",
+ "pl" => "Spis Trei",
+ "ko" => "",
+ "fi" => "Sisllysluettelo"
+ }
+};
+
+=back
+
+=head1 AUTHOR
+
+Cees de Groot, C<E<lt>cg@pobox.comE<gt>>
+
+=cut
+
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Utils.pm b/tools/linuxdoc-tools/LinuxDocTools/Utils.pm
new file mode 100644
index 00000000..63fe5f91
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Utils.pm
@@ -0,0 +1,392 @@
+#
+# Utils.pm
+#
+# $Id: Utils.pm,v 1.2 2001/08/31 22:39:44 sano Exp $
+#
+# Utilities, split off from other modules in order to cut down file size.
+#
+# Copyright 1996, 1997, Cees de Groot
+#
+package LinuxDocTools::Utils;
+use strict;
+
+=head1 NAME
+
+LinuxDocTools::Utils - various supporting routines
+
+=head1 SYNOPSIS
+
+ @files = process_options (@args);
+
+ usage ($msg);
+
+ trap_signals;
+
+ cleanup;
+
+ create_temp($tempfile)
+
+=head1 DESCRIPTION
+
+The B<LinuxDocTools::Utils> module contains a number of generic routines, mainly
+split off from the main module in order to keep file size down.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=cut
+
+use DirHandle;
+use FileHandle;
+use Cwd;
+use File::Basename;
+use Exporter;
+use LinuxDocTools::Vars;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $in_signal);
+@ISA = qw(Exporter);
+@EXPORT = qw(usage process_options);
+@EXPORT_OK = qw(cleanup trap_signals remove_tmpfiles create_temp);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/);
+
+use subs qw(usage);
+
+# check whether options are unique
+sub check_option_consistency
+{
+ my $owner = {};
+ my ($fmt, $opt);
+ foreach $fmt (keys %FmtList)
+ {
+ my $add = sub { # add to options of $fmt
+ my $str = shift;
+ if ($owner->{$str}) {
+ push(@{$owner->{$str}}, $fmt);
+ }
+ else {
+ $owner->{$str} = [$fmt];
+ }
+ };
+ foreach $opt (@{$Formats{$fmt}{OPTIONS}})
+ {
+ &$add("--$opt->{option}");
+ &$add("-$opt->{short}");
+ }
+ }
+ my $error = 0;
+ foreach $opt (keys %$owner)
+ {
+ if (scalar @{$owner->{$opt}} > 1)
+ {
+ warn "duplicate option: $opt in " .
+ join(', ', @{$owner->{$opt}}) . "\n";
+ $error = 1;
+ }
+ }
+ die "Internal error detected" if $error;
+}
+
+
+=item process_options
+
+This function processes the command line, and sets the variables associated
+with the options along the way. When successful, it returns the arguments
+on the command line it didn't interpret. Normally, this will be a list of
+filenames.
+
+=cut
+
+sub process_options
+{
+ my @args = @_;
+ my @retval;
+
+ OPTPROC: while ($args[0])
+ {
+ my $long;
+ my $curarg = $args[0];
+ if ($curarg =~ /^--.*/)
+ {
+ #
+ # Long option, --opt[==value]
+ #
+ $long = 1;
+ }
+ elsif ($curarg =~ /^-.*/)
+ {
+ #
+ # Short option, -o value
+ #
+ $long = 0;
+ }
+ else
+ {
+ #
+ # Filename
+ #
+ push @retval, $curarg;
+ next OPTPROC;
+ }
+
+ #
+ # Start looking for the option
+ #
+ foreach my $fmt (keys %FmtList)
+ {
+ foreach my $opt (@{$Formats{$fmt}{OPTIONS}})
+ {
+ if (($long && $curarg =~ /^--$opt->{option}.*/) ||
+ $curarg =~ /^-$opt->{short}/)
+ {
+ #
+ # Found it! Get the argument and see whether all is OK
+ # with the option.
+ #
+ my $optval = "";
+ if ($long)
+ {
+ if ($curarg =~ /^--$opt->{option}=.*/)
+ {
+ $optval = $curarg;
+ $optval =~ s/[^=]*=(.*)/$1/;
+ }
+ }
+ else
+ {
+ if ($args[1] =~ /^[^-].*/)
+ {
+ $optval = $args[1];
+ }
+ }
+ $opt->{type} eq "f" && do
+ {
+ #
+ # "f" -> flag. Increment, so '-v -v' can work.
+ #
+ $Formats{$fmt}{$opt->{option}} += 1;
+ next OPTPROC;
+ };
+ #
+ # All other types require a value (for now).
+ #
+ shift @args unless $long;
+ if ($optval eq "")
+ {
+ usage "Option $curarg: value required";
+ }
+ ($opt->{type} eq "i" || $opt->{type} eq "s") && do
+ {
+ #
+ # "i" -> numeric value.
+ # "s" -> string value.
+ #
+ # No type checking yet...
+ #
+ if ($opt->{option} eq "define")
+ {
+ $Formats{$fmt}{$opt->{option}} .= " " . $optval;
+ }
+ else
+ {
+ $Formats{$fmt}{$opt->{option}} = $optval;
+ }
+ next OPTPROC;
+ };
+ $opt->{type} eq "l" && do
+ {
+ #
+ # "l" -> list of values.
+ #
+ foreach my $val (@{$opt->{'values'}})
+ {
+ if ($val eq $optval)
+ {
+ $Formats{$fmt}{$opt->{option}} = $optval;
+ next OPTPROC;
+ }
+ }
+ usage "Invalid value '$optval' for '--$opt->{option}'";
+ };
+ usage "Unknown option type $opt->{type} in $fmt/$opt";
+ }
+ }
+ }
+ usage "Unknown option $curarg";
+ }
+ continue
+ {
+ shift @args;
+ }
+ return @retval;
+}
+
+
+=item usage
+
+Prints out a generated help message about calling convention and allowed
+options, then the argument string, and finally exits.
+
+=cut
+
+sub usage
+{
+ my ($msg) = @_;
+
+ print "LinuxDoc-Tools version " . `cat $main::DataDir/VERSION` . "\n";
+ check_option_consistency;
+ print "Usage:\n";
+ print " " . $global->{myname} . " [options] <infile>\n\n";
+ my @helplist = sort(keys %Formats);
+ @helplist = sort (keys %FmtList) if ($global->{format});
+ foreach my $fmt (@helplist)
+ {
+ if ($fmt eq "global")
+ {
+ print "General options:\n";
+ }
+ else
+ {
+ print "Format: " . $fmt . "\n";
+ }
+ print $Formats{$fmt}{HELP};
+ for my $opt (@{$Formats{$fmt}{OPTIONS}})
+ {
+ my $value = '';
+ if ($opt->{type} eq "i")
+ {
+ $value = "number";
+ }
+ elsif ($opt->{type} eq "l")
+ {
+ $value = "{";
+ my $first = 1;
+ for my $val (@{$opt->{'values'}})
+ {
+ $first || ($value .= ",");
+ $first = 0;
+ $value .= $val;
+ }
+ $value .= "}";
+ }
+ elsif ($opt->{type} eq "s")
+ {
+ $value = "string";
+ }
+ print " --$opt->{option}"; print "=$value" if $value;
+ print " -$opt->{short}"; print " $value" if $value;
+ print "\n";
+ }
+ print "\n";
+ }
+
+ $msg && print "Error: $msg\n\n";
+ exit 1;
+}
+
+
+=item cleanup
+
+This function cleans out all temporary files and exits. The unlink step
+is skipped if debugging is turned on.
+
+=cut
+
+sub cleanup
+{
+ my ($signame) = @_;
+
+ if( $signame ) {
+ if ( $in_signal ) {
+ if( $global->{debug} ) {
+ print STDERR "Caught SIG$signame during cleanup -- aborting\n";
+ }
+ exit -1;
+ }
+ else {
+ if( $global->{debug} ) {
+ print STDERR "Caught SIG$signame -- cleaning up\n";
+ }
+ $in_signal = 1;
+ }
+ }
+
+ if( !$global->{debug} && $global->{tmpbase} ) {
+ remove_tmpfiles($global->{tmpbase});
+ }
+ exit 0;
+}
+
+=item remove_tmpfiles( $tmpbase )
+
+This function cleans out all temporary files, using the argument $tmpbase to
+determine the directory and pattern to use to find the temporary files.
+
+=cut
+
+sub remove_tmpfiles($) {
+ my $tmpbase = shift;
+ my ($name,$tmpdir) = fileparse($tmpbase,"");
+ my $namelength = length $name;
+ my $savdir = cwd;
+
+ chdir($tmpdir);
+ my $dir = new DirHandle(".");
+
+ if (!defined($dir) ) {
+ warn "Couldn't open temp directory $tmpdir: $!\n";
+ } else {
+ foreach my $tmpfile ($dir->read()) {
+ if (substr ($tmpfile, 0, $namelength) eq $name) {
+ unlink ($tmpfile) || warn "Couldn't unlink $tmpfile: $! \n";
+ }
+ }
+ $dir->close();
+ }
+
+ chdir($savdir);
+ rmdir($tmpdir) || return -1;
+}
+
+=item trap_signals
+
+This function traps all known signals, making sure that the B<cleanup>
+function is executed on them. It should be called once at initialization
+time.
+
+=cut
+
+sub trap_signals
+{
+ foreach my $sig ( 'HUP', 'INT', 'QUIT', 'ILL',
+ 'TRAP', 'IOT', 'BUS', 'FPE',
+ 'USR1', 'SEGV', 'USR2',
+ 'PIPE', 'ALRM', 'TERM', )
+ {
+ $SIG{$sig} = \&cleanup;
+ }
+}
+
+=item create_temp ( $tmpfile )
+
+This function creates an empty temporary file with the required
+permission for security reasons.
+
+=cut
+
+sub create_temp($) {
+ my $tmpnam = shift;
+ my $fh = new FileHandle($tmpnam,O_CREAT|O_EXCL|O_WRONLY,0600);
+ $fh or die "$0: failed to create temporary file: $!";
+ $fh->close;
+}
+
+=back
+
+=head1 AUTHOR
+
+Cees de Groot, C<E<lt>cg@pobox.comE<gt>>.
+
+=cut
+
+1;
diff --git a/tools/linuxdoc-tools/LinuxDocTools/Vars.pm b/tools/linuxdoc-tools/LinuxDocTools/Vars.pm
new file mode 100644
index 00000000..49cf630b
--- /dev/null
+++ b/tools/linuxdoc-tools/LinuxDocTools/Vars.pm
@@ -0,0 +1,22 @@
+#
+# Vars.pm
+#
+# $Id: Vars.pm,v 1.1.1.1 2001/05/24 15:57:41 sano Exp $
+#
+# Shared variables.
+#
+# Copyright 1996, 1997, Cees de Groot
+#
+package LinuxDocTools::Vars;
+use strict;
+
+use Exporter;
+
+use vars qw($VERSION @ISA @EXPORT);
+@ISA = qw(Exporter);
+@EXPORT = qw(%Formats $global %FmtList);
+$VERSION = sprintf("%d.%02d", q$Revision: 1.1.1.1 $ =~ /(\d+)\.(\d+)/);
+
+use vars @EXPORT;
+
+1;
diff --git a/tools/linuxdoc-tools/Text/EntityMap.pm b/tools/linuxdoc-tools/Text/EntityMap.pm
new file mode 100644
index 00000000..d878fa3c
--- /dev/null
+++ b/tools/linuxdoc-tools/Text/EntityMap.pm
@@ -0,0 +1,121 @@
+# -*- perl -*-
+#
+# Copyright (C) 1996 Ken MacLeod
+# See the file COPYING for distribution terms.
+#
+# This file is preprocessed during the build to fix-up the references
+# in `sdata_dirs'.
+#
+# $Id: EntityMap.pm.in,v 1.1.1.1 2001/05/24 15:57:40 sano Exp $
+#
+
+package Text::EntityMap;
+
+use strict;
+
+=head1 NAME
+
+Text::EntityMap - map character entities to output formats
+
+=head1 SYNOPSIS
+
+use Text::EntityMap;
+
+$tex_iso_lat1 = Text::EntityMap->load ("ISOlat1.2tex");
+$tex_iso_lat2 = Text::EntityMap->load ("ISOlat2.2tex");
+$ent_group = Text::EntityMap->group ($tex_iso_lat1, $tex_iso_lat2);
+
+$ent_group->lookup ('[copy ]');
+
+@dirs = Text::EntityMap->sdata_dirs ();
+
+=head1 DESCRIPTION
+
+Text::EntityMap is a module that can look-up an output-format
+equivalent for special character or other entities. This was inspired
+by SGML character entities but can be used in any scenario where
+output formatting codes are different for special characters.
+
+The C<load()> function takes a file name of a mapping table and
+returns an Text::EntityMap object.
+
+The C<group()> function takes a ordered list of Text::EntityMap and
+returns an Text::EntityMapGroup object. Looking up entities in a
+group object returns the entity replacement returned by the first
+EntityMap object. This can be used both to group sets of mapping
+files into one object as well as overriding entity replacements. A
+EntityMapGroup may contain other EntityMapGroup's.
+
+The C<lookup()> function can be used with either a EntityMap or
+EntityMapGroup object. It takes an entity name and returns the
+output-format equivalent.
+
+C<sdata_dirs()> returns an array containing the local site directory
+and ``this'' version of EntityMap's installed directory that contain
+the entity maps. Callers can use these paths when looking for tables
+to pass to C<load()>.
+
+=head1 AUTHOR
+
+Ken MacLeod E<lt>ken@bitsko.slc.ut.usE<gt>
+
+=cut
+
+sub sdata_dirs {
+ return ("/usr/share/entity-map", "/usr/share/entity-map/0.1.0");
+}
+
+sub load {
+ my ($type, $file_name) = @_;
+
+ my ($self) = {};
+ bless ($self, $type);
+
+ open (FILE, "$file_name")
+ || die "Can't open \`$file_name' for reading: $!\n";
+ while (<FILE>) {
+ chop;
+ m/(^[^\t]+)\t(.*)/;
+ $self->{"$1"} = $2;
+ }
+ close (FILE);
+
+ return ($self);
+}
+
+sub group {
+ my ($type) = shift;
+
+ my ($self) = [{}, @_];
+ bless ($self, 'Text::EntityMapGroup');
+
+ return ($self);
+}
+
+sub lookup {
+ my ($self, $entity) = @_;
+
+ return ($self->{$entity});
+}
+
+package Text::EntityMapGroup;
+
+sub lookup {
+ my ($self, $entity) = @_;
+
+ my ($replacement) = $self->[0]{$entity};
+ return $replacement if defined $replacement;
+
+ my ($ii);
+ for ($ii = 1; $ii <= $#{$self}; $ii ++) {
+ $replacement = $self->[$ii]->lookup($entity);
+ if (defined $replacement) {
+ $self->[0]{$entity} = $replacement;
+ return ($replacement);
+ }
+ }
+
+ return (undef);
+}
+
+1;
diff --git a/tools/linuxdoc-tools/copyright b/tools/linuxdoc-tools/copyright
new file mode 100644
index 00000000..a89b6ada
--- /dev/null
+++ b/tools/linuxdoc-tools/copyright
@@ -0,0 +1,85 @@
+
+This is `linuxdoc-tools', a series of tools to implement the Linux
+Documentation Project HOWTO and book styles in SGML.
+
+This copy was modified in order to work with birddoc DTD. It is
+based on version 0.9.73-2 from Debian 10.
+
+
+----------------------------------
+ The linuxdoc-tools license
+----------------------------------
+
+linuxdoc-tools is derived from linuxdoc-SGML, originally written by
+Matt Welsh and later maintained by Cees de Groot. Linuxdoc-SGML is
+based on James Clark's sgmls parser, and the QWERTZ DTD by Tom
+Gordon. Magnus Alvestad provided the current HTML support. For
+the rest of linuxdoc-SGML,
+
+ Copyright (C) 1994-1996 Matt Welsh <mdw@cs.cornell.edu>
+ Copyright (C) 1996-1998 Cees de Groot <cg@pobox.com>
+
+Original Linuxdoc-SGML itself does not have any limitations.
+Everything not having explicit additional conditions can be freely
+used, modified, and redistributed, under the usual fair use clauses:
+
+ * No warranty. Use at your own risk.
+ * Do not pretend to have written what you did not (Preserve credits
+ and Copyright notices of the different elements if present).
+
+Since then, lots of smaller and bigger changes resulted in a rename
+to SGML-Tools (and then to SGMLtools, the hyphen caused confusion)
+to indicate that it wasn't just for Linux anymore. See files
+CHANGES.old-v1 and CONTRIBUTORS.old-v1 for changelog and list of
+contributors to old linuxdoc-sgml and sgmltools-v1.
+
+When sgml-tools dropped support for the linuxdoc DTD, Taketoshi Sano
+<sano@debian.org> forked the code to linuxdoc-tools. See README file.
+
+Changes after the fork
+
+ Copyright (C) 1999-2002 Taketoshi Sano <sano@debian.org>
+ Copyright (C) 2000 Juan Jose Amor
+ Copyright (C) 2007-2018 Agustin Martin Domingo <agmartin@debian.org>
+
+Unless conflicting with other licenses, changes by Agustin Martin
+Domingo are free software: you can redistribute and/or modify them
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version. Otherwise they honour previous
+license.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+In Debian systems you can find a copy under /usr/share/common-licenses.
+
+
+----------------------------------
+ The entity-map license
+----------------------------------
+
+Copyright (C) 1997 Ken MacLeod
+
+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 KEN MACLEOD BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Ken MacLeod shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from
+Ken MacLeod.
diff --git a/tools/make-dev-archive b/tools/make-dev-archive
new file mode 100755
index 00000000..caaee121
--- /dev/null
+++ b/tools/make-dev-archive
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# This a modified version of gendist script which generates development
+# archive (tarball) without docs from current sources.
+
+BIRD_VERSION=`grep 'BIRD_VERSION \"' sysdep/config.h | sed '/BIRD_VERSION/!d;s/^.*"\(.*\)"$/\1/'`
+# differentiate dev tarballs from upstream ones
+GIT_HASH=$(git rev-parse --short HEAD )
+TIMESTAMP=$(date -u +'%s' 2>/dev/null)
+VERSION=$BIRD_VERSION.$TIMESTAMP.$GIT_HASH
+
+REL=bird-$VERSION
+T=/tmp/bird
+
+set -e
+
+# prepare output dir
+rm -rf $T/$REL $T/$REL.tar.gz
+mkdir -p $T
+
+echo Building $REL
+git archive --format=tar --prefix=$REL/ HEAD | (cd $T && tar xf -)
+echo Running autoreconf
+( cd $T/$REL ; autoreconf ; rm -rf autom4te*cache )
+echo Generating ChangeLog
+git log >$T/$REL/ChangeLog
+rm -f $T/$REL/bird.conf*
+rm -rf $T/$REL/misc $T/$REL/doc/slides $T/$REL/doc/slt2001 $T/$REL/doc/old
+( cd $T ; tar czf $REL.tar.gz $REL )
+rm -rf $T/$REL
+
+echo $T/$REL.tar.gz
diff --git a/tools/make-obs b/tools/make-obs
new file mode 100755
index 00000000..aeec70ad
--- /dev/null
+++ b/tools/make-obs
@@ -0,0 +1,46 @@
+#!/bin/bash
+# create OpenSUSE Build System (OBS) source package
+#
+# this needs to be run on a (Debian-based) system with:
+#
+# * apkg
+# * dpkg-buildpackage
+#
+# run from project root containing distro/ dir:
+#
+# ./tools/make-obs [path/to/archive.tar.gz]
+#
+# supply archives as optional arguments to build from,
+# otherwise archive will be built from sources by apkg
+#
+# output at ./pkg/obs/ (removed on each run)
+set -o errexit -o nounset
+
+OUTDIR="pkg/obs"
+APKG_OPTS="-O $OUTDIR"
+
+if [ -z $@ ]; then
+ echo "building OBS srcpkg from project files"
+else
+ AR=$1
+ echo "building OBS srcpkg from specified archive(s)"
+ APKG_OPTS="-a $AR $APKG_OPTS"
+fi
+
+if [ -n "$RELEASE" ]; then
+ echo "custom release: $RELEASE"
+ APKG_OPTS="-r $RELEASE $APKG_OPTS"
+fi
+
+set -o xtrace
+: removing existing output files at output dir: $OUTDIR
+rm -rf "$OUTDIR"
+: making debian source package from archive
+apkg srcpkg $APKG_OPTS -d debian
+: removing extra debian source package files
+rm -f $OUTDIR/*_source.*
+: rendering RPM template
+apkg srcpkg $APKG_OPTS -d fedora --render-template
+: fixing RPM .spec to use debian source archive
+sed -i 's/^\(Source0:\s\+\).*/\1bird2_%{version}.orig.tar.gz/' $OUTDIR/*.spec
+echo "OBS srcpkg ready at: $OUTDIR"