OpenBSD src changes summary for 2017-08-21
==========================================

distrib/sets                            distrib/syspatch
etc/mtree/4.4BSD.dist                   etc/rc
etc/signify/openbsd-59-base.pub         etc/signify/openbsd-59-fw.pub
etc/signify/openbsd-59-pkg.pub          etc/signify/openbsd-63-base.pub
gnu/usr.bin/cvs                         lib/libfuse
lib/libssl                              libexec/reorder_kernel
sbin/slaacd                             share/man
sys/arch/armv7/stand/efiboot            sys/arch/i386/i386
sys/arch/i386/include                   sys/dev/fdt
sys/dev/ic                              sys/dev/usb
sys/kern                                usr.bin/calendar
usr.bin/cvs                             usr.bin/m4
usr.bin/mandoc                          usr.bin/passwd
usr.bin/sendbug                         usr.bin/time
usr.bin/tmux                            usr.bin/tput
usr.bin/xinstall                        usr.sbin/bgpd
usr.sbin/ifstated                       usr.sbin/radiusd

== distrib =========================================================== 01/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/distrib

sets

  ~ lists/comp/mi                         

  > sync (jsg@)

  ~ lists/base/mi                         ~ lists/comp/mi

  > sync (deraadt@)

  ~ lists/base/mi                         

  > Move the kernel relinking code from /etc/rc into a seperate script
  > /usr/libexec/reorder_kernel. Requested by ajacoutot@ to be able to
  > relink the kernel from within syspatch(8).
  > OK deraadt@ tb@ (rpe@)

syspatch

  + README                                

  > The syspatch(8) build system will eventually be properly documented in its
  > own
  > man(1) page but until things settle and the framework is robust, this file
  > will
  > be used as a quick reminder.
  > ok robert@ (ajacoutot@)

  ~ diff.sh                               

  > Catch non existent files (in case a syspatch would _add_ a new file).
  > (ajacoutot@)

  ~ bsd.syspatch.mk                       

  > Kernel syspatches will now only contain the differing object files.
  > The syspatch(8) utility will be modified accordingly to relink the kernel
  > at the
  > end of its run (not done yet, still WIP). That will give us KARL and much
  > smaller patches.
  > Idea from deraadt@
  > OK robert@ (ajacoutot@)

  ~ bsd.syspatch.mk                       

  > No need to explicitely add patch.sig to the plist, diff.sh will now pick it
  > up properly. (ajacoutot@)

  ~ diff.sh                               

  > Add a comment about why we need to ignore the timestamps on perl man pages
  > (Pod::Man adds the current date to the manuals).
  > ok robert@ (ajacoutot@)

== etc =============================================================== 02/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/etc

mtree/4.4BSD.dist

  ~ mtree/4.4BSD.dist                     

  > add basedir of the kernel link-kit
  > requested by ajacoutot@
  > OK tb@ (rpe@)

rc

  ~ rc                                    

  > Move the kernel relinking code from /etc/rc into a seperate script
  > /usr/libexec/reorder_kernel. Requested by ajacoutot@ to be able to
  > relink the kernel from within syspatch(8).
  > OK deraadt@ tb@ (rpe@)

signify/openbsd-59-base.pub

  - signify/openbsd-59-base.pub           

  > 5.9 pubkeys no longer needed (deraadt@)

signify/openbsd-59-fw.pub

  - signify/openbsd-59-fw.pub             

  > 5.9 pubkeys no longer needed (deraadt@)

signify/openbsd-59-pkg.pub

  - signify/openbsd-59-pkg.pub            

  > 5.9 pubkeys no longer needed (deraadt@)

signify/openbsd-63-base.pub

  + signify/openbsd-63-base.pub           

  > add 6.3 base key (deraadt@)

== gnu =============================================================== 03/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/gnu

usr.bin/cvs

  ~ src/client.c                          

  > When executing ssh, use "--" to indicate end of arguments before the
  > host name.  Adapted from a MirBSD diff by Thorsten Glaser. (millert@)

== lib =============================================================== 04/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib

libfuse

  ~ fuse.c                                

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

libssl

  ~ man/SSL_CTX_add_session.3             

  > Delete non-existent functions SSL_add_session() and SSL_remove_session()
  > and
  > clarify that SSL_CTX_remove_session(3) marks the session as non-resumable.
  > From Rich Salz <rsalz at openssl dot org>
  > via OpenSSL commit 1722496f Jun 8 15:18:38 2017 -0400
  > and from Matt Caswell <matt at openssl dot org>
  > via OpenSSL commit b8964668 Apr 26 15:16:18 2017 +0100. (schwarze@)

  ~ man/SSL_CTX_flush_sessions.3          

  > Delete non-existent function SSL_flush_sessions();
  > from Rich Salz <rsalz at openssl dot org>
  > via OpenSSL commit 1722496f Jun 8 15:18:38 2017 -0400. (schwarze@)

  ~ man/SSL_CTX_set_alpn_select_cb.3      

  > Mention three functions related to protocol selection by the client
  > that are deprecated no-ops in LibreSSL, but that OpenSSL explicitly
  > documented on April 19, 2017, without deprecating them. (schwarze@)

  ~ man/SSL_CTX_set_msg_callback.3        

  > Selectively merge OpenSSL commit e091367d May 5 11:56:45 2017 +0100
  > from Matt Caswell <matt at openssl dot org>.
  > In particular, stop talking about SSL 2.0 and SSL 3.0,
  > but do not start talking about TLS 1.3 just yet. (schwarze@)

  ~ man/SSL_CTX_set_tlsext_servername_callback.3

  > merge the applicable parts of SSL_set_tlsext_host_name(3) documentation;
  > from Paul Yang <yang dot yang at baishancloud dot com>
  > via OpenSSL commit 190b9a03 Jun 28 15:46:13 2017 +0800 (schwarze@)

  ~ man/Makefile                          ~ man/ssl.3
  + man/SSL_export_keying_material.3      

  > import SSL_export_keying_material(3) from OpenSSL (schwarze@)

== libexec =========================================================== 05/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/libexec

reorder_kernel

  + Makefile                              + reorder_kernel.sh

  > Move the kernel relinking code from /etc/rc into a seperate script
  > /usr/libexec/reorder_kernel. Requested by ajacoutot@ to be able to
  > relink the kernel from within syspatch(8).
  > OK deraadt@ tb@ (rpe@)

== sbin ============================================================== 06/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sbin

slaacd

  ~ engine.c                              ~ slaacd.c
  ~ slaacd.h                              

  > Move sin6_to_str() to slaacd.c so that it can be used in more
  > places. While here do not compile it for the ramdisk. (florian@)

  ~ frontend.c                            

  > s/xflagssock/ioctlsock/ since the socket is (going to be) used for
  > more. (florian@)

== share ============================================================= 07/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/share

man

  ~ man9/rasops.9                         

  > Document the newly introduced RI_ROTATE_CCW flag.
  > OK kettenis@ (fcambus@)

== sys =============================================================== 08/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys

arch/armv7/stand/efiboot

  ~ conf.c                                ~ efiboot.c

  > Pass the address of the EFI system table and the EFI memory map through
  > properties in the /chosen node of the FDT.  The properties match the ones
  > used by Linux (see Documentation/arm/uefi.txt in the Linux kernel source
  > tree) but with the "linux," prefix replaced by "openbsd,".
  > While there, reduce the diffs to the arm64 efiboot.
  > ok tom@, jsg@ (kettenis@)

arch/i386/i386

  ~ vmm.c                                 

  > vmm (i386): Move CPUID masks to vmmvar.h
  > My previous commit to restrict vm migration broke vmd for i386. This fixes
  > it.
  > ok mlarkin@ (pd@)

arch/i386/include

  ~ vmmvar.h                              

  > vmm (i386): Move CPUID masks to vmmvar.h
  > My previous commit to restrict vm migration broke vmd for i386. This fixes
  > it.
  > ok mlarkin@ (pd@)

dev/fdt

  ~ rkclock.c                             ~ rkclock_clocks.h

  > Add RK3399 CPU core related clocks.  Fix RK3399 SD/MMC controller clock.
  > For now, expose the clock speed of the Cortex-A53 cores through the
  > hw.cupseed sysctl. (kettenis@)

dev/ic

  ~ rtwn.c                                

  > Fix the build when RTWN_DEBUG is defined.
  > ok kettenis@ stsp@ (jsg@)

  ~ ahci.c                                ~ ahcivar.h

  > Split up ahci_port_portreset into a few smaller bits, and also slightly
  > adjust port multiplier detection so it doesn't call ahci_port_portreset
  > again directly, but instead restarts the loop for the current call.
  > During attach, poll for device detection across all ports until either all
  > ports have detected a device, or one second has passed, rather than doing
  > them sequentially.  Devices are still attached in order of port number,
  > so disk unit numbers won't change.
  > ok visa@ (jmatthew@)

dev/usb

  ~ uvideo.c                              

  > Fix off by one in array bounds tests when parsing descriptors.
  > Coverity CIDs 1452970 1453305. (jsg@)

kern

  ~ kern_pledge.c                         

  > Allow SIOCGIFAFLAG_IN6 and SIOCGIFALIFETIME_IN6 ioctls with
  > pledge("route"). These are read only and expose only minimal kernel
  > code.
  > slaacd(8) needs this on startup and when an interface gains the
  > autoconf6 flag to get lifetime and autoconf information about already
  > configured addresses.
  > OK deraadt (florian@)

== usr.bin =========================================================== 09/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin

calendar

  ~ io.c                                  

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

cvs

  ~ client.c                              

  > When executing ssh, use "--" to indicate end of arguments before the
  > host name.  Adapted from a MirBSD diff by Thorsten Glaser. (millert@)

m4

  ~ gnum4.c                               

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

mandoc

  ~ main.c                                

  > When the stdout stream gets broken, there is no point in reading
  > any more input files, and it would be misleading to start a parser,
  > because that would show randomly truncated text.
  > Instead, print an error message and exit the program.
  > Issue found by Leah Neukirchen <leah at vuxu dot org>, who was
  > surprised to see half a manpage when her /tmp/ overflew. (schwarze@)

passwd

  ~ pwd_check.c                           

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

sendbug

  ~ sendbug.c                             

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

time

  ~ time.c                                

  > Minor cleanup, joint work with Scott Cheloha <scottcheloha at gmail dot
  > com>:
  > * Delete bogus error message and correct exit status when dying from
  > SIGKILL.
  > * Prefer warn(3) over perror(3) for clarity.
  > * Return from main() rather than exit(3).
  > * Simplify kill(getpid(), ...) to raise(...).
  > * Drop obvious /* NOTREACHED */.
  > No objections raised when shown on tech@. (schwarze@)

tmux

  ~ tty.c                                 

  > Do not emit \r\n to move to column 0 if there are margins, because it
  > will instead move to the margin left. (nicm@)

  ~ tty.c                                 

  > Same as previous for \r alone. (nicm@)

tput

  ~ tput.c                                

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

xinstall

  ~ xinstall.c                            

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

== usr.sbin ========================================================== 10/10 ==

  http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.sbin

bgpd

  ~ Makefile                              ~ parse.y
  ~ pfkey.c                               

  > /*      $OpenBSD: parse.y,v 1.314 2017/08/12 16:47:50 phessler Exp $ */
  > /*
  > * Copyright (c) 2002, 2003, 2004 Henning Brauer <[email protected]>
  > * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  > * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
  > * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
  > * Copyright (c) 2016 Job Snijders <[email protected]>
  > * Copyright (c) 2016 Peter Hessler <[email protected]>
  > *
  > * Permission to use, copy, modify, and distribute this software for any
  > * purpose with or without fee is hereby granted, provided that the above
  > * copyright notice and this permission notice appear in all copies.
  > *
  > * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  > * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  > * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  > * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  > * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  > * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  > * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  > */
  > %{
  > #include <sys/types.h>
  > #include <sys/socket.h>
  > #include <sys/stat.h>
  > #include <sys/un.h>
  > #include <netinet/in.h>
  > #include <netinet/ip_ipsp.h>
  > #include <arpa/inet.h>
  > #include <netmpls/mpls.h>
  > #include <ctype.h>
  > #include <err.h>
  > #include <unistd.h>
  > #include <errno.h>
  > #include <limits.h>
  > #include <stdarg.h>
  > #include <stdio.h>
  > #include <string.h>
  > #include <syslog.h>
  > #include "bgpd.h"
  > #include "mrt.h"
  > #include "session.h"
  > #include "rde.h"
  > #include "log.h"
  > TAILQ_HEAD(files, file)          files = TAILQ_HEAD_INITIALIZER(files);
  > static struct file {
  > TAILQ_ENTRY(file)        entry;
  > FILE                    *stream;
  > char                    *name;
  > int                      lineno;
  > int                      errors;
  > } *file, *topfile;
  > struct file     *pushfile(const char *, int);
  > int              popfile(void);
  > int              check_file_secrecy(int, const char *);
  > int              yyparse(void);
  > int              yylex(void);
  > int              yyerror(const char *, ...)
  > __attribute__((__format__ (printf, 1, 2)))
  > __attribute__((__nonnull__ (1)));
  > int              kw_cmp(const void *, const void *);
  > int              lookup(char *);
  > int              lgetc(int);
  > int              lungetc(int);
  > int              findeol(void);
  > TAILQ_HEAD(symhead, sym)         symhead = TAILQ_HEAD_INITIALIZER(symhead);
  > struct sym {
  > TAILQ_ENTRY(sym)         entry;
  > int                      used;
  > int                      persist;
  > char                    *nam;
  > char                    *val;
  > };
  > int              symset(const char *, const char *, int);
  > char            *symget(const char *);
  > static struct bgpd_config       *conf;
  > static struct network_head      *netconf;
  > static struct peer              *peer_l, *peer_l_old;
  > static struct peer              *curpeer;
  > static struct peer              *curgroup;
  > static struct rdomain           *currdom;
  > static struct filter_head       *filter_l;
  > static struct filter_head       *peerfilter_l;
  > static struct filter_head       *groupfilter_l;
  > static struct filter_rule       *curpeer_filter[2];
  > static struct filter_rule       *curgroup_filter[2];
  > static u_int32_t                 id;
  > struct filter_rib_l {
  > struct filter_rib_l     *next;
  > char                     name[PEER_DESCR_LEN];
  > };
  > struct filter_peers_l {
  > struct filter_peers_l   *next;
  > struct filter_peers      p;
  > };
  > struct filter_prefix_l {
  > struct filter_prefix_l  *next;
  > struct filter_prefix     p;
  > };
  > struct filter_prefixlen {
  > enum comp_ops           op;
  > int                     len_min;
  > int                     len_max;
  > };
  > struct filter_as_l {
  > struct filter_as_l      *next;
  > struct filter_as         a;
  > };
  > struct filter_match_l {
  > struct filter_match      m;
  > struct filter_prefix_l  *prefix_l;
  > struct filter_as_l      *as_l;
  > } fmopts;
  > struct peer     *alloc_peer(void);
  > struct peer     *new_peer(void);
  > struct peer     *new_group(void);
  > int              add_mrtconfig(enum mrt_type, char *, int, struct peer *,
  > char *);
  > int              add_rib(char *, u_int, u_int16_t);
  > struct rde_rib  *find_rib(char *);
  > int              get_id(struct peer *);
  > int              merge_prefixspec(struct filter_prefix_l *,
  > struct filter_prefixlen *);
  > int              expand_rule(struct filter_rule *, struct filter_rib_l *,
  > struct filter_peers_l *, struct filter_match_l *,
  > struct filter_set_head *);
  > int              str2key(char *, char *, size_t);
  > int              neighbor_consistent(struct peer *);
  > int              merge_filterset(struct filter_set_head *, struct
  > filter_set *);
  > void             copy_filterset(struct filter_set_head *,
  > struct filter_set_head *);
  > void             merge_filter_lists(struct filter_head *, struct
  > filter_head *);
  > struct filter_rule      *get_rule(enum action_types);
  > int              getcommunity(char *);
  > int              parsecommunity(struct filter_community *, char *);
  > int64_t          getlargecommunity(char *);
  > int              parselargecommunity(struct filter_largecommunity *, char
  > *);
  > int              parsesubtype(char *, int *, int *);
  > int              parseextvalue(char *, u_int32_t *);
  > int              parseextcommunity(struct filter_extcommunity *, char *,
  > char *);
  > typedef struct {
  > union {
  > int64_t                  number;
  > char                    *string;
  > struct bgpd_addr         addr;
  > u_int8_t                 u8;
  > struct filter_rib_l     *filter_rib;
  > struct filter_peers_l   *filter_peers;
  > struct filter_match_l    filter_match;
  > struct filter_prefix_l  *filter_prefix;
  > struct filter_as_l      *filter_as;
  > struct filter_set       *filter_set;
  > struct filter_set_head  *filter_set_head;
  > struct {
  > struct bgpd_addr        prefix;
  > u_int8_t                len;
  > }                       prefix;
  > struct filter_prefixlen prefixlen;
  > struct {
  > u_int8_t                enc_alg;
  > char                    enc_key[IPSEC_ENC_KEY_LEN];
  > u_int8_t                enc_key_len;
  > }                       encspec;
  > } v;
  > int lineno;
  > } YYSTYPE;
  > %}
  > %token  AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE
  > %token  RDOMAIN RD EXPORTTRGT IMPORTTRGT
  > %token  RDE RIB EVALUATE IGNORE COMPARE
  > %token  GROUP NEIGHBOR NETWORK
  > %token  EBGP IBGP
  > %token  LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
  > %token  ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY
  > %token  DEMOTE ENFORCE NEIGHBORAS REFLECTOR DEPEND DOWN
  > %token  DUMP IN OUT SOCKET RESTRICTED
  > %token  LOG ROUTECOLL TRANSPARENT
  > %token  TCP MD5SIG PASSWORD KEY TTLSECURITY
  > %token  ALLOW DENY MATCH
  > %token  QUICK
  > %token  FROM TO ANY
  > %token  CONNECTED STATIC
  > %token  COMMUNITY EXTCOMMUNITY LARGECOMMUNITY
  > %token  PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN MAXASSEQ
  > %token  SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
  > %token  PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN
  > %token  ERROR INCLUDE
  > %token  IPSEC ESP AH SPI IKE
  > %token  IPV4 IPV6
  > %token  QUALIFY VIA
  > %token  NE LE GE XRANGE LONGER
  > %token  <v.string>              STRING
  > %token  <v.number>              NUMBER
  > %type   <v.number>              asnumber as4number as4number_any optnumber
  > %type   <v.number>              espah family restart origincode nettype
  > %type   <v.number>              yesno inout restricted
  > %type   <v.string>              string
  > %type   <v.addr>                address
  > %type   <v.prefix>              prefix addrspec
  > %type   <v.u8>                  action quick direction delete
  > %type   <v.filter_rib>          filter_rib_h filter_rib_l filter_rib
  > %type   <v.filter_peers>        filter_peer filter_peer_l filter_peer_h
  > %type   <v.filter_match>        filter_match filter_elm filter_match_h
  > %type   <v.filter_as>           filter_as filter_as_l filter_as_h
  > %type   <v.filter_as>           filter_as_t filter_as_t_l filter_as_l_h
  > %type   <v.prefixlen>           prefixlenop
  > %type   <v.filter_set>          filter_set_opt
  > %type   <v.filter_set_head>     filter_set filter_set_l
  > %type   <v.filter_prefix>       filter_prefix filter_prefix_l
  > filter_prefix_h
  > %type   <v.filter_prefix>       filter_prefix_m
  > %type   <v.u8>                  unaryop equalityop binaryop filter_as_type
  > %type   <v.encspec>             encspec
  > %%
  > grammar         : /* empty */
  > | grammar '\n'
  > | grammar include '\n'
  > | grammar conf_main '\n'
  > | grammar varset '\n'
  > | grammar rdomain '\n'
  > | grammar neighbor '\n'
  > | grammar group '\n'
  > | grammar filterrule '\n'
  > | grammar error '\n'            { file->errors++; }
  > ;
  > asnumber        : NUMBER                        {
  > /*
  > * According to iana 65535 and 4294967295 are reserved
  > * but enforcing this is not duty of the parser.
  > */
  > if ($1 < 0 || $1 > UINT_MAX) {
  > yyerror("AS too big: max %u", UINT_MAX);
  > YYERROR;
  > }
  > }
  > as4number       : STRING                        {
  > const char      *errstr;
  > char            *dot;
  > u_int32_t        uvalh = 0, uval;
  > if ((dot = strchr($1,'.')) != NULL) {
  > *dot++ = '\0';
  > uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
  > if (errstr) {
  > yyerror("number %s is %s", $1, errstr);
  > free($1);
  > YYERROR;
  > }
  > uval = strtonum(dot, 0, USHRT_MAX, &errstr);
  > if (errstr) {
  > yyerror("number %s is %s", dot, errstr);
  > free($1);
  > YYERROR;
  > }
  > free($1);
  > } else {
  > yyerror("AS %s is bad", $1);
  > free($1);
  > YYERROR;
  > }
  > if (uvalh == 0 && uval == AS_TRANS) {
  > yyerror("AS %u is reserved and may not be used",
  > AS_TRANS);
  > YYERROR;
  > }
  > $$ = uval | (uvalh << 16);
  > }
  > | asnumber {
  > if ($1 == AS_TRANS) {
  > yyerror("AS %u is reserved and may not be used",
  > AS_TRANS);
  > YYERROR;
  > }
  > $$ = $1;
  > }
  > ;
  > as4number_any   : STRING                        {
  > const char      *errstr;
  > char            *dot;
  > u_int32_t        uvalh = 0, uval;
  > if ((dot = strchr($1,'.')) != NULL) {
  > *dot++ = '\0';
  > uvalh = strtonum($1, 0, USHRT_MAX, &errstr);
  > if (errstr) {
  > yyerror("number %s is %s", $1, errstr);
  > free($1);
  > YYERROR;
  > }
  > uval = strtonum(dot, 0, USHRT_MAX, &errstr);
  > if (errstr) {
  > yyerror("number %s is %s", dot, errstr);
  > free($1);
  > YYERROR;
  > }
  > free($1);
  > } else {
  > yyerror("AS %s is bad", $1);
  > free($1);
  > YYERROR;
  > }
  > $$ = uval | (uvalh << 16);
  > }
  > | asnumber {
  > $$ = $1;
  > }
  > ;
  > string          : string STRING                 {
  > if (asprintf(&$$, "%s %s", $1, $2) == -1)
  > fatal("string: asprintf");
  > free($1);
  > free($2);
  > }
  > | STRING
  > ;
  > yesno           :  STRING                       {
  > if (!strcmp($1, "yes"))
  > $$ = 1;
  > else if (!strcmp($1, "no"))
  > $$ = 0;
  > else {
  > yyerror("syntax error, "
  > "either yes or no expected");
  > free($1);
  > YYERROR;
  > }
  > free($1);
  > }
  > ;
  > varset          : STRING '=' string             {
  > char *s = $1;
  > if (cmd_opts & BGPD_OPT_VERBOSE)
  > printf("%s = \"%s\"\n", $1, $3);
  > while (*s++) {
  > if (isspace((unsigned char)*s)) {
  > yyerror("macro name cannot contain "
  > "whitespace");
  > YYERROR;
  > }
  > }
  > if (symset($1, $3, 0) == -1)
  > fatal("cannot store variable");
  > free($1);
  > free($3);
  > }
  > ;
  > include         : INCLUDE STRING                {
  > struct file     *nfile;
  > if ((nfile = pushfile($2, 1)) == NULL) {
  > yyerror("failed to include file %s", $2);
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > file = nfile;
  > lungetc('\n');
  > }
  > ;
  > conf_main       : AS as4number          {
  > conf->as = $2;
  > if ($2 > USHRT_MAX)
  > conf->short_as = AS_TRANS;
  > else
  > conf->short_as = $2;
  > }
  > | AS as4number asnumber {
  > conf->as = $2;
  > conf->short_as = $3;
  > }
  > | ROUTERID address              {
  > if ($2.aid != AID_INET) {
  > yyerror("router-id must be an IPv4 address");
  > YYERROR;
  > }
  > conf->bgpid = $2.v4.s_addr;
  > }
  > | HOLDTIME NUMBER       {
  > if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
  > yyerror("holdtime must be between %u and %u",
  > MIN_HOLDTIME, USHRT_MAX);
  > YYERROR;
  > }
  > conf->holdtime = $2;
  > }
  > | HOLDTIME YMIN NUMBER  {
  > if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
  > yyerror("holdtime must be between %u and %u",
  > MIN_HOLDTIME, USHRT_MAX);
  > YYERROR;
  > }
  > conf->min_holdtime = $3;
  > }
  > | LISTEN ON address     {
  > struct listen_addr      *la;
  > if ((la = calloc(1, sizeof(struct listen_addr))) ==
  > NULL)
  > fatal("parse conf_main listen on calloc");
  > la->fd = -1;
  > memcpy(&la->sa, addr2sa(&$3, BGP_PORT), sizeof(la->sa));
  > TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry);
  > }
  > | FIBPRIORITY NUMBER            {
  > if ($2 <= RTP_NONE || $2 > RTP_MAX) {
  > yyerror("invalid fib-priority");
  > YYERROR;
  > }
  > conf->fib_priority = $2;
  > }
  > | FIBUPDATE yesno               {
  > struct rde_rib *rr;
  > rr = find_rib("Loc-RIB");
  > if (rr == NULL)
  > fatalx("RTABLE can not find the main RIB!");
  > if ($2 == 0)
  > rr->flags |= F_RIB_NOFIBSYNC;
  > else
  > rr->flags &= ~F_RIB_NOFIBSYNC;
  > }
  > | ROUTECOLL yesno       {
  > if ($2 == 1)
  > conf->flags |= BGPD_FLAG_NO_EVALUATE;
  > else
  > conf->flags &= ~BGPD_FLAG_NO_EVALUATE;
  > }
  > | RDE RIB STRING {
  > if (add_rib($3, conf->default_tableid, F_RIB_NOFIB)) {
  > free($3);
  > YYERROR;
  > }
  > free($3);
  > }
  > | RDE RIB STRING yesno EVALUATE {
  > if ($4) {
  > free($3);
  > yyerror("bad rde rib definition");
  > YYERROR;
  > }
  > if (add_rib($3, conf->default_tableid,
  > F_RIB_NOFIB | F_RIB_NOEVALUATE)) {
  > free($3);
  > YYERROR;
  > }
  > free($3);
  > }
  > | RDE RIB STRING RTABLE NUMBER {
  > if (add_rib($3, $5, 0)) {
  > free($3);
  > YYERROR;
  > }
  > free($3);
  > }
  > | RDE RIB STRING RTABLE NUMBER FIBUPDATE yesno {
  > int     flags = 0;
  > if ($7 == 0)
  > flags = F_RIB_NOFIBSYNC;
  > if (add_rib($3, $5, flags)) {
  > free($3);
  > YYERROR;
  > }
  > free($3);
  > }
  > | TRANSPARENT yesno     {
  > if ($2 == 1)
  > conf->flags |= BGPD_FLAG_DECISION_TRANS_AS;
  > else
  > conf->flags &= ~BGPD_FLAG_DECISION_TRANS_AS;
  > }
  > | LOG STRING            {
  > if (!strcmp($2, "updates"))
  > conf->log |= BGPD_LOG_UPDATES;
  > else {
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | network
  > | DUMP STRING STRING optnumber          {
  > int action;
  > if ($4 < 0 || $4 > INT_MAX) {
  > yyerror("bad timeout");
  > free($2);
  > free($3);
  > YYERROR;
  > }
  > if (!strcmp($2, "table"))
  > action = MRT_TABLE_DUMP;
  > else if (!strcmp($2, "table-mp"))
  > action = MRT_TABLE_DUMP_MP;
  > else if (!strcmp($2, "table-v2"))
  > action = MRT_TABLE_DUMP_V2;
  > else {
  > yyerror("unknown mrt dump type");
  > free($2);
  > free($3);
  > YYERROR;
  > }
  > free($2);
  > if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) {
  > free($3);
  > YYERROR;
  > }
  > free($3);
  > }
  > | DUMP RIB STRING STRING STRING optnumber               {
  > int action;
  > if ($6 < 0 || $6 > INT_MAX) {
  > yyerror("bad timeout");
  > free($3);
  > free($4);
  > free($5);
  > YYERROR;
  > }
  > if (!strcmp($4, "table"))
  > action = MRT_TABLE_DUMP;
  > else if (!strcmp($4, "table-mp"))
  > action = MRT_TABLE_DUMP_MP;
  > else if (!strcmp($4, "table-v2"))
  > action = MRT_TABLE_DUMP_V2;
  > else {
  > yyerror("unknown mrt dump type");
  > free($3);
  > free($4);
  > free($5);
  > YYERROR;
  > }
  > free($4);
  > if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) {
  > free($3);
  > free($5);
  > YYERROR;
  > }
  > free($3);
  > free($5);
  > }
  > | mrtdump
  > | RDE STRING EVALUATE           {
  > if (!strcmp($2, "route-age"))
  > conf->flags |= BGPD_FLAG_DECISION_ROUTEAGE;
  > else {
  > yyerror("unknown route decision type");
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | RDE STRING IGNORE             {
  > if (!strcmp($2, "route-age"))
  > conf->flags &= ~BGPD_FLAG_DECISION_ROUTEAGE;
  > else {
  > yyerror("unknown route decision type");
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | RDE MED COMPARE STRING        {
  > if (!strcmp($4, "always"))
  > conf->flags |= BGPD_FLAG_DECISION_MED_ALWAYS;
  > else if (!strcmp($4, "strict"))
  > conf->flags &= ~BGPD_FLAG_DECISION_MED_ALWAYS;
  > else {
  > yyerror("rde med compare: "
  > "unknown setting \"%s\"", $4);
  > free($4);
  > YYERROR;
  > }
  > free($4);
  > }
  > | NEXTHOP QUALIFY VIA STRING    {
  > if (!strcmp($4, "bgp"))
  > conf->flags |= BGPD_FLAG_NEXTHOP_BGP;
  > else if (!strcmp($4, "default"))
  > conf->flags |= BGPD_FLAG_NEXTHOP_DEFAULT;
  > else {
  > yyerror("nexthop depend on: "
  > "unknown setting \"%s\"", $4);
  > free($4);
  > YYERROR;
  > }
  > free($4);
  > }
  > | RTABLE NUMBER {
  > struct rde_rib *rr;
  > if (ktable_exists($2, NULL) != 1) {
  > yyerror("rtable id %lld does not exist", $2);
  > YYERROR;
  > }
  > rr = find_rib("Loc-RIB");
  > if (rr == NULL)
  > fatalx("RTABLE can not find the main RIB!");
  > rr->rtableid = $2;
  > }
  > | CONNECTRETRY NUMBER {
  > if ($2 > USHRT_MAX || $2 < 1) {
  > yyerror("invalid connect-retry");
  > YYERROR;
  > }
  > conf->connectretry = $2;
  > }
  > | SOCKET STRING restricted {
  > if (strlen($2) >=
  > sizeof(((struct sockaddr_un *)0)->sun_path)) {
  > yyerror("socket path too long");
  > YYERROR;
  > }
  > if ($3) {
  > free(conf->rcsock);
  > conf->rcsock = $2;
  > } else {
  > free(conf->csock);
  > conf->csock = $2;
  > }
  > }
  > ;
  > mrtdump         : DUMP STRING inout STRING optnumber    {
  > int action;
  > if ($5 < 0 || $5 > INT_MAX) {
  > yyerror("bad timeout");
  > free($2);
  > free($4);
  > YYERROR;
  > }
  > if (!strcmp($2, "all"))
  > action = $3 ? MRT_ALL_IN : MRT_ALL_OUT;
  > else if (!strcmp($2, "updates"))
  > action = $3 ? MRT_UPDATE_IN : MRT_UPDATE_OUT;
  > else {
  > yyerror("unknown mrt msg dump type");
  > free($2);
  > free($4);
  > YYERROR;
  > }
  > if (add_mrtconfig(action, $4, $5, curpeer, NULL) ==
  > -1) {
  > free($2);
  > free($4);
  > YYERROR;
  > }
  > free($2);
  > free($4);
  > }
  > ;
  > network         : NETWORK prefix filter_set     {
  > struct network  *n, *m;
  > if ((n = calloc(1, sizeof(struct network))) == NULL)
  > fatal("new_network");
  > memcpy(&n->net.prefix, &$2.prefix,
  > sizeof(n->net.prefix));
  > n->net.prefixlen = $2.len;
  > filterset_move($3, &n->net.attrset);
  > free($3);
  > TAILQ_FOREACH(m, netconf, entry) {
  > if (n->net.prefixlen == m->net.prefixlen &&
  > prefix_compare(&n->net.prefix,
  > &m->net.prefix, n->net.prefixlen) == 0)
  > yyerror("duplicate prefix "
  > "in network statement");
  > }
  > TAILQ_INSERT_TAIL(netconf, n, entry);
  > }
  > | NETWORK family RTLABEL STRING filter_set      {
  > struct network  *n;
  > if ((n = calloc(1, sizeof(struct network))) == NULL)
  > fatal("new_network");
  > if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
  > -1) {
  > yyerror("unknown family");
  > filterset_free($5);
  > free($5);
  > YYERROR;
  > }
  > n->net.type = NETWORK_RTLABEL;
  > n->net.rtlabel = rtlabel_name2id($4);
  > filterset_move($5, &n->net.attrset);
  > free($5);
  > TAILQ_INSERT_TAIL(netconf, n, entry);
  > }
  > | NETWORK family nettype filter_set     {
  > struct network  *n;
  > if ((n = calloc(1, sizeof(struct network))) == NULL)
  > fatal("new_network");
  > if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) ==
  > -1) {
  > yyerror("unknown family");
  > filterset_free($4);
  > free($4);
  > YYERROR;
  > }
  > n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED;
  > filterset_move($4, &n->net.attrset);
  > free($4);
  > TAILQ_INSERT_TAIL(netconf, n, entry);
  > }
  > ;
  > inout           : IN            { $$ = 1; }
  > | OUT           { $$ = 0; }
  > ;
  > restricted      : RESTRICTED    { $$ = 1; }
  > | /* nothing */ { $$ = 0; }
  > ;
  > address         : STRING                {
  > u_int8_t        len;
  > if (!host($1, &$$, &len)) {
  > yyerror("could not parse address spec \"%s\"",
  > $1);
  > free($1);
  > YYERROR;
  > }
  > free($1);
  > if (($$.aid == AID_INET && len != 32) ||
  > ($$.aid == AID_INET6 && len != 128)) {
  > /* unreachable */
  > yyerror("got prefixlen %u, expected %u",
  > len, $$.aid == AID_INET ? 32 : 128);
  > YYERROR;
  > }
  > }
  > ;
  > prefix          : STRING '/' NUMBER     {
  > char    *s;
  > if ($3 < 0 || $3 > 128) {
  > yyerror("bad prefixlen %lld", $3);
  > free($1);
  > YYERROR;
  > }
  > if (asprintf(&s, "%s/%lld", $1, $3) == -1)
  > fatal(NULL);
  > free($1);
  > if (!host(s, &$$.prefix, &$$.len)) {
  > yyerror("could not parse address \"%s\"", s);
  > free(s);
  > YYERROR;
  > }
  > free(s);
  > }
  > | NUMBER '/' NUMBER     {
  > char    *s;
  > /* does not match IPv6 */
  > if ($1 < 0 || $1 > 255 || $3 < 0 || $3 > 32) {
  > yyerror("bad prefix %lld/%lld", $1, $3);
  > YYERROR;
  > }
  > if (asprintf(&s, "%lld/%lld", $1, $3) == -1)
  > fatal(NULL);
  > if (!host(s, &$$.prefix, &$$.len)) {
  > yyerror("could not parse address \"%s\"", s);
  > free(s);
  > YYERROR;
  > }
  > free(s);
  > }
  > ;
  > addrspec        : address       {
  > memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr));
  > if ($$.prefix.aid == AID_INET)
  > $$.len = 32;
  > else
  > $$.len = 128;
  > }
  > | prefix
  > ;
  > optnl           : '\n' optnl
  > |
  > ;
  > nl              : '\n' optnl            /* one newline or more */
  > ;
  > optnumber       : /* empty */           { $$ = 0; }
  > | NUMBER
  > ;
  > rdomain         : RDOMAIN NUMBER optnl '{' optnl        {
  > if (ktable_exists($2, NULL) != 1) {
  > yyerror("rdomain %lld does not exist", $2);
  > YYERROR;
  > }
  > if (!(currdom = calloc(1, sizeof(struct rdomain))))
  > fatal(NULL);
  > currdom->rtableid = $2;
  > TAILQ_INIT(&currdom->import);
  > TAILQ_INIT(&currdom->export);
  > TAILQ_INIT(&currdom->net_l);
  > netconf = &currdom->net_l;
  > }
  > rdomainopts_l '}' {
  > /* insert into list */
  > SIMPLEQ_INSERT_TAIL(&conf->rdomains, currdom, entry);
  > currdom = NULL;
  > netconf = &conf->networks;
  > }
  > rdomainopts_l   : rdomainopts_l rdomainoptsl
  > | rdomainoptsl
  > ;
  > rdomainoptsl    : rdomainopts nl
  > ;
  > rdomainopts     : RD STRING {
  > struct filter_extcommunity      ext;
  > u_int64_t                       rd;
  > if (parseextcommunity(&ext, "rt", $2) == -1) {
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > /*
  > * RD is almost encode like an ext-community,
  > * but only almost so convert here.
  > */
  > if (community_ext_conv(&ext, 0, &rd)) {
  > yyerror("bad encoding of rd");
  > YYERROR;
  > }
  > rd = betoh64(rd) & 0xffffffffffffULL;
  > switch (ext.type) {
  > case EXT_COMMUNITY_TRANS_TWO_AS:
  > rd |= (0ULL << 48);
  > break;
  > case EXT_COMMUNITY_TRANS_IPV4:
  > rd |= (1ULL << 48);
  > break;
  > case EXT_COMMUNITY_TRANS_FOUR_AS:
  > rd |= (2ULL << 48);
  > break;
  > default:
  > yyerror("bad encoding of rd");
  > YYERROR;
  > }
  > currdom->rd = htobe64(rd);
  > }
  > | EXPORTTRGT STRING STRING      {
  > struct filter_set       *set;
  > if ((set = calloc(1, sizeof(struct filter_set))) ==
  > NULL)
  > fatal(NULL);
  > set->type = ACTION_SET_EXT_COMMUNITY;
  > if (parseextcommunity(&set->action.ext_community,
  > $2, $3) == -1) {
  > free($3);
  > free($2);
  > free(set);
  > YYERROR;
  > }
  > free($3);
  > free($2);
  > TAILQ_INSERT_TAIL(&currdom->export, set, entry);
  > }
  > | IMPORTTRGT STRING STRING      {
  > struct filter_set       *set;
  > if ((set = calloc(1, sizeof(struct filter_set))) ==
  > NULL)
  > fatal(NULL);
  > set->type = ACTION_SET_EXT_COMMUNITY;
  > if (parseextcommunity(&set->action.ext_community,
  > $2, $3) == -1) {
  > free($3);
  > free($2);
  > free(set);
  > YYERROR;
  > }
  > free($3);
  > free($2);
  > TAILQ_INSERT_TAIL(&currdom->import, set, entry);
  > }
  > | DESCR string          {
  > if (strlcpy(currdom->descr, $2,
  > sizeof(currdom->descr)) >=
  > sizeof(currdom->descr)) {
  > yyerror("descr \"%s\" too long: max %zu",
  > $2, sizeof(currdom->descr) - 1);
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | FIBUPDATE yesno               {
  > if ($2 == 0)
  > currdom->flags |= F_RIB_NOFIBSYNC;
  > else
  > currdom->flags &= ~F_RIB_NOFIBSYNC;
  > }
  > | network
  > | DEPEND ON STRING      {
  > /* XXX this is a hack */
  > if (if_nametoindex($3) == 0) {
  > yyerror("interface %s does not exist", $3);
  > free($3);
  > YYERROR;
  > }
  > strlcpy(currdom->ifmpe, $3, IFNAMSIZ);
  > free($3);
  > if (get_mpe_label(currdom)) {
  > yyerror("failed to get mpls label from %s",
  > currdom->ifmpe);
  > YYERROR;
  > }
  > }
  > ;
  > neighbor        : {     curpeer = new_peer(); }
  > NEIGHBOR addrspec {
  > memcpy(&curpeer->conf.remote_addr, &$3.prefix,
  > sizeof(curpeer->conf.remote_addr));
  > curpeer->conf.remote_masklen = $3.len;
  > if (($3.prefix.aid == AID_INET && $3.len != 32) ||
  > ($3.prefix.aid == AID_INET6 && $3.len != 128))
  > curpeer->conf.template = 1;
  > if (curpeer->conf.capabilities.mp[
  > curpeer->conf.remote_addr.aid] == -1)
  > curpeer->conf.capabilities.mp[
  > curpeer->conf.remote_addr.aid] = 1;
  > if (get_id(curpeer)) {
  > yyerror("get_id failed");
  > YYERROR;
  > }
  > }
  > peeropts_h {
  > if (curpeer_filter[0] != NULL)
  > TAILQ_INSERT_TAIL(peerfilter_l,
  > curpeer_filter[0], entry);
  > if (curpeer_filter[1] != NULL)
  > TAILQ_INSERT_TAIL(peerfilter_l,
  > curpeer_filter[1], entry);
  > curpeer_filter[0] = NULL;
  > curpeer_filter[1] = NULL;
  > if (neighbor_consistent(curpeer) == -1)
  > YYERROR;
  > curpeer->next = peer_l;
  > peer_l = curpeer;
  > curpeer = curgroup;
  > }
  > ;
  > group           : GROUP string optnl '{' optnl {
  > curgroup = curpeer = new_group();
  > if (strlcpy(curgroup->conf.group, $2,
  > sizeof(curgroup->conf.group)) >=
  > sizeof(curgroup->conf.group)) {
  > yyerror("group name \"%s\" too long: max %zu",
  > $2, sizeof(curgroup->conf.group) - 1);
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > if (get_id(curgroup)) {
  > yyerror("get_id failed");
  > YYERROR;
  > }
  > }
  > groupopts_l '}' {
  > if (curgroup_filter[0] != NULL)
  > TAILQ_INSERT_TAIL(groupfilter_l,
  > curgroup_filter[0], entry);
  > if (curgroup_filter[1] != NULL)
  > TAILQ_INSERT_TAIL(groupfilter_l,
  > curgroup_filter[1], entry);
  > curgroup_filter[0] = NULL;
  > curgroup_filter[1] = NULL;
  > free(curgroup);
  > curgroup = NULL;
  > }
  > ;
  > groupopts_l     : groupopts_l groupoptsl
  > | groupoptsl
  > ;
  > groupoptsl      : peeropts nl
  > | neighbor nl
  > | error nl
  > ;
  > peeropts_h      : '{' optnl peeropts_l '}'
  > | /* empty */
  > ;
  > peeropts_l      : peeropts_l peeroptsl
  > | peeroptsl
  > ;
  > peeroptsl       : peeropts nl
  > ;
  > peeropts        : REMOTEAS as4number    {
  > curpeer->conf.remote_as = $2;
  > }
  > | LOCALAS as4number     {
  > curpeer->conf.local_as = $2;
  > if ($2 > USHRT_MAX)
  > curpeer->conf.local_short_as = AS_TRANS;
  > else
  > curpeer->conf.local_short_as = $2;
  > }
  > | LOCALAS as4number asnumber {
  > curpeer->conf.local_as = $2;
  > curpeer->conf.local_short_as = $3;
  > }
  > | DESCR string          {
  > if (strlcpy(curpeer->conf.descr, $2,
  > sizeof(curpeer->conf.descr)) >=
  > sizeof(curpeer->conf.descr)) {
  > yyerror("descr \"%s\" too long: max %zu",
  > $2, sizeof(curpeer->conf.descr) - 1);
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | LOCALADDR address     {
  > memcpy(&curpeer->conf.local_addr, &$2,
  > sizeof(curpeer->conf.local_addr));
  > }
  > | MULTIHOP NUMBER       {
  > if ($2 < 2 || $2 > 255) {
  > yyerror("invalid multihop distance %lld", $2);
  > YYERROR;
  > }
  > curpeer->conf.distance = $2;
  > }
  > | PASSIVE               {
  > curpeer->conf.passive = 1;
  > }
  > | DOWN                  {
  > curpeer->conf.down = 1;
  > }
  > | DOWN STRING           {
  > curpeer->conf.down = 1;
  > if (strlcpy(curpeer->conf.shutcomm, $2,
  > sizeof(curpeer->conf.shutcomm)) >=
  > sizeof(curpeer->conf.shutcomm)) {
  > yyerror("shutdown reason too long");
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | RIB STRING    {
  > if (!find_rib($2)) {
  > yyerror("rib \"%s\" does not exist.", $2);
  > free($2);
  > YYERROR;
  > }
  > if (strlcpy(curpeer->conf.rib, $2,
  > sizeof(curpeer->conf.rib)) >=
  > sizeof(curpeer->conf.rib)) {
  > yyerror("rib name \"%s\" too long: max %zu",
  > $2, sizeof(curpeer->conf.rib) - 1);
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | HOLDTIME NUMBER       {
  > if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
  > yyerror("holdtime must be between %u and %u",
  > MIN_HOLDTIME, USHRT_MAX);
  > YYERROR;
  > }
  > curpeer->conf.holdtime = $2;
  > }
  > | HOLDTIME YMIN NUMBER  {
  > if ($3 < MIN_HOLDTIME || $3 > USHRT_MAX) {
  > yyerror("holdtime must be between %u and %u",
  > MIN_HOLDTIME, USHRT_MAX);
  > YYERROR;
  > }
  > curpeer->conf.min_holdtime = $3;
  > }
  > | ANNOUNCE family STRING {
  > u_int8_t        aid, safi;
  > int8_t          val = 1;
  > if (!strcmp($3, "none")) {
  > safi = SAFI_UNICAST;
  > val = 0;
  > } else if (!strcmp($3, "unicast")) {
  > safi = SAFI_UNICAST;
  > } else if (!strcmp($3, "vpn")) {
  > safi = SAFI_MPLSVPN;
  > } else {
  > yyerror("unknown/unsupported SAFI \"%s\"",
  > $3);
  > free($3);
  > YYERROR;
  > }
  > free($3);
  > if (afi2aid($2, safi, &aid) == -1) {
  > yyerror("unknown AFI/SAFI pair");
  > YYERROR;
  > }
  > curpeer->conf.capabilities.mp[aid] = val;
  > }
  > | ANNOUNCE CAPABILITIES yesno {
  > curpeer->conf.announce_capa = $3;
  > }
  > | ANNOUNCE REFRESH yesno {
  > curpeer->conf.capabilities.refresh = $3;
  > }
  > | ANNOUNCE RESTART yesno {
  > curpeer->conf.capabilities.grestart.restart = $3;
  > }
  > | ANNOUNCE AS4BYTE yesno {
  > curpeer->conf.capabilities.as4byte = $3;
  > }
  > | ANNOUNCE SELF {
  > curpeer->conf.announce_type = ANNOUNCE_SELF;
  > }
  > | ANNOUNCE STRING {
  > if (!strcmp($2, "self"))
  > curpeer->conf.announce_type = ANNOUNCE_SELF;
  > else if (!strcmp($2, "none"))
  > curpeer->conf.announce_type = ANNOUNCE_NONE;
  > else if (!strcmp($2, "all"))
  > curpeer->conf.announce_type = ANNOUNCE_ALL;
  > else if (!strcmp($2, "default-route"))
  > curpeer->conf.announce_type =
  > ANNOUNCE_DEFAULT_ROUTE;
  > else {
  > yyerror("invalid announce type");
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | ENFORCE NEIGHBORAS yesno {
  > if ($3)
  > curpeer->conf.enforce_as = ENFORCE_AS_ON;
  > else
  > curpeer->conf.enforce_as = ENFORCE_AS_OFF;
  > }
  > | ENFORCE LOCALAS yesno {
  > if ($3)
  > curpeer->conf.enforce_local_as = ENFORCE_AS_ON;
  > else
  > curpeer->conf.enforce_local_as = ENFORCE_AS_OFF;
  > }
  > | MAXPREFIX NUMBER restart {
  > if ($2 < 0 || $2 > UINT_MAX) {
  > yyerror("bad maximum number of prefixes");
  > YYERROR;
  > }
  > curpeer->conf.max_prefix = $2;
  > curpeer->conf.max_prefix_restart = $3;
  > }
  > | TCP MD5SIG PASSWORD string {
  > if (curpeer->conf.auth.method) {
  > yyerror("auth method cannot be redefined");
  > free($4);
  > YYERROR;
  > }
  > if (strlcpy(curpeer->conf.auth.md5key, $4,
  > sizeof(curpeer->conf.auth.md5key)) >=
  > sizeof(curpeer->conf.auth.md5key)) {
  > yyerror("tcp md5sig password too long: max %zu",
  > sizeof(curpeer->conf.auth.md5key) - 1);
  > free($4);
  > YYERROR;
  > }
  > curpeer->conf.auth.method = AUTH_MD5SIG;
  > curpeer->conf.auth.md5key_len = strlen($4);
  > free($4);
  > }
  > | TCP MD5SIG KEY string {
  > if (curpeer->conf.auth.method) {
  > yyerror("auth method cannot be redefined");
  > free($4);
  > YYERROR;
  > }
  > if (str2key($4, curpeer->conf.auth.md5key,
  > sizeof(curpeer->conf.auth.md5key)) == -1) {
  > free($4);
  > YYERROR;
  > }
  > curpeer->conf.auth.method = AUTH_MD5SIG;
  > curpeer->conf.auth.md5key_len = strlen($4) / 2;
  > free($4);
  > }
  > | IPSEC espah IKE {
  > if (curpeer->conf.auth.method) {
  > yyerror("auth method cannot be redefined");
  > YYERROR;
  > }
  > if ($2)
  > curpeer->conf.auth.method = AUTH_IPSEC_IKE_ESP;
  > else
  > curpeer->conf.auth.method = AUTH_IPSEC_IKE_AH;
  > }
  > | IPSEC espah inout SPI NUMBER STRING STRING encspec {
  > u_int32_t       auth_alg;
  > u_int8_t        keylen;
  > if (curpeer->conf.auth.method &&
  > (((curpeer->conf.auth.spi_in && $3 == 1) ||
  > (curpeer->conf.auth.spi_out && $3 == 0)) ||
  > ($2 == 1 && curpeer->conf.auth.method !=
  > AUTH_IPSEC_MANUAL_ESP) ||
  > ($2 == 0 && curpeer->conf.auth.method !=
  > AUTH_IPSEC_MANUAL_AH))) {
  > yyerror("auth method cannot be redefined");
  > free($6);
  > free($7);
  > YYERROR;
  > }
  > if (!strcmp($6, "sha1")) {
  > auth_alg = SADB_AALG_SHA1HMAC;
  > keylen = 20;
  > } else if (!strcmp($6, "md5")) {
  > auth_alg = SADB_AALG_MD5HMAC;
  > keylen = 16;
  > } else {
  > yyerror("unknown auth algorithm \"%s\"", $6);
  > free($6);
  > free($7);
  > YYERROR;
  > }
  > free($6);
  > if (strlen($7) / 2 != keylen) {
  > yyerror("auth key len: must be %u bytes, "
  > "is %zu bytes", keylen, strlen($7) / 2);
  > free($7);
  > YYERROR;
  > }
  > if ($2)
  > curpeer->conf.auth.method =
  > AUTH_IPSEC_MANUAL_ESP;
  > else {
  > if ($8.enc_alg) {
  > yyerror("\"ipsec ah\" doesn't take "
  > "encryption keys");
  > free($7);
  > YYERROR;
  > }
  > curpeer->conf.auth.method =
  > AUTH_IPSEC_MANUAL_AH;
  > }
  > if ($5 <= SPI_RESERVED_MAX || $5 > UINT_MAX) {
  > yyerror("bad spi number %lld", $5);
  > free($7);
  > YYERROR;
  > }
  > if ($3 == 1) {
  > if (str2key($7, curpeer->conf.auth.auth_key_in,
  > sizeof(curpeer->conf.auth.auth_key_in)) ==
  > -1) {
  > free($7);
  > YYERROR;
  > }
  > curpeer->conf.auth.spi_in = $5;
  > curpeer->conf.auth.auth_alg_in = auth_alg;
  > curpeer->conf.auth.enc_alg_in = $8.enc_alg;
  > memcpy(&curpeer->conf.auth.enc_key_in,
  > &$8.enc_key,
  > sizeof(curpeer->conf.auth.enc_key_in));
  > curpeer->conf.auth.enc_keylen_in =
  > $8.enc_key_len;
  > curpeer->conf.auth.auth_keylen_in = keylen;
  > } else {
  > if (str2key($7, curpeer->conf.auth.auth_key_out,
  > sizeof(curpeer->conf.auth.auth_key_out)) ==
  > -1) {
  > free($7);
  > YYERROR;
  > }
  > curpeer->conf.auth.spi_out = $5;
  > curpeer->conf.auth.auth_alg_out = auth_alg;
  > curpeer->conf.auth.enc_alg_out = $8.enc_alg;
  > memcpy(&curpeer->conf.auth.enc_key_out,
  > &$8.enc_key,
  > sizeof(curpeer->conf.auth.enc_key_out));
  > curpeer->conf.auth.enc_keylen_out =
  > $8.enc_key_len;
  > curpeer->conf.auth.auth_keylen_out = keylen;
  > }
  > free($7);
  > }
  > | TTLSECURITY yesno     {
  > curpeer->conf.ttlsec = $2;
  > }
  > | SET filter_set_opt    {
  > struct filter_rule      *r;
  > r = get_rule($2->type);
  > if (merge_filterset(&r->set, $2) == -1)
  > YYERROR;
  > }
  > | SET optnl "{" optnl filter_set_l optnl "}"    {
  > struct filter_rule      *r;
  > struct filter_set       *s;
  > while ((s = TAILQ_FIRST($5)) != NULL) {
  > TAILQ_REMOVE($5, s, entry);
  > r = get_rule(s->type);
  > if (merge_filterset(&r->set, s) == -1)
  > YYERROR;
  > }
  > free($5);
  > }
  > | mrtdump
  > | REFLECTOR             {
  > if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
  > conf->clusterid != 0) {
  > yyerror("only one route reflector "
  > "cluster allowed");
  > YYERROR;
  > }
  > conf->flags |= BGPD_FLAG_REFLECTOR;
  > curpeer->conf.reflector_client = 1;
  > }
  > | REFLECTOR address     {
  > if ($2.aid != AID_INET) {
  > yyerror("route reflector cluster-id must be "
  > "an IPv4 address");
  > YYERROR;
  > }
  > if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
  > conf->clusterid != $2.v4.s_addr) {
  > yyerror("only one route reflector "
  > "cluster allowed");
  > YYERROR;
  > }
  > conf->flags |= BGPD_FLAG_REFLECTOR;
  > curpeer->conf.reflector_client = 1;
  > conf->clusterid = $2.v4.s_addr;
  > }
  > | DEPEND ON STRING      {
  > if (strlcpy(curpeer->conf.if_depend, $3,
  > sizeof(curpeer->conf.if_depend)) >=
  > sizeof(curpeer->conf.if_depend)) {
  > yyerror("interface name \"%s\" too long: "
  > "max %zu", $3,
  > sizeof(curpeer->conf.if_depend) - 1);
  > free($3);
  > YYERROR;
  > }
  > free($3);
  > }
  > | DEMOTE STRING         {
  > if (strlcpy(curpeer->conf.demote_group, $2,
  > sizeof(curpeer->conf.demote_group)) >=
  > sizeof(curpeer->conf.demote_group)) {
  > yyerror("demote group name \"%s\" too long: "
  > "max %zu", $2,
  > sizeof(curpeer->conf.demote_group) - 1);
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > if (carp_demote_init(curpeer->conf.demote_group,
  > cmd_opts & BGPD_OPT_FORCE_DEMOTE) == -1) {
  > yyerror("error initializing group \"%s\"",
  > curpeer->conf.demote_group);
  > YYERROR;
  > }
  > }
  > | TRANSPARENT yesno     {
  > if ($2 == 1)
  > curpeer->conf.flags |= PEERFLAG_TRANS_AS;
  > else
  > curpeer->conf.flags &= ~PEERFLAG_TRANS_AS;
  > }
  > | LOG STRING            {
  > if (!strcmp($2, "updates"))
  > curpeer->conf.flags |= PEERFLAG_LOG_UPDATES;
  > else if (!strcmp($2, "no"))
  > curpeer->conf.flags &= ~PEERFLAG_LOG_UPDATES;
  > else {
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > ;
  > restart         : /* nada */            { $$ = 0; }
  > | RESTART NUMBER        {
  > if ($2 < 1 || $2 > USHRT_MAX) {
  > yyerror("restart out of range. 1 to %u minutes",
  > USHRT_MAX);
  > YYERROR;
  > }
  > $$ = $2;
  > }
  > ;
  > family          : IPV4  { $$ = AFI_IPv4; }
  > | IPV6  { $$ = AFI_IPv6; }
  > ;
  > nettype         : STATIC { $$ = 1; },
  > | CONNECTED { $$ = 0; }
  > ;
  > espah           : ESP           { $$ = 1; }
  > | AH            { $$ = 0; }
  > ;
  > encspec         : /* nada */    {
  > bzero(&$$, sizeof($$));
  > }
  > | STRING STRING {
  > bzero(&$$, sizeof($$));
  > if (!strcmp($1, "3des") || !strcmp($1, "3des-cbc")) {
  > $$.enc_alg = SADB_EALG_3DESCBC;
  > $$.enc_key_len = 21; /* XXX verify */
  > } else if (!strcmp($1, "aes") ||
  > !strcmp($1, "aes-128-cbc")) {
  > $$.enc_alg = SADB_X_EALG_AES;
  > $$.enc_key_len = 16;
  > } else {
  > yyerror("unknown enc algorithm \"%s\"", $1);
  > free($1);
  > free($2);
  > YYERROR;
  > }
  > free($1);
  > if (strlen($2) / 2 != $$.enc_key_len) {
  > yyerror("enc key length wrong: should be %u "
  > "bytes, is %zu bytes",
  > $$.enc_key_len * 2, strlen($2));
  > free($2);
  > YYERROR;
  > }
  > if (str2key($2, $$.enc_key, sizeof($$.enc_key)) == -1) {
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > ;
  > filterrule      : action quick filter_rib_h direction filter_peer_h
  > filter_match_h filter_set
  > {
  > struct filter_rule       r;
  > struct filter_rib_l      *rb, *rbnext;
  > bzero(&r, sizeof(r));
  > r.action = $1;
  > r.quick = $2;
  > r.dir = $4;
  > if ($3) {
  > if (r.dir != DIR_IN) {
  > yyerror("rib only allowed on \"from\" "
  > "rules.");
  > for (rb = $3; rb != NULL; rb = rbnext) {
  > rbnext = rb->next;
  > free(rb);
  > }
  > YYERROR;
  > }
  > }
  > if (expand_rule(&r, $3, $5, &$6, $7) == -1)
  > YYERROR;
  > }
  > ;
  > action          : ALLOW         { $$ = ACTION_ALLOW; }
  > | DENY          { $$ = ACTION_DENY; }
  > | MATCH         { $$ = ACTION_NONE; }
  > ;
  > quick           : /* empty */   { $$ = 0; }
  > | QUICK         { $$ = 1; }
  > ;
  > direction       : FROM          { $$ = DIR_IN; }
  > | TO            { $$ = DIR_OUT; }
  > ;
  > filter_rib_h    : /* empty */                   { $$ = NULL; }
  > | RIB filter_rib                { $$ = $2; }
  > | RIB '{' filter_rib_l '}'      { $$ = $3; }
  > filter_rib_l    : filter_rib                    { $$ = $1; }
  > | filter_rib_l comma filter_rib {
  > $3->next = $1;
  > $$ = $3;
  > }
  > ;
  > filter_rib      : STRING        {
  > if (!find_rib($1)) {
  > yyerror("rib \"%s\" does not exist.", $1);
  > free($1);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_rib_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->next = NULL;
  > if (strlcpy($$->name, $1, sizeof($$->name)) >=
  > sizeof($$->name)) {
  > yyerror("rib name \"%s\" too long: "
  > "max %zu", $1, sizeof($$->name) - 1);
  > free($1);
  > free($$);
  > YYERROR;
  > }
  > free($1);
  > }
  > ;
  > filter_peer_h   : filter_peer
  > | '{' filter_peer_l '}'         { $$ = $2; }
  > ;
  > filter_peer_l   : filter_peer                           { $$ = $1; }
  > | filter_peer_l comma filter_peer       {
  > $3->next = $1;
  > $$ = $3;
  > }
  > ;
  > filter_peer     : ANY           {
  > if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.peerid = $$->p.groupid = 0;
  > $$->next = NULL;
  > }
  > | address       {
  > struct peer *p;
  > if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.remote_as = $$->p.groupid = $$->p.peerid = 0;
  > $$->next = NULL;
  > for (p = peer_l; p != NULL; p = p->next)
  > if (!memcmp(&p->conf.remote_addr,
  > &$1, sizeof(p->conf.remote_addr))) {
  > $$->p.peerid = p->conf.id;
  > break;
  > }
  > if ($$->p.peerid == 0) {
  > yyerror("no such peer: %s", log_addr(&$1));
  > free($$);
  > YYERROR;
  > }
  > }
  > | AS as4number  {
  > if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.groupid = $$->p.peerid = 0;
  > $$->p.remote_as = $2;
  > }
  > | GROUP STRING  {
  > struct peer *p;
  > if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.remote_as = $$->p.peerid = 0;
  > $$->next = NULL;
  > for (p = peer_l; p != NULL; p = p->next)
  > if (!strcmp(p->conf.group, $2)) {
  > $$->p.groupid = p->conf.groupid;
  > break;
  > }
  > if ($$->p.groupid == 0) {
  > yyerror("no such group: \"%s\"", $2);
  > free($2);
  > free($$);
  > YYERROR;
  > }
  > free($2);
  > }
  > | EBGP {
  > if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.ebgp = 1;
  > }
  > | IBGP {
  > if (($$ = calloc(1, sizeof(struct filter_peers_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.ibgp = 1;
  > }
  > ;
  > filter_prefix_h : IPV4 prefixlenop                       {
  > if ($2.op == OP_NONE)
  > $2.op = OP_GE;
  > if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.addr.aid = AID_INET;
  > if (merge_prefixspec($$, &$2) == -1) {
  > free($$);
  > YYERROR;
  > }
  > }
  > | IPV6 prefixlenop                      {
  > if ($2.op == OP_NONE)
  > $2.op = OP_GE;
  > if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->p.addr.aid = AID_INET6;
  > if (merge_prefixspec($$, &$2) == -1) {
  > free($$);
  > YYERROR;
  > }
  > }
  > | PREFIX filter_prefix                  { $$ = $2; }
  > | PREFIX '{' filter_prefix_m '}'        { $$ = $3; }
  > ;
  > filter_prefix_m : filter_prefix_l
  > | '{' filter_prefix_l '}'               { $$ = $2; }
  > | '{' filter_prefix_l '}' filter_prefix_m
  > {
  > struct filter_prefix_l  *p;
  > /* merge, both can be lists */
  > for (p = $2; p != NULL && p->next != NULL; p = p->next)
  > ;       /* nothing */
  > if (p != NULL)
  > p->next = $4;
  > $$ = $2;
  > }
  > filter_prefix_l : filter_prefix                         { $$ = $1; }
  > | filter_prefix_l comma filter_prefix   {
  > $3->next = $1;
  > $$ = $3;
  > }
  > ;
  > filter_prefix   : prefix prefixlenop                    {
  > if (($$ = calloc(1, sizeof(struct filter_prefix_l))) ==
  > NULL)
  > fatal(NULL);
  > memcpy(&$$->p.addr, &$1.prefix,
  > sizeof($$->p.addr));
  > $$->p.len = $1.len;
  > if (merge_prefixspec($$, &$2) == -1) {
  > free($$);
  > YYERROR;
  > }
  > }
  > ;
  > filter_as_h     : filter_as_t
  > | '{' filter_as_t_l '}'         { $$ = $2; }
  > ;
  > filter_as_t_l   : filter_as_t
  > | filter_as_t_l comma filter_as_t               {
  > struct filter_as_l      *a;
  > /* merge, both can be lists */
  > for (a = $1; a != NULL && a->next != NULL; a = a->next)
  > ;       /* nothing */
  > if (a != NULL)
  > a->next = $3;
  > $$ = $1;
  > }
  > ;
  > filter_as_t     : filter_as_type filter_as                      {
  > $$ = $2;
  > $$->a.type = $1;
  > }
  > | filter_as_type '{' filter_as_l_h '}'  {
  > struct filter_as_l      *a;
  > $$ = $3;
  > for (a = $$; a != NULL; a = a->next)
  > a->a.type = $1;
  > }
  > ;
  > filter_as_l_h   : filter_as_l
  > | '{' filter_as_l '}'                   { $$ = $2; }
  > | '{' filter_as_l '}' filter_as_l_h
  > {
  > struct filter_as_l      *a;
  > /* merge, both can be lists */
  > for (a = $2; a != NULL && a->next != NULL; a = a->next)
  > ;       /* nothing */
  > if (a != NULL)
  > a->next = $4;
  > $$ = $2;
  > }
  > ;
  > filter_as_l     : filter_as
  > | filter_as_l comma filter_as   {
  > $3->next = $1;
  > $$ = $3;
  > }
  > ;
  > filter_as       : as4number_any         {
  > if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->a.as = $1;
  > $$->a.op = OP_EQ;
  > }
  > | NEIGHBORAS            {
  > if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->a.flags = AS_FLAG_NEIGHBORAS;
  > }
  > | equalityop as4number_any      {
  > if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
  > NULL)
  > fatal(NULL);
  > $$->a.op = $1;
  > $$->a.as = $2;
  > }
  > | as4number_any binaryop as4number_any {
  > if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
  > NULL)
  > fatal(NULL);
  > if ($1 >= $3) {
  > yyerror("start AS is bigger than end");
  > YYERROR;
  > }
  > $$->a.op = $2;
  > $$->a.as_min = $1;
  > $$->a.as_max = $3;
  > }
  > ;
  > filter_match_h  : /* empty */                   {
  > bzero(&$$, sizeof($$));
  > $$.m.community.as = COMMUNITY_UNSET;
  > $$.m.large_community.as = COMMUNITY_UNSET;
  > }
  > | {
  > bzero(&fmopts, sizeof(fmopts));
  > fmopts.m.community.as = COMMUNITY_UNSET;
  > fmopts.m.large_community.as = COMMUNITY_UNSET;
  > }
  > filter_match            {
  > memcpy(&$$, &fmopts, sizeof($$));
  > }
  > ;
  > filter_match    : filter_elm
  > | filter_match filter_elm
  > ;
  > filter_elm      : filter_prefix_h       {
  > if (fmopts.prefix_l != NULL) {
  > yyerror("\"prefix\" already specified");
  > YYERROR;
  > }
  > fmopts.prefix_l = $1;
  > }
  > | filter_as_h           {
  > if (fmopts.as_l != NULL) {
  > yyerror("AS filters already specified");
  > YYERROR;
  > }
  > fmopts.as_l = $1;
  > }
  > | MAXASLEN NUMBER       {
  > if (fmopts.m.aslen.type != ASLEN_NONE) {
  > yyerror("AS length filters already specified");
  > YYERROR;
  > }
  > if ($2 < 0 || $2 > UINT_MAX) {
  > yyerror("bad max-as-len %lld", $2);
  > YYERROR;
  > }
  > fmopts.m.aslen.type = ASLEN_MAX;
  > fmopts.m.aslen.aslen = $2;
  > }
  > | MAXASSEQ NUMBER       {
  > if (fmopts.m.aslen.type != ASLEN_NONE) {
  > yyerror("AS length filters already specified");
  > YYERROR;
  > }
  > if ($2 < 0 || $2 > UINT_MAX) {
  > yyerror("bad max-as-seq %lld", $2);
  > YYERROR;
  > }
  > fmopts.m.aslen.type = ASLEN_SEQ;
  > fmopts.m.aslen.aslen = $2;
  > }
  > | COMMUNITY STRING      {
  > if (fmopts.m.community.as != COMMUNITY_UNSET) {
  > yyerror("\"community\" already specified");
  > free($2);
  > YYERROR;
  > }
  > if (parsecommunity(&fmopts.m.community, $2) == -1) {
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | LARGECOMMUNITY STRING {
  > if (fmopts.m.large_community.as != COMMUNITY_UNSET) {
  > yyerror("\"large-community\" already specified");
  > free($2);
  > YYERROR;
  > }
  > if (parselargecommunity(&fmopts.m.large_community, $2) == -1) {
  > free($2);
  > YYERROR;
  > }
  > free($2);
  > }
  > | EXTCOMMUNITY STRING STRING {
  > if (fmopts.m.ext_community.flags &
  > EXT_COMMUNITY_FLAG_VALID) {
  > yyerror("\"ext-community\" already specified");
  > free($2);
  > free($3);
  > YYERROR;
  > }
  > if (parseextcommunity(&fmopts.m.ext_community,
  > $2, $3) == -1) {
  > free($2);
  > free($3);
  > YYERROR;
  > }
  > free($2);
  > free($3);
  > }
  > | NEXTHOP address       {
  > if (fmopts.m.nexthop.flags) {
  > yyerror("nexthop already specified");
  > YYERROR;
  > }
  > fmopts.m.nexthop.addr = $2;
  > fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR;
  > }
  > | NEXTHOP NEIGHBOR      {
  > if (fmopts.m.nexthop.flags) {
  > yyerror("nexthop already specified");
  > YYERROR;
  > }
  > fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR;
  > }
  > ;
  > prefixlenop     : /* empty */                   { bzero(&$$, sizeof($$)); }
  > | LONGER                                {
  > bzero(&$$, sizeof($$));
  > $$.op = OP_GE;
  > $$.len_min = -1;
  > }
  > | PREFIXLEN unaryop NUMBER              {
  > bzero(&$$, sizeof($$));
  > if ($3 < 0 || $3 > 128) {
  > yyerror("prefixlen must be >= 0 and <= 128");
  > YYERROR;
  > }
  > if ($2 == OP_GT && $3 == 0) {
  > yyerror("prefixlen must be > 0");
  > YYERROR;
  > }
  > $$.op = $2;
  > $$.len_min = $3;
  > }
  > | PREFIXLEN NUMBER binaryop NUMBER      {
  > bzero(&$$, sizeof($$));
  > if ($2 < 0 || $2 > 128 || $4 < 0 || $4 > 128) {
  > yyerror("prefixlen must be < 128");
  > YYERROR;
  > }
  > if ($2 >= $4) {
  > yyerror("start prefixlen is bigger than end");
  > YYERROR;
  > }
  > $$.op = $3;
  > $$.len_min = $2;
  > $$.len_max = $4;
  > }
  > ;
  > filter_as_type  : AS            { $$ = AS_ALL; }
  > | SOURCEAS      { $$ = AS_SOURCE; }
  > | TRANSITAS     { $$ = AS_TRANSIT; }
  > | PEERAS        { $$ = AS_PEER; }
  > ;
  > filter_set      : /* empty */                                   { $$ =
  > NULL; }
  > | SET filter_set_opt                            {
  > if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
  > NULL)
  > fatal(NULL);
  > TAILQ_INIT($$);
  > TAILQ_INSERT_TAIL($$, $2, entry);
  > }
  > | SET optnl "{" optnl filter_set_l optnl "}"    { $$ = $5; }
  > ;
  > filter_set_l    : filter_set_l comma filter_set_opt     {
  > $$ = $1;
  > if (merge_filterset($$, $3) == 1)
  > YYERROR;
  > }
  > | filter_set_opt {
  > if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
  > NULL)
  > fatal(NULL);
  > TAILQ_INIT($$);
  > TAILQ_INSERT_TAIL($$, $1, entry);
  > }
  > ;
  > delete          : /* empty */   { $$ = 0; }
  > | DELETE        { $$ = 1; }
  > ;
  > filter_set_opt  : LOCALPREF NUMBER              {
  > if ($2 < -INT_MAX || $2 > UINT_MAX) {
  > yyerror("bad localpref %lld", $2);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > if ($2 >= 0) {
  > $$->type = ACTION_SET_LOCALPREF;
  > $$->action.metric = $2;
  > } else {
  > $$->type = ACTION_SET_RELATIVE_LOCALPREF;
  > $$->action.relative = $2;
  > }
  > }
  > | LOCALPREF '+' NUMBER          {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad localpref +%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_LOCALPREF;
  > $$->action.relative = $3;
  > }
  > | LOCALPREF '-' NUMBER          {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad localpref -%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_LOCALPREF;
  > $$->action.relative = -$3;
  > }
  > | MED NUMBER                    {
  > if ($2 < -INT_MAX || $2 > UINT_MAX) {
  > yyerror("bad metric %lld", $2);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > if ($2 >= 0) {
  > $$->type = ACTION_SET_MED;
  > $$->action.metric = $2;
  > } else {
  > $$->type = ACTION_SET_RELATIVE_MED;
  > $$->action.relative = $2;
  > }
  > }
  > | MED '+' NUMBER                        {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad metric +%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_MED;
  > $$->action.relative = $3;
  > }
  > | MED '-' NUMBER                        {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad metric -%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_MED;
  > $$->action.relative = -$3;
  > }
  > | METRIC NUMBER                 {       /* alias for MED */
  > if ($2 < -INT_MAX || $2 > UINT_MAX) {
  > yyerror("bad metric %lld", $2);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > if ($2 >= 0) {
  > $$->type = ACTION_SET_MED;
  > $$->action.metric = $2;
  > } else {
  > $$->type = ACTION_SET_RELATIVE_MED;
  > $$->action.relative = $2;
  > }
  > }
  > | METRIC '+' NUMBER                     {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad metric +%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_MED;
  > $$->action.metric = $3;
  > }
  > | METRIC '-' NUMBER                     {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad metric -%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_MED;
  > $$->action.relative = -$3;
  > }
  > | WEIGHT NUMBER                         {
  > if ($2 < -INT_MAX || $2 > UINT_MAX) {
  > yyerror("bad weight %lld", $2);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > if ($2 > 0) {
  > $$->type = ACTION_SET_WEIGHT;
  > $$->action.metric = $2;
  > } else {
  > $$->type = ACTION_SET_RELATIVE_WEIGHT;
  > $$->action.relative = $2;
  > }
  > }
  > | WEIGHT '+' NUMBER                     {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad weight +%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_WEIGHT;
  > $$->action.relative = $3;
  > }
  > | WEIGHT '-' NUMBER                     {
  > if ($3 < 0 || $3 > INT_MAX) {
  > yyerror("bad weight -%lld", $3);
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_RELATIVE_WEIGHT;
  > $$->action.relative = -$3;
  > }
  > | NEXTHOP address               {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_NEXTHOP;
  > memcpy(&$$->action.nexthop, &$2,
  > sizeof($$->action.nexthop));
  > }
  > | NEXTHOP BLACKHOLE             {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_NEXTHOP_BLACKHOLE;
  > }
  > | NEXTHOP REJECT                {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_NEXTHOP_REJECT;
  > }
  > | NEXTHOP NOMODIFY              {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_NEXTHOP_NOMODIFY;
  > }
  > | NEXTHOP SELF          {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_NEXTHOP_SELF;
  > }
  > | PREPEND_SELF NUMBER           {
  > if ($2 < 0 || $2 > 128) {
  > yyerror("bad number of prepends");
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_PREPEND_SELF;
  > $$->action.prepend = $2;
  > }
  > | PREPEND_PEER NUMBER           {
  > if ($2 < 0 || $2 > 128) {
  > yyerror("bad number of prepends");
  > YYERROR;
  > }
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_PREPEND_PEER;
  > $$->action.prepend = $2;
  > }
  > | PFTABLE STRING                {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_PFTABLE;
  > if (!(cmd_opts & BGPD_OPT_NOACTION) &&
  > pftable_exists($2) != 0) {
  > yyerror("pftable name does not exist");
  > free($2);
  > free($$);
  > YYERROR;
  > }
  > if (strlcpy($$->action.pftable, $2,
  > sizeof($$->action.pftable)) >=
  > sizeof($$->action.pftable)) {
  > yyerror("pftable name too long");
  > free($2);
  > free($$);
  > YYERROR;
  > }
  > if (pftable_add($2) != 0) {
  > yyerror("Couldn't register table");
  > free($2);
  > free($$);
  > YYERROR;
  > }
  > free($2);
  > }
  > | RTLABEL STRING                {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_RTLABEL;
  > if (strlcpy($$->action.rtlabel, $2,
  > sizeof($$->action.rtlabel)) >=
  > sizeof($$->action.rtlabel)) {
  > yyerror("rtlabel name too long");
  > free($2);
  > free($$);
  > YYERROR;
  > }
  > free($2);
  > }
  > | COMMUNITY delete STRING       {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > if ($2)
  > $$->type = ACTION_DEL_COMMUNITY;
  > else
  > $$->type = ACTION_SET_COMMUNITY;
  > if (parsecommunity(&$$->action.community, $3) == -1) {
  > free($3);
  > free($$);
  > YYERROR;
  > }
  > free($3);
  > /* Don't allow setting of any match */
  > if (!$2 && ($$->action.community.as == COMMUNITY_ANY ||
  > $$->action.community.type == COMMUNITY_ANY)) {
  > yyerror("'*' is not allowed in set community");
  > free($$);
  > YYERROR;
  > }
  > }
  > | LARGECOMMUNITY delete STRING  {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > if ($2)
  > $$->type = ACTION_DEL_LARGE_COMMUNITY;
  > else
  > $$->type = ACTION_SET_LARGE_COMMUNITY;
  > if (parselargecommunity(&$$->action.large_community,
  > $3) == -1) {
  > free($3);
  > free($$);
  > YYERROR;
  > }
  > free($3);
  > /* Don't allow setting of any match */
  > if (!$2 &&
  > ($$->action.large_community.as == COMMUNITY_ANY ||
  > $$->action.large_community.ld1 == COMMUNITY_ANY ||
  > $$->action.large_community.ld2 == COMMUNITY_ANY)) {
  > yyerror("'*' is not allowed in set community");
  > free($$);
  > YYERROR;
  > }
  > }
  > | EXTCOMMUNITY delete STRING STRING {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > if ($2)
  > $$->type = ACTION_DEL_EXT_COMMUNITY;
  > else
  > $$->type = ACTION_SET_EXT_COMMUNITY;
  > if (parseextcommunity(&$$->action.ext_community,
  > $3, $4) == -1) {
  > free($3);
  > free($4);
  > free($$);
  > YYERROR;
  > }
  > free($3);
  > free($4);
  > }
  > | ORIGIN origincode {
  > if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
  > fatal(NULL);
  > $$->type = ACTION_SET_ORIGIN;
  > $$->action.origin = $2;
  > }
  > ;
  > origincode      : string {
  > if (!strcmp($1, "egp"))
  > $$ = ORIGIN_EGP;
  > else if (!strcmp($1, "igp"))
  > $$ = ORIGIN_IGP;
  > else if (!strcmp($1, "incomplete"))
  > $$ = ORIGIN_INCOMPLETE;
  > else {
  > yyerror("unknown origin \"%s\"", $1);
  > free($1);
  > YYERROR;
  > }
  > free($1);
  > };
  > comma           : ","
  > | /* empty */
  > ;
  > unaryop         : '='           { $$ = OP_EQ; }
  > | NE            { $$ = OP_NE; }
  > | LE            { $$ = OP_LE; }
  > | '<'           { $$ = OP_LT; }
  > | GE            { $$ = OP_GE; }
  > | '>'           { $$ = OP_GT; }
  > ;
  > equalityop      : '='           { $$ = OP_EQ; }
  > | NE            { $$ = OP_NE; }
  > ;
  > binaryop        : '-'           { $$ = OP_RANGE; }
  > | XRANGE        { $$ = OP_XRANGE; }
  > ;
  > %%
  > struct keywords {
  > const char      *k_name;
  > int              k_val;
  > };
  > int
  > yyerror(const char *fmt, ...)
  > {
  > va_list          ap;
  > char            *msg;
  > file->errors++;
  > va_start(ap, fmt);
  > if (vasprintf(&msg, fmt, ap) == -1)
  > fatalx("yyerror vasprintf");
  > va_end(ap);
  > logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
  > free(msg);
  > return (0);
  > }
  > int
  > kw_cmp(const void *k, const void *e)
  > {
  > return (strcmp(k, ((const struct keywords *)e)->k_name));
  > }
  > int
  > lookup(char *s)
  > {
  > /* this has to be sorted always */
  > static const struct keywords keywords[] = {
  > { "AS",                 AS},
  > { "IPv4",               IPV4},
  > { "IPv6",               IPV6},
  > { "ah",                 AH},
  > { "allow",              ALLOW},
  > { "announce",           ANNOUNCE},
  > { "any",                ANY},
  > { "as-4byte",           AS4BYTE },
  > { "blackhole",          BLACKHOLE},
  > { "capabilities",       CAPABILITIES},
  > { "community",          COMMUNITY},
  > { "compare",            COMPARE},
  > { "connect-retry",      CONNECTRETRY},
  > { "connected",          CONNECTED},
  > { "delete",             DELETE},
  > { "demote",             DEMOTE},
  > { "deny",               DENY},
  > { "depend",             DEPEND},
  > { "descr",              DESCR},
  > { "down",               DOWN},
  > { "dump",               DUMP},
  > { "ebgp",               EBGP},
  > { "enforce",            ENFORCE},
  > { "esp",                ESP},
  > { "evaluate",           EVALUATE},
  > { "export-target",      EXPORTTRGT},
  > { "ext-community",      EXTCOMMUNITY},
  > { "fib-priority",       FIBPRIORITY},
  > { "fib-update",         FIBUPDATE},
  > { "from",               FROM},
  > { "group",              GROUP},
  > { "holdtime",           HOLDTIME},
  > { "ibgp",               IBGP},
  > { "ignore",             IGNORE},
  > { "ike",                IKE},
  > { "import-target",      IMPORTTRGT},
  > { "in",                 IN},
  > { "include",            INCLUDE},
  > { "inet",               IPV4},
  > { "inet6",              IPV6},
  > { "ipsec",              IPSEC},
  > { "key",                KEY},
  > { "large-community",    LARGECOMMUNITY},
  > { "listen",             LISTEN},
  > { "local-address",      LOCALADDR},
  > { "local-as",           LOCALAS},
  > { "localpref",          LOCALPREF},
  > { "log",                LOG},
  > { "match",              MATCH},
  > { "max-as-len",         MAXASLEN},
  > { "max-as-seq",         MAXASSEQ},
  > { "max-prefix",         MAXPREFIX},
  > { "md5sig",             MD5SIG},
  > { "med",                MED},
  > { "metric",             METRIC},
  > { "min",                YMIN},
  > { "multihop",           MULTIHOP},
  > { "neighbor",           NEIGHBOR},
  > { "neighbor-as",        NEIGHBORAS},
  > { "network",            NETWORK},
  > { "nexthop",            NEXTHOP},
  > { "no-modify",          NOMODIFY},
  > { "on",                 ON},
  > { "or-longer",          LONGER},
  > { "origin",             ORIGIN},
  > { "out",                OUT},
  > { "passive",            PASSIVE},
  > { "password",           PASSWORD},
  > { "peer-as",            PEERAS},
  > { "pftable",            PFTABLE},
  > { "prefix",             PREFIX},
  > { "prefixlen",          PREFIXLEN},
  > { "prepend-neighbor",   PREPEND_PEER},
  > { "prepend-self",       PREPEND_SELF},
  > { "qualify",            QUALIFY},
  > { "quick",              QUICK},
  > { "rd",                 RD},
  > { "rde",                RDE},
  > { "rdomain",            RDOMAIN},
  > { "refresh",            REFRESH },
  > { "reject",             REJECT},
  > { "remote-as",          REMOTEAS},
  > { "restart",            RESTART},
  > { "restricted",         RESTRICTED},
  > { "rib",                RIB},
  > { "route-collector",    ROUTECOLL},
  > { "route-reflector",    REFLECTOR},
  > { "router-id",          ROUTERID},
  > { "rtable",             RTABLE},
  > { "rtlabel",            RTLABEL},
  > { "self",               SELF},
  > { "set",                SET},
  > { "socket",             SOCKET },
  > { "source-as",          SOURCEAS},
  > { "spi",                SPI},
  > { "static",             STATIC},
  > { "tcp",                TCP},
  > { "to",                 TO},
  > { "transit-as",         TRANSITAS},
  > { "transparent-as",     TRANSPARENT},
  > { "ttl-security",       TTLSECURITY},
  > { "via",                VIA},
  > { "weight",             WEIGHT}
  > };
  > const struct keywords   *p;
  > p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
  > sizeof(keywords[0]), kw_cmp);
  > if (p)
  > return (p->k_val);
  > else
  > return (STRING);
  > }
  > #define MAXPUSHBACK     128
  > u_char  *parsebuf;
  > int      parseindex;
  > u_char   pushback_buffer[MAXPUSHBACK];
  > int      pushback_index = 0;
  > int
  > lgetc(int quotec)
  > {
  > int             c, next;
  > if (parsebuf) {
  > /* Read character from the parsebuffer instead of input. */
  > if (parseindex >= 0) {
  > c = parsebuf[parseindex++];
  > if (c != '\0')
  > return (c);
  > parsebuf = NULL;
  > } else
  > parseindex++;
  > }
  > if (pushback_index)
  > return (pushback_buffer[--pushback_index]);
  > if (quotec) {
  > if ((c = getc(file->stream)) == EOF) {
  > yyerror("reached end of file while parsing "
  > "quoted string");
  > if (file == topfile || popfile() == EOF)
  > return (EOF);
  > return (quotec);
  > }
  > return (c);
  > }
  > while ((c = getc(file->stream)) == '\\') {
  > next = getc(file->stream);
  > if (next != '\n') {
  > c = next;
  > break;
  > }
  > yylval.lineno = file->lineno;
  > file->lineno++;
  > }
  > while (c == EOF) {
  > if (file == topfile || popfile() == EOF)
  > return (EOF);
  > c = getc(file->stream);
  > }
  > return (c);
  > }
  > int
  > lungetc(int c)
  > {
  > if (c == EOF)
  > return (EOF);
  > if (parsebuf) {
  > parseindex--;
  > if (parseindex >= 0)
  > return (c);
  > }
  > if (pushback_index < MAXPUSHBACK-1)
  > return (pushback_buffer[pushback_index++] = c);
  > else
  > return (EOF);
  > }
  > int
  > findeol(void)
  > {
  > int     c;
  > parsebuf = NULL;
  > /* skip to either EOF or the first real EOL */
  > while (1) {
  > if (pushback_index)
  > c = pushback_buffer[--pushback_index];
  > else
  > c = lgetc(0);
  > if (c == '\n') {
  > file->lineno++;
  > break;
  > }
  > if (c == EOF)
  > break;
  > }
  > return (ERROR);
  > }
  > int
  > yylex(void)
  > {
  > u_char   buf[8096];
  > u_char  *p, *val;
  > int      quotec, next, c;
  > int      token;
  > top:
  > p = buf;
  > while ((c = lgetc(0)) == ' ' || c == '\t')
  > ; /* nothing */
  > yylval.lineno = file->lineno;
  > if (c == '#')
  > while ((c = lgetc(0)) != '\n' && c != EOF)
  > ; /* nothing */
  > if (c == '$' && parsebuf == NULL) {
  > while (1) {
  > if ((c = lgetc(0)) == EOF)
  > return (0);
  > if (p + 1 >= buf + sizeof(buf) - 1) {
  > yyerror("string too long");
  > return (findeol());
  > }
  > if (isalnum(c) || c == '_') {
  > *p++ = c;
  > continue;
  > }
  > *p = '\0';
  > lungetc(c);
  > break;
  > }
  > val = symget(buf);
  > if (val == NULL) {
  > yyerror("macro '%s' not defined", buf);
  > return (findeol());
  > }
  > parsebuf = val;
  > parseindex = 0;
  > goto top;
  > }
  > switch (c) {
  > case '\'':
  > case '"':
  > quotec = c;
  > while (1) {
  > if ((c = lgetc(quotec)) == EOF)
  > return (0);
  > if (c == '\n') {
  > file->lineno++;
  > continue;
  > } else if (c == '\\') {
  > if ((next = lgetc(quotec)) == EOF)
  > return (0);
  > if (next == quotec || c == ' ' || c == '\t')
  > c = next;
  > else if (next == '\n') {
  > file->lineno++;
  > continue;
  > } else
  > lungetc(next);
  > } else if (c == quotec) {
  > *p = '\0';
  > break;
  > } else if (c == '\0') {
  > yyerror("syntax error");
  > return (findeol());
  > }
  > if (p + 1 >= buf + sizeof(buf) - 1) {
  > yyerror("string too long");
  > return (findeol());
  > }
  > *p++ = c;
  > }
  > yylval.v.string = strdup(buf);
  > if (yylval.v.string == NULL)
  > fatal("yylex: strdup");
  > return (STRING);
  > case '!':
  > next = lgetc(0);
  > if (next == '=')
  > return (NE);
  > lungetc(next);
  > break;
  > case '<':
  > next = lgetc(0);
  > if (next == '=')
  > return (LE);
  > lungetc(next);
  > break;
  > case '>':
  > next = lgetc(0);
  > if (next == '<')
  > return (XRANGE);
  > else if (next == '=')
  > return (GE);
  > lungetc(next);
  > break;
  > }
  > #define allowed_to_end_number(x) \
  > (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
  > if (c == '-' || isdigit(c)) {
  > do {
  > *p++ = c;
  > if ((unsigned)(p-buf) >= sizeof(buf)) {
  > yyerror("string too long");
  > return (findeol());
  > }
  > } while ((c = lgetc(0)) != EOF && isdigit(c));
  > lungetc(c);
  > if (p == buf + 1 && buf[0] == '-')
  > goto nodigits;
  > if (c == EOF || allowed_to_end_number(c)) {
  > const char *errstr = NULL;
  > *p = '\0';
  > yylval.v.number = strtonum(buf, LLONG_MIN,
  > LLONG_MAX, &errstr);
  > if (errstr) {
  > yyerror("\"%s\" invalid number: %s",
  > buf, errstr);
  > return (findeol());
  > }
  > return (NUMBER);
  > } else {
  > nodigits:
  > while (p > buf + 1)
  > lungetc(*--p);
  > c = *--p;
  > if (c == '-')
  > return (c);
  > }
  > }
  > #define allowed_in_string(x) \
  > (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
  > x != '{' && x != '}' && x != '<' && x != '>' && \
  > x != '!' && x != '=' && x != '/' && x != '#' && \
  > x != ','))
  > if (isalnum(c) || c == ':' || c == '_' || c == '*') {
  > do {
  > *p++ = c;
  > if ((unsigned)(p-buf) >= sizeof(buf)) {
  > yyerror("string too long");
  > return (findeol());
  > }
  > } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
  > lungetc(c);
  > *p = '\0';
  > if ((token = lookup(buf)) == STRING)
  > if ((yylval.v.string = strdup(buf)) == NULL)
  > fatal("yylex: strdup");
  > return (token);
  > }
  > if (c == '\n') {
  > yylval.lineno = file->lineno;
  > file->lineno++;
  > }
  > if (c == EOF)
  > return (0);
  > return (c);
  > }
  > int
  > check_file_secrecy(int fd, const char *fname)
  > {
  > struct stat     st;
  > if (fstat(fd, &st)) {
  > log_warn("cannot stat %s", fname);
  > return (-1);
  > }
  > return (0);
  > }
  > struct file *
  > pushfile(const char *name, int secret)
  > {
  > struct file     *nfile;
  > if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
  > log_warn("malloc");
  > return (NULL);
  > }
  > if ((nfile->name = strdup(name)) == NULL) {
  > log_warn("malloc");
  > free(nfile);
  > return (NULL);
  > }
  > if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
  > log_warn("%s", nfile->name);
  > free(nfile->name);
  > free(nfile);
  > return (NULL);
  > }
  > if (secret &&
  > check_file_secrecy(fileno(nfile->stream), nfile->name)) {
  > fclose(nfile->stream);
  > free(nfile->name);
  > free(nfile);
  > return (NULL);
  > }
  > nfile->lineno = 1;
  > TAILQ_INSERT_TAIL(&files, nfile, entry);
  > return (nfile);
  > }
  > int
  > popfile(void)
  > {
  > struct file     *prev;
  > if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
  > prev->errors += file->errors;
  > TAILQ_REMOVE(&files, file, entry);
  > fclose(file->stream);
  > free(file->name);
  > free(file);
  > file = prev;
  > return (file ? 0 : EOF);
  > }
  > int
  > parse_config(char *filename, struct bgpd_config *xconf, struct peer
  > **xpeers)
  > {
  > struct sym              *sym, *next;
  > struct peer             *p, *pnext;
  > struct rde_rib          *rr;
  > int                      errors = 0;
  > conf = new_config();
  > if ((filter_l = calloc(1, sizeof(struct filter_head))) == NULL)
  > fatal(NULL);
  > if ((peerfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
  > fatal(NULL);
  > if ((groupfilter_l = calloc(1, sizeof(struct filter_head))) == NULL)
  > fatal(NULL);
  > TAILQ_INIT(filter_l);
  > TAILQ_INIT(peerfilter_l);
  > TAILQ_INIT(groupfilter_l);
  > peer_l = NULL;
  > peer_l_old = *xpeers;
  > curpeer = NULL;
  > curgroup = NULL;
  > id = 1;
  > netconf = &conf->networks;
  > add_rib("Adj-RIB-In", conf->default_tableid,
  > F_RIB_NOFIB | F_RIB_NOEVALUATE);
  > add_rib("Loc-RIB", conf->default_tableid, F_RIB_LOCAL);
  > if ((file = pushfile(filename, 1)) == NULL) {
  > free(conf);
  > return (-1);
  > }
  > topfile = file;
  > yyparse();
  > errors = file->errors;
  > popfile();
  > /* Free macros and check which have not been used. */
  > TAILQ_FOREACH_SAFE(sym, &symhead, entry, next) {
  > if ((cmd_opts & BGPD_OPT_VERBOSE2) && !sym->used)
  > fprintf(stderr, "warning: macro \"%s\" not "
  > "used\n", sym->nam);
  > if (!sym->persist) {
  > free(sym->nam);
  > free(sym->val);
  > TAILQ_REMOVE(&symhead, sym, entry);
  > free(sym);
  > }
  > }
  > if (errors) {
  > for (p = peer_l; p != NULL; p = pnext) {
  > pnext = p->next;
  > free(p);
  > }
  > while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) {
  > SIMPLEQ_REMOVE_HEAD(&ribnames, entry);
  > free(rr);
  > }
  > filterlist_free(filter_l);
  > filterlist_free(peerfilter_l);
  > filterlist_free(groupfilter_l);
  > free_config(conf);
  > } else {
  > /*
  > * Move filter list and static group and peer filtersets
  > * together. Static group sets come first then peer sets
  > * last normal filter rules.
  > */
  > merge_filter_lists(conf->filters, groupfilter_l);
  > merge_filter_lists(conf->filters, peerfilter_l);
  > merge_filter_lists(conf->filters, filter_l);
  > errors += mrt_mergeconfig(xconf->mrt, conf->mrt);
  > errors += merge_config(xconf, conf, peer_l);
  > *xpeers = peer_l;
  > for (p = peer_l_old; p != NULL; p = pnext) {
  > pnext = p->next;
  > free(p);
  > }
  > free(filter_l);
  > free(peerfilter_l);
  > free(groupfilter_l);
  > }
  > return (errors ? -1 : 0);
  > }
  > int
  > symset(const char *nam, const char *val, int persist)
  > {
  > struct sym      *sym;
  > TAILQ_FOREACH(sym, &symhead, entry) {
  > if (strcmp(nam, sym->nam) == 0)
  > break;
  > }
  > if (sym != NULL) {
  > if (sym->persist == 1)
  > return (0);
  > else {
  > free(sym->nam);
  > free(sym->val);
  > TAILQ_REMOVE(&symhead, sym, entry);
  > free(sym);
  > }
  > }
  > if ((sym = calloc(1, sizeof(*sym))) == NULL)
  > return (-1);
  > sym->nam = strdup(nam);
  > if (sym->nam == NULL) {
  > free(sym);
  > return (-1);
  > }
  > sym->val = strdup(val);
  > if (sym->val == NULL) {
  > free(sym->nam);
  > free(sym);
  > return (-1);
  > }
  > sym->used = 0;
  > sym->persist = persist;
  > TAILQ_INSERT_TAIL(&symhead, sym, entry);
  > return (0);
  > }
  > int
  > cmdline_symset(char *s)
  > {
  > char    *sym, *val;
  > int     ret;
  > size_t  len;
  > if ((val = strrchr(s, '=')) == NULL)
  > return (-1);
  > len = strlen(s) - strlen(val) + 1;
  > if ((sym = malloc(len)) == NULL)
  > fatal("cmdline_symset: malloc");
  > strlcpy(sym, s, len);
  > ret = symset(sym, val + 1, 1);
  > free(sym);
  > return (ret);
  > }
  > char *
  > symget(const char *nam)
  > {
  > struct sym      *sym;
  > TAILQ_FOREACH(sym, &symhead, entry) {
  > if (strcmp(nam, sym->nam) == 0) {
  > sym->used = 1;
  > return (sym->val);
  > }
  > }
  > return (NULL);
  > }
  > int
  > getcommunity(char *s)
  > {
  > int              val;
  > const char      *errstr;
  > if (strcmp(s, "*") == 0)
  > return (COMMUNITY_ANY);
  > if (strcmp(s, "neighbor-as") == 0)
  > return (COMMUNITY_NEIGHBOR_AS);
  > if (strcmp(s, "local-as") == 0)
  > return (COMMUNITY_LOCAL_AS);
  > val = strtonum(s, 0, USHRT_MAX, &errstr);
  > if (errstr) {
  > yyerror("Community %s is %s (max: %u)", s, errstr, USHRT_MAX);
  > return (COMMUNITY_ERROR);
  > }
  > return (val);
  > }
  > int
  > parsecommunity(struct filter_community *c, char *s)
  > {
  > char *p;
  > int i, as;
  > /* Well-known communities */
  > if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) {
  > c->as = COMMUNITY_WELLKNOWN;
  > c->type = COMMUNITY_GRACEFUL_SHUTDOWN;
  > return (0);
  > } else if (strcasecmp(s, "NO_EXPORT") == 0) {
  > c->as = COMMUNITY_WELLKNOWN;
  > c->type = COMMUNITY_NO_EXPORT;
  > return (0);
  > } else if (strcasecmp(s, "NO_ADVERTISE") == 0) {
  > c->as = COMMUNITY_WELLKNOWN;
  > c->type = COMMUNITY_NO_ADVERTISE;
  > return (0);
  > } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) {
  > c->as = COMMUNITY_WELLKNOWN;
  > c->type = COMMUNITY_NO_EXPSUBCONFED;
  > return (0);
  > } else if (strcasecmp(s, "NO_PEER") == 0) {
  > c->as = COMMUNITY_WELLKNOWN;
  > c->type = COMMUNITY_NO_PEER;
  > return (0);
  > } else if (strcasecmp(s, "BLACKHOLE") == 0) {
  > c->as = COMMUNITY_WELLKNOWN;
  > c->type = COMMUNITY_BLACKHOLE;
  > return (0);
  > }
  > if ((p = strchr(s, ':')) == NULL) {
  > yyerror("Bad community syntax");
  > return (-1);
  > }
  > *p++ = 0;
  > if ((i = getcommunity(s)) == COMMUNITY_ERROR)
  > return (-1);
  > as = i;
  > if ((i = getcommunity(p)) == COMMUNITY_ERROR)
  > return (-1);
  > c->as = as;
  > c->type = i;
  > return (0);
  > }
  > int64_t
  > getlargecommunity(char *s)
  > {
  > u_int            val;
  > const char      *errstr;
  > if (strcmp(s, "*") == 0)
  > return (COMMUNITY_ANY);
  > if (strcmp(s, "neighbor-as") == 0)
  > return (COMMUNITY_NEIGHBOR_AS);
  > if (strcmp(s, "local-as") == 0)
  > return (COMMUNITY_LOCAL_AS);
  > val = strtonum(s, 0, UINT_MAX, &errstr);
  > if (errstr) {
  > yyerror("Large Community %s is %s (max: %u)",
  > s, errstr, UINT_MAX);
  > return (COMMUNITY_ERROR);
  > }
  > return (val);
  > }
  > int
  > parselargecommunity(struct filter_largecommunity *c, char *s)
  > {
  > char *p, *q;
  > int64_t as, ld1, ld2;
  > if ((p = strchr(s, ':')) == NULL) {
  > yyerror("Bad community syntax");
  > return (-1);
  > }
  > *p++ = 0;
  > if ((q = strchr(p, ':')) == NULL) {
  > yyerror("Bad community syntax");
  > return (-1);
  > }
  > *q++ = 0;
  > if ((as = getlargecommunity(s)) == COMMUNITY_ERROR)
  > return (-1);
  > if ((ld1 = getlargecommunity(p)) == COMMUNITY_ERROR)
  > return (-1);
  > if ((ld2 = getlargecommunity(q)) == COMMUNITY_ERROR)
  > return (-1);
  > c->as = as;
  > c->ld1 = ld1;
  > c->ld2 = ld2;
  > return (0);
  > }
  > int
  > parsesubtype(char *name, int *type, int *subtype)
  > {
  > const struct ext_comm_pairs *cp;
  > int found = 0;
  > for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
  > if (strcmp(name, cp->subname) == 0) {
  > if (found == 0) {
  > *type = cp->type;
  > *subtype = cp->subtype;
  > }
  > found++;
  > }
  > }
  > if (found > 1)
  > *type = -1;
  > return (found);
  > }
  > int
  > parseextvalue(char *s, u_int32_t *v)
  > {
  > const char      *errstr;
  > char            *p;
  > struct in_addr   ip;
  > u_int32_t        uvalh = 0, uval;
  > if ((p = strchr(s, '.')) == NULL) {
  > /* AS_PLAIN number (4 or 2 byte) */
  > uval = strtonum(s, 0, UINT_MAX, &errstr);
  > if (errstr) {
  > yyerror("Bad ext-community %s is %s", s, errstr);
  > return (-1);
  > }
  > *v = uval;
  > if (uval <= USHRT_MAX)
  > return (EXT_COMMUNITY_TRANS_TWO_AS);
  > else
  > return (EXT_COMMUNITY_TRANS_FOUR_AS);
  > } else if (strchr(p + 1, '.') == NULL) {
  > /* AS_DOT number (4-byte) */
  > *p++ = '\0';
  > uvalh = strtonum(s, 0, USHRT_MAX, &errstr);
  > if (errstr) {
  > yyerror("Bad ext-community %s is %s", s, errstr);
  > return (-1);
  > }
  > uval = strtonum(p, 0, USHRT_MAX, &errstr);
  > if (errstr) {
  > yyerror("Bad ext-community %s is %s", p, errstr);
  > return (-1);
  > }
  > *v = uval | (uvalh << 16);
  > return (EXT_COMMUNITY_TRANS_FOUR_AS);
  > } else {
  > /* more than one dot -> IP address */
  > if (inet_aton(s, &ip) == 0) {
  > yyerror("Bad ext-community %s not parseable", s);
  > return (-1);
  > }
  > *v = ip.s_addr;
  > return (EXT_COMMUNITY_TRANS_IPV4);
  > }
  > return (-1);
  > }
  > int
  > parseextcommunity(struct filter_extcommunity *c, char *t, char *s)
  > {
  > const struct ext_comm_pairs *cp;
  > const char      *errstr;
  > u_int64_t        ullval;
  > u_int32_t        uval;
  > char            *p, *ep;
  > int              type, subtype;
  > if (parsesubtype(t, &type, &subtype) == 0) {
  > yyerror("Bad ext-community unknown type");
  > return (-1);
  > }
  > switch (type) {
  > case -1:
  > if ((p = strchr(s, ':')) == NULL) {
  > yyerror("Bad ext-community %s is %s", s, errstr);
  > return (-1);
  > }
  > *p++ = '\0';
  > if ((type = parseextvalue(s, &uval)) == -1)
  > return (-1);
  > switch (type) {
  > case EXT_COMMUNITY_TRANS_TWO_AS:
  > ullval = strtonum(p, 0, UINT_MAX, &errstr);
  > break;
  > case EXT_COMMUNITY_TRANS_IPV4:
  > case EXT_COMMUNITY_TRANS_FOUR_AS:
  > ullval = strtonum(p, 0, USHRT_MAX, &errstr);
  > break;
  > default:
  > fatalx("parseextcommunity: unexpected result");
  > }
  > if (errstr) {
  > yyerror("Bad ext-community %s is %s", p, errstr);
  > return (-1);
  > }
  > switch (type) {
  > case EXT_COMMUNITY_TRANS_TWO_AS:
  > c->data.ext_as.as = uval;
  > c->data.ext_as.val = ullval;
  > break;
  > case EXT_COMMUNITY_TRANS_IPV4:
  > c->data.ext_ip.addr.s_addr = uval;
  > c->data.ext_ip.val = ullval;
  > break;
  > case EXT_COMMUNITY_TRANS_FOUR_AS:
  > c->data.ext_as4.as4 = uval;
  > c->data.ext_as4.val = ullval;
  > break;
  > }
  > break;
  > case EXT_COMMUNITY_TRANS_OPAQUE:
  > case EXT_COMMUNITY_TRANS_EVPN:
  > errno = 0;
  > ullval = strtoull(s, &ep, 0);
  > if (s[0] == '\0' || *ep != '\0') {
  > yyerror("Bad ext-community bad value");
  > return (-1);
  > }
  > if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) {
  > yyerror("Bad ext-community value too big");
  > return (-1);
  > }
  > c->data.ext_opaq = ullval;
  > break;
  > case EXT_COMMUNITY_NON_TRANS_OPAQUE:
  > if (strcmp(s, "valid") == 0)
  > c->data.ext_opaq = EXT_COMMUNITY_OVS_VALID;
  > else if (strcmp(s, "invalid") == 0)
  > c->data.ext_opaq = EXT_COMMUNITY_OVS_INVALID;
  > else if (strcmp(s, "not-found") == 0)
  > c->data.ext_opaq = EXT_COMMUNITY_OVS_NOTFOUND;
  > else {
  > yyerror("Bad ext-community %s is %s", s, errstr);
  > return (-1);
  > }
  > break;
  > }
  > c->type = type;
  > c->subtype = subtype;
  > /* verify type/subtype combo */
  > for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
  > if (cp->type == type && cp->subtype == subtype) {
  > c->flags |= EXT_COMMUNITY_FLAG_VALID;
  > return (0);
  > }
  > }
  > yyerror("Bad ext-community bad format for type");
  > return (-1);
  > }
  > struct peer *
  > alloc_peer(void)
  > {
  > struct peer     *p;
  > u_int8_t         i;
  > if ((p = calloc(1, sizeof(struct peer))) == NULL)
  > fatal("new_peer");
  > /* some sane defaults */
  > p->state = STATE_NONE;
  > p->next = NULL;
  > p->conf.distance = 1;
  > p->conf.announce_type = ANNOUNCE_UNDEF;
  > p->conf.announce_capa = 1;
  > for (i = 0; i < AID_MAX; i++)
  > p->conf.capabilities.mp[i] = -1;
  > p->conf.capabilities.refresh = 1;
  > p->conf.capabilities.grestart.restart = 1;
  > p->conf.capabilities.as4byte

  ~ Makefile                              ~ pfkey.c

  > undo unintentional commits (phessler@)

ifstated

  ~ parse.y                               

  > Remove unnecessary NULL check and fix an incorrect warning.
  > Ok jca@ (rob@)

radiusd

  ~ radiusd_bsdauth.c                     

  > Use waitpid()/EINTR idiom for the specific pid, rather than generic wait(),
  > in case the parent process was started with a dangling child.  This style
  > ensures any potential parent:child interlock isn't disrupted due to the
  > "wrong" child being waited on first.  Then the other other childs can
  > safely
  > zombie.
  > ok millert jca brynet (deraadt@)

===============================================================================
_______________________________________________
odc mailing list
[email protected]
http://www.squish.net/mailman/listinfo/odc

Reply via email to