%{
/*
 *  parser.y,v 1.131.2.5 1994/03/18 22:56:17 jch Exp
 */

/* Gated Release 3.5 */
/* Copyright (c) 1990,1991,1992,1993,1994 by Cornell University. All rights */
/* reserved. Refer to Particulars and other Copyright notices at the end of this */
/* file. */

#include "include.h"
@BEGIN:	PROTO_INET
#include "inet.h"
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
#include "iso.h"
@END:	PROTO_ISO
#include "parse.h"
#include "krt.h"
@BEGIN:	PROTO_RIP
#include "rip.h"
@END:	PROTO_RIP
@BEGIN:	PROTO_HELLO
#include "hello.h"
@END:	PROTO_HELLO
@BEGIN:	PROTO_ICMP
#include "icmp.h"
@END:	PROTO_ICMP
@BEGIN:	PROTO_OSPF
#include "ospf.h"
@END:	PROTO_OSPF
@BEGIN:	PROTO_IDPR
#include "idpr.h"
@END:	PROTO_IDPR
@BEGIN:	PROTO_EGP
#include "egp.h"
@END:	PROTO_EGP
@BEGIN:	PROTO_BGP
#include "bgp.h"
@END:	PROTO_BGP
@BEGIN:	PROTO_DVMRP
#include "dvmrp.h"
@END:	PROTO_DVMRP
@BEGIN:	PROTO_ISODE_SNMP
#include "snmp_isode.h"
@END:	PROTO_ISODE_SNMP
@BEGIN:	PROTO_ISIS
#include "isis.h"
#include "isis_test.h"
#include "isis_globals.h"
@END:	PROTO_ISIS
@BEGIN:	PROTO_SLSP
#include "slsp.h"
@END:	PROTO_SLSP
@BEGIN:	PROTO_RDISC
#include "rdisc.h"
@END:	PROTO_RDISC
@BEGIN:	PROTO_IDRP
#include "idrp.h"
@END:	PROTO_IDRP
#undef	vsprintf

char parse_error[LINE_MAX] = { 0 };
char *parse_filename = 0;

static	proto_t	parse_proto;			/* For correctly tagging ADV lists */
static	proto_t	parse_export_proto;		/* For checking metrics */
static	gw_entry	**parse_gwlist;
@BEGIN:	PROTO_INET
static	gw_entry	*parse_gwp;		/* To fake a list for EGP and BGP */
@END:	PROTO_INET
@BEGIN:	PARSE_PORT
static  char *parse_serv_proto;
@END:	PARSE_PORT
static	int	parse_contig_masks = TRUE;	/* Masks must be contiguous */
@BEGIN:	PROTO_EGP
static	int parse_group_index;
static	egp_neighbor *ngp, egp_group, *gr_ngp;
@END:	PROTO_EGP
@BEGIN:	PROTO_BGP
static	bgpPeer *bnp;
static	bgpPeerGroup *bgp;
static 	struct bgp_conf *bcp;
@END:	PROTO_BGP
@BEGIN:	PROTO_OSPF
static struct AREA *ospf_AREA;
@END:	PROTO_OSPF
@BEGIN:	PROTO_SLSP
static slsp_instance *slsp_parse_instance;
static slsp_gateway *slsp_parse_gateway;
@END:	PROTO_SLSP
@BEGIN:	PROTO_IDRP
static	idrpPeer *idgp = (idrpPeer *) NULL; 
static	idrp_group_parms	idrp_grp;	
struct	iso_prefix *nlri; 
static	idrpRoute *p_idrp;
static	int idrp_parse_group_index;
static	idrpRoute_options 	*p_idrp_opts,*p_idrp_opts_old;	
static	idrpRoute_options 	*p_idrp_ps_atts = (idrpRoute_options *) NULL;	
static  idrp_distinguish_att	*p_qos;
static  idrp_qos_rib		*p_rib;
static  qos_operator	*p_qos_op;
static	snpa_list	*p_snpa_list = (snpa_list *) NULL;
static  struct _adv_entry *p_adv;
#define PS_NONE -1
#define PS_OFF 0
#define PS_ON  1
static  int idrp_have_nexthop = FALSE;
static  int idrp_ps_flag = PS_NONE;
static  int junk_int;
static  struct _idrp_canon_rdpath *p_idrp_dist_canon_rdpath = (struct _idrp_canon_rdpath *) NULL;
@END:	PROTO_IDRP
@BEGIN:	PROTO_RDPATHS
static	idrp_canon_rdpath	*p_rdi_head,*p_rdi_tail;
static	idrp_canon_rdpath	*p_idrp_excl_rdi_tail, *p_idrp_excl_rdi_head;
static	idrp_canon_rdpath	*p_idrp_incl_rdi_tail, *p_idrp_incl_rdi_head;
static  idrp_canon_rdpath	*p_idrp_incl =  NULL; /* @@@ (idrp_canon_rdpath) NULL,
							*p_idrp_excl = (idrp_canon_rdpath) NULL;*/
struct  _RD_path *p_rdpath, *p_old_rdpath_part, *p_new_rdpath_part;
@END:	PROTO_RDPATHS
static if_info parse_ifi;	/* Used for configuring interfaces that do not exist */

u_int parse_state = PS_INITIAL;
proto_t protos_seen = 0;

PROTOTYPE(yyerror,
	  static void,
	  (const char *));

#define	free_string(s)	task_mem_free((task *) 0, (caddr_t) s); s = 0
#define	free_charstr(s)	task_mem_free((task *) 0, (caddr_t) (s)->ptr); (s)->ptr = (char *) 0; (s)->len = (s)->type = 0
#define	free_bytestr(s)	task_mem_free((task *) 0, (caddr_t) (s)->ptr); (s)->ptr = (byte *) 0; (s)->len = (s)->type = 0

#define	PARSE_ERROR	yyerror(parse_error); yynerrs++; YYERROR;

#define	PROTO_SEEN(proto) \
	if (BIT_TEST(protos_seen, RTPROTO_BIT(proto))) { \
	    sprintf(parse_error, "parse_proto_seen: duplicate %s clause", gd_lower(trace_state(rt_proto_bits, proto))); \
	    PARSE_ERROR; \
	} else { \
	    BIT_SET(protos_seen, RTPROTO_BIT(proto)); \
	    parse_proto = proto; \
	} \

%}

/* Global */
%union {
    long	num;
    u_long	u_num;
    bytestr	hex;
    charstr	str;
    flag_t	flag;
    time_t	time;
    utime_t	utime;
    as_t	as;
    proto_t	proto;
    pmet_t	metric;
    pref_t	pref;
    if_addr	*ifap;
    if_addr_entry	*ifae;
    adv_entry	*adv;
    gw_entry	*gwp;
    void_t	vt;
    sockaddr_un	*sockaddr;
    trace_file	*trace_file;
#ifdef	PROTO_INET
    struct in_addr in_addr;
#endif	/* PROTO_INET */
    dest_mask	dm;
    struct {
	pmet_t metric;
	adv_entry *adv;
    } metric_adv ;
    struct {
	proto_t proto;
	adv_entry **import_list;
	adv_entry **export_list;
	gw_entry **gw_list;
    } proto_lists;
    config_entry *config;
    config_list *conflist;
#ifndef	GATED_LEXER
#ifdef	PROTO_OSPF
    ospf_config_router *ospf_router;
#endif	/* PROTO_OSPF */
#ifdef PROTO_RDPATHS
    struct _RD_path *rdp_match;
    struct _idrp_canon_rdpath *p_idrp_canon_rdpath;
#endif
/* TODO SJR--clean this up */
    struct _policy_rdpath *p_policy_rdpath;
    struct _idrp_canon_rdpath *p_idrp_canon_rdpath;
#ifdef	PROTO_ASPATHS
    as_path *aspath;
    asmatch_t *asp_match;
    asp_range asp_range;
    asp_stack asp_stack;
#endif	/* PROTO_ASPATHS */
#endif	/* GATED_LEXER */
}

/* Lexer tokens */
%token			L_EOS L_ERROR
%token	<num>		L_NUMBER
%token	<str>		L_STRING L_HNAME L_KEYWORD L_OPERATOR
%token	<hex>		L_HEXSTRING L_OCTETSTRING L_HEXSTRING_ODD
@BEGIN:	PROTO_ISO
%token	<hex>		L_ISOADDR
@END:	PROTO_ISO

/* Keyword tokens */    
%token	<num>		T_DIRECT T_INTERFACE T_INTERFACES T_LCLADDR
%token	<num>		T_PROTO T_METRIC T_METRICIN T_METRICOUT T_INFINITY T_DOWN
%token	<num>		T_PARSE T_ADV T_DEFAULT T_DEFAULTS
%token	<num>		T_YYDEBUG T_YYSTATE T_YYQUIT T_DEBUG
%token	<num>		T_SYSLOG T_UPTO T_EMERG T_ALERT T_CRIT T_ERR T_WARNING T_NOTICE T_INFO
%token	<num>		T_ON T_OFF T_GATEWAY T_PREFERENCE T_PREFERENCE2
%token	<num>		T_DEFAULTMETRIC T_NONBROADCAST T_BROADCAST T_TYPE
%token	<num>		T_POINTOPOINT T_MULTICAST T_NETMASK T_DEFINE
%token	<num>		T_INTERNAL T_EXTERNAL
%token	<num>		T_IGNORE

/* Filler for conditional clauses */
%token			T_NOP T_NOP1
%token	<dm>		T_NOP_DM
%token	<adv>		T_NOP_ADV
%token	<proto>		T_NOP_PROTO
%token	<sockaddr>	T_NOP_SOCKADDR

%type	<num>		syslog_level syslog_mask
%type	<time>		mark_time    

/* BGP and EGP */
%token	<num>		T_PEERAS T_LOCALAS T_GROUP
%token			T_NEIGHBOR
%token	<num>		T_NOGENDEFAULT T_VERSION
%token	<num>		T_ACQUIRE T_TTL
%type	<num>		inet_ttl

/* BGP and IDRP */
%token 	<num>		T_TEST T_HOLDTIME
%token	<num>		T_KEEPALIVE T_OPEN

@BEGIN:	PROTO_EGP
%token	<num>		T_MAXUP T_SOURCENET T_PKTSIZE T_P1 T_P2 T_DEFAULTIN T_DEFAULTOUT
%type	<u_num>		egp_trace_option_index    
%type	<flag>		egp_trace_options_none egp_trace_options egp_trace_option
%type	<proto>		egp_prop_init    
@END:	PROTO_EGP
@BEGIN:	PROTO_BGP
%token	<num>		T_BGP T_KEEP T_SENDBUF T_RECVBUF T_INDELAY T_OUTDELAY
%token	<num>		T_ROUTING T_ANALRETENTIVE T_KEEPALIVESALWAYS T_NOAGGRID T_NOAUTHCHECK T_SETPREF
%type	<num>		bgp_linktype bgp_kbufsize
%type	<flag>		bgp_trace_options_none bgp_trace_options bgp_trace_option
%type	<u_num>		bgp_trace_option_index
%type	<proto>		bgp_prop_init bgp_proto_option bgp_proto
%type	<dm>		bgp_allow
%type	<adv>		bgp_allow_list    
@END:	PROTO_BGP

/* Needed for both EGP and AS paths */    
%token	<num>		T_EGP 

/* for PROTO_ASPATHS or PROTO_IDRP */
%token	<num>		T_ANY

@BEGIN:	PROTO_ASPATHS
/* AS Paths */    
%token	<num>		T_ASPATH T_ORIGIN T_INCOMPLETE T_LOOPS
%type	<asp_match>	aspath_match
%type	<asp_stack>	aspath_regex aspath_sum aspath_symbol aspath_term
%type	<asp_range>	aspath_range
%type	<flag>		aspath_origin_list aspath_origins aspath_origin
%type	<proto>		aspath_prop_init    
/* Tags */
%token	<num>		T_TAG
%type	<metric>	tag_option tag_as tag_as_option tag
%type	<proto>		tag_prop_init
@END:	PROTO_ASPATHS

/* Kernel */
%token	<num>		T_KERNEL T_SYMBOLS T_REMNANTS T_IFLIST T_ROUTES
%token	<num>		T_NOCHANGE T_NOFLUSHATEXIT T_REMNANTHOLDTIME
%token	<num>		T_HIGHER T_LOWER T_FLASH T_INTERIOR T_BACKGROUND T_LIMIT
%type	<u_num>		kernel_trace_option_index
%type	<flag>		kernel_trace_options_none kernel_trace_options kernel_trace_option
%type	<flag>		kernel_flash_type kernel_bg_type
   
/* RIP and HELLO */
%token	<num>		T_TRUSTEDGATEWAYS T_SOURCEGATEWAYS
%token	<num>		T_RIP
@BEGIN:	PROTO_RIP
%token	<num>		T_RIPOUT T_NORIPOUT T_RIPIN T_NORIPIN T_NOCHECKZERO
%type	<config>	rip_interface_option rip_interface_options
%type	<u_num>		rip_trace_option_index
%type	<flag>		rip_trace_options_none rip_trace_options rip_trace_option rip_v2_options
%type	<proto>		rip_prop_init
%type	<vt>		rip_auth
@END:	PROTO_RIP

@BEGIN:	PROTO_HELLO
%token	<num>		T_HELLOOUT T_HELLOIN T_NOHELLOOUT T_NOHELLOIN
%type	<config>	hello_interface_option hello_interface_options    
%type	<u_num>		hello_trace_option_index    
%type	<flag>		hello_trace_options_none hello_trace_options hello_trace_option
%type	<proto>		hello_prop_init
@END:	PROTO_HELLO

@BEGIN:	PROTO_OSPF
%token <num>		T_OSPF T_OSPF_ASE T_NETWORKS T_BACKBONE T_VIRTUALLINK T_STUB T_STUBHOSTS
%token <num>		T_RXMITINTERVAL T_INFTRANSDELAY
%token <num>		T_POLLINTERVAL T_ROUTERS T_NEIGHBORID T_TRANSITAREA
%token <num>		T_ENABLE T_DISABLE T_ELIGIBLE T_MONITORAUTHKEY
%token <num>		T_DD T_ACK T_LSA_BLD T_LSA_RX T_LSA_TX
%token <num>		T_EXPORTINTERVAL T_EXPORTLIMIT    
%token <num>		T_FIRST T_EVERY
%type	<adv>		ospf_interface
%type	<conflist>	ospf_common ospf_nonbroadcast
%type	<config>	ospf_common_options ospf_common_option ospf_nonbroadcast_options ospf_nonbroadcast_option
%type	<metric>	ospf_cost_option ospf_cost ospf_type_option ospf_type
%type	<num>		ospf_auth_type
%type	<hex>		ospf_auth_key
%type	<u_num>		ospf_area ospf_area_option
%type	<u_num>		ospf_syslog_first ospf_syslog_every
%type	<num>		ospf_priority ospf_eligible_option
%type	<ospf_router>	ospf_router_eligible ospf_router_eligible_list
%type	<flag>		ospf_trace_options_none ospf_trace_options ospf_trace_option
%type	<u_num>		ospf_trace_option_index    
%type	<proto>		ospf_prop_init ospf_ase_prop_init export_ospf_ase
%type	<dm>		ospf_area_range
%type	<adv>		ospf_area_range_list    
@END:	PROTO_OSPF


/* ISIS and IDRP */
%token	<num>		T_SNPA T_IP

@BEGIN:	PROTO_ISIS
%token	<num>		T_ISIS T_DUAL T_CIRCUIT T_SYSTEMID 
%token	<num>		T_LEVEL T_IPREACH T_TROLL T_SET T_PREFIX
%token	<num>		T_INTDOMINFO T_MODE
%type	<num>		isis_option isis_mode isis_level ipreach_type prefix_type
%type	<flag>		isis_trace_options isis_trace_option
%type	<proto>		isis_prop_init export_isis    
@END:	PROTO_ISIS

/* OSPF and ISIS */
%token	<num>		T_AREA T_SPF

/* OSPF and SLSP */
%token <num>		T_HELLO T_HELLOINTERVAL T_ROUTERDEADINTERVAL

/* OSPF and ISIS and SLSP */
%token	<num>		T_PRIORITY

@BEGIN:	PROTO_IGMP
/* IGMP */
%token	<num>		T_IGMP    
@END:	PROTO_IGMP

@BEGIN:	PROTO_DVMRP
/* DVMRP */
%token	<num>		T_DVMRP
%type	<num>		T_THRESHOLD T_TUNNEL
%type	<config>	dvmrp_interface_statements dvmrp_interface_options dvmrp_interface_option
%type	<config>	dvmrp_tunnel_options dvmrp_tunnel_option
@END:	PROTO_DVMRP

@BEGIN:	PROTO_IDPR
/* IDPR */
%token	<num>		T_IDPR
%type	<str>		idpr_config_file    
@END:	PROTO_IDPR

/* SNMP */
%token	<num>		T_SNMP
@BEGIN:	PROTO_SNMP
%token	<num>		T_REGISTER T_RESOLVE
%type	<flag>		snmp_trace_options_none snmp_trace_options snmp_trace_option
@END:	PROTO_SNMP

@BEGIN:	PROTO_SLSP
/* SLSP */
%token	<num>		T_SLSP T_INSTANCE T_NODE T_NODEMASK
%type	<config>	slsp_interface slsp_interfaces
%type	<time>		slsp_hello slsp_dead
%type	<metric>	slsp_cost    
%type	<num>		slsp_priority    
%type	<u_num>		slsp_trace_option_index
%type	<flag>		slsp_trace_options_none slsp_trace_options slsp_trace_option
%type	<proto>		slsp_prop_init
@END:	PROTO_SLSP

@BEGIN:	PROTO_RDISC
/* Router Discovery */
%token	<num>		T_ROUTERDISCOVERY T_ADDRESS T_MAXADVINTERVAL T_MINADVINTERVAL T_LIFETIME T_ADVERTISE T_INELIGIBLE
%type	<num>		rdisc_phys_type rdisc_addr_adv rdisc_addr_preference
%type	<config>	rdisc_phys_option rdisc_phys_options rdisc_addr_option rdisc_addr_options
@END:	PROTO_RDISC

@BEGIN:	PROTO_ICMP
/* ICMP */
%token	<num>		T_ICMP T_ROUTERDISCOVERY
%type	<u_num>		icmp_trace_option_index
%type	<flag>		icmp_trace_options_none icmp_trace_options icmp_trace_option
@END:	PROTO_ICMP


/* IDRP */
@BEGIN:	PROTO_IDRP
%token	<num>	T_IDRP T_RDI T_RDPATH T_OSISTATIC 
%token	<num>	T_NSAP T_NET T_NSAPPREFIX
%token		T_PROTOSUPPORT T_PROTOSOCK T_SOCKSUPPORT
%token		T_LOCALNODE T_OSILOCAL 
%token	<num>	T_LOCAL_INTERFACE T_LOCAL_SNPA T_LOCAL_NET
%token	<num> 	T_UDP
%token	<num>	T_AUTHCODE T_CAPACITY T_EXPENSE T_INTRAIS
%token	<num>	T_MAXCPU T_MAXPDUSIZE T_MINADVRD T_MULTIEXIT
%token	<num>	T_RIBCHECK T_RDC T_RDLRE T_TRANSITDELAY
%token	<num> 	T_REXMIT T_ROUTESERVER
%token	<num>	T_CLOSEWAIT T_MINADV T_OUTPDUS
%token	<num>	T_ASRDI
%token	<num>	T_LISTENOPEN
%token	<num>	T_PROHIBIT_DIST T_ALLOW_DIST 
%token	<num>	T_DIST_LIST_INCL T_DIST_LIST_EXCL 
%token  <num>	T_IDRP_ATTS T_IDRP_PS_ATTS T_IDRP_PS_POLICY_ATTS T_HOPCOUNT T_HOPCOUNT_OFFSET
%token	<num>	T_CLOSESTAY T_EXTINFO T_LOCALINFO T_HIERARCHICAL_REC
%token	<num>	T_RIB_REFRESH 
%token	<num>	T_EXPAND_NEXT_HOP T_NET_AUTO_NLRI 
%token  <num> 	T_GATED_PREF T_IDRP_PREF
%token	<num>	T_PHASE1 T_PHASE3 T_ROUTE_TIES T_IDRP_DEBUG T_MINADVTIMER
%token 	<num>	T_LT T_LE T_EQ T_NE T_GE T_GT T_EXTERIOR
%token	<num>	T_SECURITY T_FAA_ADMIN T_FAA_GENCOM T_FAA_OPS T_FAA_SYSMGT  
%token	<num>	T_RIBSUPPORT T_RIB

%type	<num>   idrp_interior_export
%type	<proto>	idrp_prop_init    
%type	<metric_adv>	prop_source_option_idrp prop_metric_option_idrp
%type	<adv>	prop_source_idrp prop_source_list_idrp 
%type	<adv> 	prop_restrict_idrp prop_restrict_list_idrp prop_restrict_list_option_idrp

/* TODO
%type	<u_num>	idrp_trace_option_index
*/
%type	<flag>	idrp_trace_options_none idrp_trace_options idrp_trace_option

%type	<sockaddr> osi_rdi osi_rdi_or_any osi_address osi_tagged_address osi_nsap osi_prefix osi_hex
%type	<num>	osi_address_name
%type 	<dm>    osi_dest_mask idrp_dest_mask
%type   <num>   idrp_gateway_list /* TODO--change this! */
%type	<num>	idrp_interface_list  /* TODO--change this! */
/* TODO
%type	<num>   idrp_route_options idrp_route_option
%type   <adv>	idrp_attribute_list
%type	<adv>	idrp_attribute_entries
%type	<adv>	idrp_attribute_entry
*/
%type	<adv>	idrp_ps_policy_attribute_entries
%type	<adv>	idrp_ps_policy_attribute_entry
%type	<adv>   idrp_ps_policy_route_option
%type	<adv>	idrp_ps_policy_hopcount
%type	<adv>	idrp_ps_policy_nexthop
%type	<adv>	idrp_ps_policy_QOS_option
/* TODO--wrap in RDPATH */
%type	<adv>	idrp_ps_policy_dist_option

%type	<num>	idrp_ps_attribute_entries 
%type	<num>	idrp_ps_attribute_entry 
%type	<num>   idrp_ps_route_option 
%type	<num>	idrp_ps_pref_calc 
%type	<num>	idrp_ps_QOS_option 
%type	<num>	idrp_ps_snpa_rt_option
%type	<num>	idrp_ps_rib_entries 
%type	<num>	idrp_ps_rib_entry 
%type	<num>	idrp_rib_entries 
%type	<num>	idrp_rib_entry 
%type	<num>	idrp_rib_value 
%type	<num>	idrp_peer_rib_ids	
%type	<num>	idrp_peer_rib_id	

%type	<num>	number_compare_op
%type 	<num> 	idrp_rd_hopcount_value 
%type 	<num> 	idrp_transit_delay_value 
%type	<num>	idrp_expense_value
%type	<num>	idrp_rdlre_value
%type	<num>	idrp_priority_value
%type	<num>	idrp_capacity_value
%type	<num>	idrp_security_value
%type	<num>	idrp_multiexit_value
%type	<num>	idrp_hold_time_value
%type	<num>	idrp_minadv_value

%type 	<num>	idrp_auth_type
%type	<num>	idrp_security_type

/* TODO
%type	<num>	idrp_pref_calc
%type	<num>	idrp_QOS_options
%type	<num>	idrp_QOS_option
*/

%type	<num>	idrp_snpa_rt_option
%type	<num>	idrp_snpas
%type	<num>	idrp_snpa

%type 	<proto_lists>	control_idrp
%type	<pref>		idrp_preference
%type	<metric>	idrp_preference_option idrp_preference_restrict_option

%type	<metric_adv>	idrp_import_option 
%type	<adv>	idrp_local_intf_test
%type	<adv>	idrp_import_optional_info idrp_export_optional_info
%type	<adv>	idrp_policy_atts_clause
%type	<num>	idrp_atts_clause
%type 	<adv>   idrp_parse_import_list idrp_import_listen

%type	<proto>	rdpath_prop_init    
%type 	<p_policy_rdpath> rdpath_spec rdpath_parts rdpath_part
%type 	<p_policy_rdpath> rdpath_special_part rdpath_real_part
%type 	<p_policy_rdpath> rdpath_set rdpath_or_list policy_rdpath_rdi
%type 	<p_policy_rdpath> rdpath_any rdpath_any_or_null
%type 	<num>	rdpath_flag
%token 	<num>	T_SUBSET
/* SJR TODO--when rdpath is more stable */
%type	<num>	idrp_ps_dist_option
%type	<p_idrp_canon_rdpath>	idrp_ps_dist_list  idrp_ps_dist_rdi       
@END:	PROTO_IDRP
@BEGIN:	PROTO_RDPATHS
%type	<rdp_match>	rdpath_spec  /* TODO--change this! */
/*
%type	<adv>	idrp_ps_dist_option
%type	<p_idrp_canon_rdpath>	idrp_ps_dist_list  idrp_ps_dist_rdi       
*/
%type	<num>	idrp_dist_options       
%type	<num>	idrp_dist_option        
%type	<p_idrp_canon_rdpath>	idrp_dist_list
%type	<hex>	idrp_dist_rdi
@END:	PROTO_RDPATHS

/* Redirects */
%token	<num>		T_REDIRECT T_REDIRECTS T_NOREDIRECTS
%type	<config>	redirect_interface_option redirect_interface_options
%type	<flag>		redirect_trace_options_none redirect_trace_options redirect_trace_option

/* Authentication */
%token	<num>		T_AUTHTYPE T_AUTHKEY T_NONE T_SIMPLE T_AUTH T_CRYPT T_CLEAR

/* Interface */
%token	<num>		T_PASSIVE T_SIMPLEX T_STRICTIFS T_SCANINTERVAL

/* Control */
%token	<num>		T_STATIC T_MARTIANS T_RETAIN
%token	<num>		T_EXPORT T_IMPORT T_EXACT T_REFINE
%token	<num>		T_HOST T_MASK T_MASKLEN T_REJECT T_BLACKHOLE T_RESTRICT T_ALLOW
%type	<dm>		route_dest
@BEGIN:	PROTO_ASPATHS
%type	<aspath>	route_aspath
@END:	PROTO_ASPATHS
%type	<flag>		rts_options rts_option   

/* AS control */
%token	<num>		T_AS T_ROUTERID T_IGP

/* Tracing */
%token			T_OPTIONS T_NOINSTALL T_NOSEND T_NORESOLV T_MARK
%token	<num>		T_TRACEOPTIONS T_EXCEPT T_REPLACE T_SIZE T_FILES T_K T_M
%token	<num>		T_ALL T_ROUTE T_STATE T_POLICY T_NORMAL T_GENERAL T_TASK T_TIMER T_NOSTAMP T_UPDATE
%token	<num>		T_DETAIL T_SEND T_RECEIVE T_ERROR T_PACKETS T_RESPONSE T_REQUEST T_OTHER T_TRAP
@BEGIN:	PROTO_ISIS
/* additional tracing for IS-IS */
%token  <num>   	TISIS_IIH TISIS_DUMPLSP TISIS_EVENTS TISIS_LANADJ
%token  <num>   	TISIS_FLOODING TISIS_BUILDLSP TISIS_CSNP TISIS_PSNP
%token  <num>   	TISIS_LSPINPUT TISIS_P2PADJ TISIS_LSPDB 
%token	<num>		TISIS_PATHS TISIS_LSPCONTENT TISIS_SUMMARY
@END:	PROTO_ISIS    

%type	<num>		number				/* A decimal, hex, or octet string number */
%type	<hex>		byte_string			/* A L_HEXSTRING or L_OCTETSTRING */
%type	<metric>	metric metric_option metric_restrict_option
%type	<time>		time
%token	<num>		L_USEC
@BEGIN:	PARSE_UTIME
%type	<utime>		utime
@END:	PARSE_UTIME
%type	<num>		onoff_option null_or_restrict
%type	<flag>		trace_option trace_option_global
%type	<flag>		trace_trace_options_none trace_trace_options
%type	<flag>		trace_option_detail trace_option_sendrecv
%type	<flag>		trace_control_options trace_control_option
%type	<trace_file>	trace_file_option
%type	<num>		trace_size    
%type	<config>	interface_define_options interface_define_option
%type	<flag>		trace_replace
%type	<proto>		proto_exterior
%type	<proto_lists>	control_exterior import_interior export_interior proto_interior

%token	<num>		T_AGGREGATE T_GENERATE T_BRIEF
%type	<flag>		aggregate_options

%type	<proto> 	prop_default prop_direct prop_static prop_kernel prop_aggregate
@BEGIN:	AUTONOMOUS_SYSTEM
%type	<as>		as
@BEGIN:	PARSE_ASLIST
%type	<adv>		as_list as_list_option
@END:	PARSE_ASLIST
%type	<u_num>		as_loop_option
@END:	AUTONOMOUS_SYSTEM
%type	<pref>		preference
%type	<metric>	preference_option preference_restrict_option
%type	<ifae>		interface_local    
%type	<sockaddr>	interface_addr addr host mask
@BEGIN:	PROTO_INET
%token	<num>		T_INET    
%type	<in_addr>	in_addr
%token	<num>		T_GENDEFAULT
%type	<sockaddr>	addr_inet host_inet network_inet mask_inet
%type	<dm>		dest_mask_inet host_mask_inet network_mask_inet network_mask_flags_inet all_mask_inet default_mask_inet
%type	<dm>		aggregate_dest_inet
%type	<dm>		martian_inet
%type	<adv>		martian_list_inet
%type	<sockaddr>	default_gateway_option
%type	<gwp>		gateway_inet
%type	<adv>	 	gateway_list_inet aggregate_list_inet aggregate_proto_inet
%type	<proto>		aggregate_protos_inet
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
%token	<num>		T_ISO
%type	<sockaddr>	addr_iso host_iso network_iso mask_iso
%type	<dm>		dest_mask_iso host_mask_iso network_mask_iso network_mask_flags_iso all_mask_iso default_mask_iso
%type	<dm>		aggregate_dest_iso
%type	<dm>		martian_iso
%type	<adv>		martian_list_iso
%type	<gwp>		gateway_iso
%type	<adv>	 	gateway_list_iso aggregate_list_iso aggregate_proto_iso
%type	<proto>		aggregate_protos_iso
@END:	PROTO_ISO
%type	<num>		dm_flags
%type	<adv>		interface_all interface_all_adv interface_list interface_list_option interface_all_list
@BEGIN:	PARSE_LINK
%type	<adv>		intf_phys_all intf_phys_all_adv intf_phys_list intf_phys_all_list
@END:	PARSE_LINK
%type	<adv>		interface_gateway_list gateway_list
%type	<flag>		martian_option
@BEGIN:	PROTO_INET
%type	<adv>		import_list_inet import_listen_inet
%type	<metric_adv>	import_option_inet
%type	<adv>		prop_source_inet prop_source_list_inet
%type	<adv>		prop_restrict_inet prop_restrict_list_inet prop_restrict_list_option_inet
%type	<metric_adv>	prop_source_option_inet prop_metric_option_inet
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
%type	<adv>		import_list_iso import_listen_iso
%type	<metric_adv>	import_option_iso
%type	<adv>		prop_source_iso prop_source_list_iso
%type	<adv>		prop_restrict_iso prop_restrict_list_iso prop_restrict_list_option_iso
%type	<metric_adv>	prop_source_option_iso prop_metric_option_iso
@END:	PROTO_ISO
%type	<str>		string host_name
@BEGIN:	PARSE_PORT
%token	<port>		T_PORT
%type	<num>		port
@END:	PARSE_PORT

%%

config		: /* Empty */
		| statements
		;

statements	: statement
		| statements statement
		;

statement	: parse_statement
		| trace_statement
		| option_order option_statement
		| interface_order interface_statement
		| define_order define_statement
		| proto_order proto_statement
		| route_order route_statement
		| control_order control_statement
		| error L_EOS
			{
				yyerrok;
			}
		| L_EOS
		;

/*  */

parse_statement	: T_YYDEBUG onoff_option L_EOS
			{
#if	YYDEBUG != 0
			    if ($2 == T_OFF) {
				yydebug = 0;
			    } else {
				yydebug = 1;
			    }
#endif	/* YYDEBUG */
			}
		| T_YYSTATE L_NUMBER L_EOS
			{
#if	YYDEBUG != 0
			    if ($2 < 0 || $2 > PS_MAX) {
				(void) sprintf(parse_error, "invalid yystate value: %d",
					       $2);
				PARSE_ERROR;
			    }
			    parse_state = $2;
#endif	/* YYDEBUG */
			}
		| T_YYQUIT L_EOS
			{
#if	YYDEBUG != 0
			    task_quit(0);
#endif	/* YYDEBUG */
			}
		;

/*  */

trace_statement	: T_TRACEOPTIONS trace_file_option trace_control_option trace_trace_options_none L_EOS
			{
			    if ($2 && !BIT_TEST(task_state, TASKS_TEST)) {

				trace_store(trace_global, $4, $3, $2, (bits *) 0);

				if ($4) {
				    /* Turn on or change tracing */

				    trace_on($2);
				} else {
				    /* Turn off tracing */

				    trace_off($2);
				}
				trace_display(trace_global, TR_ALL);
			    }
			}
		;

trace_file_option
		: /* Empty */
			{
			    $$ = trace_file_locate((char *) 0,
						   (off_t) 0,
						   (u_int) 0,
						   (flag_t) 0);
			}
		| string trace_replace
			{
			    $$ = trace_file_locate($1.ptr,
						   (off_t) 0,
						   (u_int) 0,
						   $2);
			}
		| string trace_replace T_SIZE trace_size T_FILES number
			{
			    if (parse_limit_check("file-size",
						  (u_int) $4,
						  TRACE_LIMIT_FILE_SIZE)) {
				PARSE_ERROR;
			    }

			    if (parse_limit_check("files",
						  (u_int) $6,
						  TRACE_LIMIT_FILE_COUNT)) {
				PARSE_ERROR;
			    }

			    $$ = trace_file_locate($1.ptr,
						   $4,
						   (u_int) $6,
						   $2);
			}
		;

trace_size	: number
		| number T_K
			{
			    $$ = $1 * 1024;
			}
		| number T_M
			{
			    $$ = $1 * 1024 * 1024;
			}
		;

trace_replace	: /* Empty */
			{
			    $$ = 0;
			}
		| T_REPLACE
			{
			    $$ = TRF_REPLACE;
			}
		;

trace_control_option
		: /* Empty */
			{
			    $$ = 0;
			}
		| trace_control_option trace_control_options
			{
			    $$ = $1 | $2;
			}
		;

trace_control_options
		: T_NOSTAMP
			{
			    $$ = TRC_NOSTAMP;
			}
		;

trace_trace_options_none
    		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| trace_trace_options
			{
			    $$ = $1;
			}
		| trace_trace_options T_EXCEPT trace_trace_options
			{
			    $$ = $1 & ~ $2;
			}
		;
		
trace_trace_options
		: trace_option
			{
			    $$ = $1;
			}
		| trace_option_global
			{
			    $$ = $1;
			}
		| trace_trace_options trace_option
			{
			    $$ = $1 | $2;
			}
		| trace_trace_options trace_option_global
			{
			    $$ = $1 | $2;
			}
		;

/* Trace options that can only be specified globally */
trace_option_global
		: T_PARSE
			{
			    $$ = TR_PARSE;
			}
		| T_ADV
			{
#ifdef	TR_ADV
			    $$ = TR_ADV;
#else	/* TR_ADV */
			    $$ = 0;
#endif	/* TR_ADV */
			}
		;

/* Trace options that can be specified anywhere */
trace_option	: T_ROUTE
			{
			    $$ = TR_ROUTE;
			}
		| T_NORMAL
			{
			    $$ = TR_NORMAL;
			}
		| T_GENERAL
			{
			    $$ = TR_GENERAL;
			}
		| T_STATE
			{
			    $$ = TR_STATE;
			}
		| T_POLICY
			{
			    $$ = TR_POLICY;
			}
    		| T_TASK
			{
			    $$ = TR_TASK;
			}
		| T_TIMER
			{
			    $$ = TR_TIMER;
			}
		| T_ALL
			{
			    $$ = TR_ALL;
			}
		;

trace_option_detail
		: /* Empty */
			{
			    $$ = (flag_t) 0;
			}
		| T_DETAIL
			{
			    $$ = TR_PARSE_DETAIL;
			}
		;

trace_option_sendrecv
		: /* Empty */
			{
			    $$ = (flag_t) 0;
			}
		| T_SEND
			{
			    $$ = TR_PARSE_SEND;
			}
		| T_RECEIVE
			{
			    $$ = TR_PARSE_RECV;
			}
		;


/*  */

define_order	: /*Empty */
			{
				if (parse_new_state(PS_DEFINE)) {
					PARSE_ERROR;
				}
			}
		;

define_statement
		: T_NOP
@BEGIN:	PROTO_INET
		| T_MARTIANS
			{
			    parse_contig_masks = FALSE;
			}
			'{' martian_list_inet '}' L_EOS
			{
			    parse_contig_masks = TRUE;

			    SI_MARTIANS(AF_INET) = $4;
			}
@END:	PROTO_INET
@BEGIN:	PROTO_IDRP
                | T_RDI osi_rdi L_EOS
                        {
				/* RDI indicates the Routing Domain IDRP peer in
				 * there for both IP and CLNP 
				 * - Kludge for now to save as AS_RDI until
				 * - more parsing code is written for IP 
				 */
 
				struct iso_net_addr *p_iso_net;

				ISO_NET_FROM_SOCKUN(p_iso_net, $2);
                                bcopy(p_iso_net->isoa_genaddr, &rt_rdi.isoa_genaddr, p_iso_net->isoa_len);
				rt_rdi.isoa_len = p_iso_net->isoa_len;
				trace_tf (trace_global, TR_PARSE, 0, ("rdi xxxx configured for idrp %A ", 
					sockbuild_iso((byte *) rt_rdi.isoa_genaddr, rt_rdi.isoa_len)));
				rt_as_rdi.isoa_len = p_iso_net->isoa_len;
				bcopy(p_iso_net->isoa_genaddr, &rt_as_rdi.isoa_genaddr,rt_as_rdi.isoa_len);
				rt_as_rdi.isoa_family = AF_ISO;
				trace_tf (trace_global, TR_PARSE, 0, ("idrp finished call to rdi in parser.y"));
                        }
                | osi_tagged_address L_EOS
                        { 
				/* need an NET for this node 
				 * if we configure multiple ISO host addresses, 
				 * we need to nominate one as NET.
				 * Eventually maybe this could be discovered
				 */
				
				struct iso_net_addr *p_iso_net;
					
				ISO_NET_FROM_SOCKUN(p_iso_net, $1);
                                bcopy(p_iso_net->isoa_genaddr, rt_net[rt_net_cnt].isoa_genaddr, p_iso_net->isoa_len);
                                rt_net[rt_net_cnt].isoa_len = p_iso_net->isoa_len;
				rt_net_cnt++;
                        }
@END:	PROTO_IDRP
@BEGIN:	PROTO_ISO
		| T_ISO T_MARTIANS
			{
			    parse_contig_masks = FALSE;
			}
			'{' martian_list_iso '}' L_EOS
			{
			    parse_contig_masks = TRUE;

			    SI_MARTIANS(AF_ISO) = $5;
			}
@END:	PROTO_ISO
@BEGIN:	AUTONOMOUS_SYSTEM
		| T_AS as as_loop_option L_EOS
			{
			    if (inet_autonomous_system) {
				(void) sprintf(parse_error, "autonomous-system already specified");
				PARSE_ERROR;
			    }
			    inet_autonomous_system = $2;
#ifdef	PROTO_ASPATHS
			    aslocal_set(inet_autonomous_system, $3);
#endif	/* PROTO_ASPATHS */
			}
@END:	AUTONOMOUS_SYSTEM
@BEGIN:	ROUTER_ID    
    		| T_ROUTERID host_inet L_EOS
			{
			    if (inet_parse_routerid($2, parse_error)) {
				PARSE_ERROR;
			    }
			}
@END:	ROUTER_ID
		;

@BEGIN:	PROTO_INET
martian_list_inet
		: /* Empty */
			{
			    $$ = SI_MARTIANS(AF_INET);
			}
		| martian_list_inet martian_inet martian_option L_EOS
			{
			    adv_entry *adv = adv_alloc(ADVFT_DM | $3, (proto_t) 0);

			    adv->adv_dm = $2;
			    $$ = adv_destmask_insert(parse_error, $1, adv);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| martian_list_inet error L_EOS
			{
			    yyerrok;
			}
		;

martian_inet	: host_mask_inet
		| network_mask_flags_inet
		| default_mask_inet
		;
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
martian_list_iso : /* Empty */
			{
			    $$ = SI_MARTIANS(AF_ISO);
			}
		| martian_list_iso martian_iso martian_option L_EOS
			{
			    adv_entry *adv = adv_alloc(ADVFT_DM | $3, (proto_t) 0);

			    adv->adv_dm = $2;
			    $$ = adv_destmask_insert(parse_error, $1, adv);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| martian_list_iso error L_EOS
			{
			    yyerrok;
			}
		;

martian_iso	: host_mask_iso
		| network_mask_flags_iso
		| default_mask_iso
		;
@END:	PROTO_ISO

martian_option	: /* Empty */
			{
			    $$ = ADVF_NO;
			}
		| T_ALLOW
			{
			    $$ = (flag_t) 0;
			}
		;

/**/

option_order	: /*Empty */
			{
				if (parse_new_state(PS_OPTIONS)) {
					PARSE_ERROR;
				}
			}
		;

option_statement
    		: T_OPTIONS option_list L_EOS
    		;

option_list	: option
		| option_list option
		;


option		: T_NOSEND
			{
			    task_newstate(TASKS_NOSEND, 0);
			}
		| T_NORESOLV
			{
			    task_newstate(TASKS_NORESOLV, 0);
			}
		| T_SYSLOG syslog_mask
			{
#ifdef	LOG_DAEMON
			    (void) setlogmask($2);
#else	/* LOG_DAEMON */
			    (void) sprintf(parse_error, "system does not support setlogmask()");
			    PARSE_ERROR;
#endif	/* LOG_DAEMON */
			}
		| T_MARK mark_time
			{
			    task_mark_interval = $2;
			}
@BEGIN:	PROTO_INET
		| T_GENDEFAULT preference_option default_gateway_option
			{
			    rt_default_needed = TRUE;
			    if (PARSE_METRIC_ISSET(&$2)) {
				rt_default_rtparms.rtp_preference = $2.metric;
			    }
			    rt_default_rtparms.rtp_router = $3;
			}
@END:	PROTO_INET
		;


@BEGIN:	PROTO_INET
default_gateway_option
		: /* Empty */
			{
			    $$ = (sockaddr_un *) 0;
			}
		| T_GATEWAY
			{
			    parse_gwlist = &parse_gwp;
			}
		gateway_inet
			{
			    $$ = sockdup($3->gw_addr);
			    gw_freelist(*parse_gwlist);
			    *parse_gwlist = parse_gwp = (gw_entry *) 0;
			}
			;
@END:	PROTO_INET

mark_time	:	/* Empty */
			{
			    $$ = TIME_MARK;
			}
		|	time
			{
			    $$ = $1;
			}
		;

syslog_mask	:	syslog_level
			{
#ifdef	LOG_DAEMON
			    $$ = LOG_MASK($1);
#endif	/* LOG_DAEMON */
			}
		|	T_UPTO syslog_level
			{
#ifdef	LOG_DAEMON
			    $$ = LOG_UPTO($2);
#endif	/* LOG_DAEMON */
			}
		|	syslog_mask syslog_level
			{
#ifdef	LOG_DAEMON
			    $$ = $1 | LOG_MASK($2);
#endif	/* LOG_DAEMON */
			}
		;

syslog_level	: T_EMERG
			{
			    $$ = LOG_EMERG;
			}
		| T_ALERT
			{
			    $$ = LOG_ALERT;
			}
		| T_CRIT
			{
			    $$ = LOG_CRIT;
			}
		| T_ERR
			{
			    $$ = LOG_ERR;
			}
		| T_WARNING
			{
			    $$ = LOG_WARNING;
			}
		| T_NOTICE
			{
			    $$ = LOG_NOTICE;
			}
		| T_INFO
			{
			    $$ = LOG_INFO;
			}
		| T_DEBUG
			{
			    $$ = LOG_EMERG;
			}
    		;

/*  */

interface_order	: /*Empty */
			{
			    if (parse_new_state(PS_INTERFACE)) {
				PARSE_ERROR;
			    }
			}
		;

interface_statement	
		: T_INTERFACES
			{
			    PROTO_SEEN(RTPROTO_DIRECT);
			}
			'{' interface_stmts '}' L_EOS
		;

interface_stmts
		: /* Empty */
    		| interface_stmts interface_stmt L_EOS
    		| interface_stmts error L_EOS
			{
			    yyerrok;
			}
    		;

interface_stmt
		: T_OPTIONS interface_options
		| T_INTERFACE interface_all_list interface_define_options
			{
			    config_list *list = config_list_alloc($3, 0);

			    parse_adv_propagate_config($2, list, (proto_t) 0);

			    if (parse_adv_append(&int_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
			}
		| T_DEFINE host_inet
			{
			    bzero((caddr_t) &parse_ifi, sizeof (parse_ifi));

			    parse_ifi.ifi_addr = $2;
			}
			interface_type_options interface_common_options
			{
			    if (if_parse_add(&parse_ifi, parse_error)) {
				PARSE_ERROR;
			    }
			}
		;

interface_options
		: interface_option
		| interface_options interface_option
		;

interface_option
		: T_STRICTIFS
			{
			    task_newstate(TASKS_STRICTIFS, 0);
			}
		| T_SCANINTERVAL time
			{
			    if (parse_limit_check("scan-interval",
						  (u_int) $2,
						  KRT_LIMIT_SCANTIMER)) {
				PARSE_ERROR;
			    }
			    
			    task_timer_set(krt_timer_ifcheck,
					   $2,
					   (time_t) 0);
			}
		;

interface_type_options
		: T_BROADCAST host
			{
			    parse_ifi.ifi_addr_broadcast = $2;
			    BIT_SET(parse_ifi.ifi_state, IFS_BROADCAST);
			}
		| T_POINTOPOINT host
			{
			    parse_ifi.ifi_addr_local = $2;
			    BIT_SET(parse_ifi.ifi_state, IFS_POINTOPOINT);
			}
		| /* Empty */
			{
			}
		;

interface_common_options
		: /* Empty */
		| interface_common_options interface_common_option
		;

interface_common_option
		: T_NETMASK mask
			{
			    parse_ifi.ifi_netmask = $2;
			}
		| T_MULTICAST
			{
			    BIT_SET(parse_ifi.ifi_state, IFS_MULTICAST);
			}
		;

interface_define_options
		: interface_define_option
		| interface_define_options interface_define_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

interface_define_option
		: T_PREFERENCE preference
			{
			    $$ = config_alloc(IF_CONFIG_PREFERENCE_UP, (void_t) $2);
			}
		| T_DOWN T_PREFERENCE preference
			{
			    $$ = config_alloc(IF_CONFIG_PREFERENCE_DOWN, (void_t) $3);
			}
		| T_PASSIVE
			{
			    $$ = config_alloc(IF_CONFIG_PASSIVE, (void_t) TRUE);
			}
		| T_SIMPLEX
			{
			    $$ = config_alloc(IF_CONFIG_SIMPLEX, (void_t) TRUE);
			}
		| T_REJECT
			{
			    $$ = config_alloc(IF_CONFIG_REJECT, (void_t) TRUE);
			}
		| T_BLACKHOLE
			{
			    $$ = config_alloc(IF_CONFIG_BLACKHOLE, (void_t) TRUE);
			}
@BEGIN:	PROTO_ASPATHS
		| T_AS as
			{
			    $$ = config_alloc(IF_CONFIG_AS, (void_t) (u_int) $2);
			}
@END:	PROTO_ASPATHS
		;

interface_list_option
		: /* Empty */
			{
			    $$ = adv_alloc(ADVFT_ANY|ADVF_FIRST, (proto_t) 0);
			}
		| T_INTERFACE interface_list
			{
			    $$ = $2;
			}
		;

interface_gateway_list
		: interface_list_option
		| T_GATEWAY gateway_list
			{
			    $$ = $2;
			}
		;

interface_all_list
		: T_ALL
			{
			    $$ = adv_alloc(ADVFT_ANY|ADVF_FIRST, (proto_t) 0);
			}
		| interface_list
		;

interface_list
		: interface_all
			{
			    BIT_SET($1->adv_flag, ADVF_FIRST);
			    $$ = $1;
			}
		| interface_list interface_all
			{
			    $$ = $1;
			    if (parse_adv_append(&$$, $2)) {
				PARSE_ERROR;
			    }
			}
		;

interface_all	: interface_all_adv
			{
			    switch ($1->adv_flag & ADVF_TYPE) {

			    case ADVFT_IFN:
				trace_tf(trace_global,
					 TR_PARSE,
					 0,
					 ("parse: %s INTERFACE: %A*",
					  parse_where(),
					  $$->adv_ifn->ifae_addr));
				break;
				
			    case ADVFT_IFAE:
				trace_tf(trace_global,
					 TR_PARSE,
					 0,
					 ("parse: %s INTERFACE: %A",
					  parse_where(),
					  $$->adv_ifae->ifae_addr));
			    }
			}
		;

interface_all_adv
		: host_name
			{
			    int valid_ifname = 0;

			    switch ($1.type) {
			    case L_KEYWORD:
			    case L_STRING:
				if ($1.len < IFL_NAMELEN) {
				    valid_ifname++;
				}
				break;

			    default:
				break;
			    }

			    if (valid_ifname) {
				/* First try to look up as an interface name */

				$$ = if_parse_name($1.ptr, FALSE);
			    } else {
				/* Doesn't meet the criteria to be a name */

				$$ = (adv_entry *) 0;
			    }
			    
			    if (!$$ && !BIT_TEST(task_state, TASKS_NORESOLV)) {
				/* Try to resolve as a host name */

				sockaddr_un *addr = parse_addr_hostname($1.ptr);

				if (addr) {
				    $$ = if_parse_address(addr);
				}

			    }

			    if ($$ == NULL) {
				if (valid_ifname && !BIT_TEST(task_state, TASKS_STRICTIFS)) {
				    /* Assume it is a reference to an interface that does not exist */

				    $$ = if_parse_name($1.ptr, TRUE);
				} else {
				    /* Time to give up */
				    
				    (void) sprintf(parse_error, "Interface not found at '%s'",
						   $1.ptr);
				    PARSE_ERROR;
				}
			    }
				
			    free_charstr(&$1);
			}
		| addr
			{
			    $$ = if_parse_address($1);
			    if ($$ == NULL) {
				(void) sprintf(parse_error, "Interface not found at '%A'",
					       $1);
				PARSE_ERROR;
			    }

			    sockfree($1);
			}
		;

interface_local	: interface_addr
			{
			    if_addr *ifap;
			    
			    ifap = if_withlcladdr($1, FALSE);
			    if (ifap) {
				$$ = ifae_alloc(ifap->ifa_addrent_local);
			    } else {
				if (BIT_TEST(task_state, TASKS_STRICTIFS)) {
				    (void) sprintf(parse_error, "Invalid interface at '%A'",
						   $1);
				    PARSE_ERROR;
				} else {
				    $$ = ifae_locate($1, &if_local_list);
				}
			    }
			    sockfree($1);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s LOCAL ADDRESS: %A",
				      parse_where(),
				      $$->ifae_addr));
			}
		;

interface_addr	: addr
		| host_name
			{
			    sockaddr_un *addr;

			    if (BIT_TEST(task_state, TASKS_NORESOLV)
				|| !(addr = parse_addr_hostname($1.ptr))) {
				PARSE_ERROR;
			    }
			    $$ = sockdup(addr);
			    free_charstr(&$1);
			}
		;

/**/

@BEGIN:	PARSE_LINK
/* Physical interfaces */

intf_phys_all_list
		: T_ALL
			{
			    $$ = adv_alloc(ADVFT_ANY|ADVF_FIRST, (proto_t) 0);
			}
		| intf_phys_list
		;

intf_phys_list
		: intf_phys_all
			{
			    BIT_SET($1->adv_flag, ADVF_FIRST);
			    $$ = $1;
			}
		| intf_phys_list intf_phys_all
			{
			    $$ = $1;
			    if (parse_adv_append(&$$, $2)) {
				PARSE_ERROR;
			    }
			}
		;

intf_phys_all	: intf_phys_all_adv
			{
			    switch ($1->adv_flag & ADVF_TYPE) {

			    case ADVFT_IFN:
				trace_tf(trace_global,
					 TR_PARSE,
					 0,
					 ("parse: %s LINK: %A*",
					  parse_where(),
					  $$->adv_ifn->ifae_addr));
				break;
				
			    case ADVFT_IFAE:
				trace_tf(trace_global,
					 TR_PARSE,
					 0,
					 ("parse: %s LINK: %A",
					  parse_where(),
					  $$->adv_ifae->ifae_addr));
			    }
			}
		;

intf_phys_all_adv
		: host_name
			{
			    int valid_ifname = 0;

			    switch ($1.type) {
			    case L_KEYWORD:
			    case L_STRING:
				if ($1.len < IFL_NAMELEN) {
				    valid_ifname++;
				}
				break;

			    default:
				break;
			    }

			    if (valid_ifname) {
				/* First try to look up as an interface name */

				$$ = if_parse_name($1.ptr, FALSE);
			    } else {
				/* Doesn't meet the criteria to be a name */

				(void) sprintf(parse_error, "Physical interface not found at '%s'",
					       $1.ptr);
				PARSE_ERROR;
			    }
			}
		/* XXX - Need to allow physical address */
		;
@END:	PARSE_LINK

/*  */

proto_order	: /* Empty */
			{
			    if (parse_new_state(PS_PROTO)) {
				PARSE_ERROR;
			    }
			}
		;

proto_statement	: redirect_statement L_EOS
		| kernel_statement L_EOS
@BEGIN:	PROTO_BGP
		| bgp_statement L_EOS
@END:	PROTO_BGP
@BEGIN:	PROTO_DVMRP
		| dvmrp_statement L_EOS
@END:	PROTO_DVMRP
@BEGIN:	PROTO_EGP
		| egp_statement L_EOS
@END:	PROTO_EGP
@BEGIN:	PROTO_HELLO
		| hello_statement L_EOS
@END:	PROTO_HELLO
@BEGIN:	PROTO_ICMP
		| icmp_statement L_EOS
@END:	PROTO_ICMP
@BEGIN:	PROTO_OSPF
    		| ospf_statement L_EOS
@END:	PROTO_OSPF
@BEGIN:	PROTO_ISIS
    		| isis_statement L_EOS
@END:	PROTO_ISIS
@BEGIN:	PROTO_SLSP
		| slsp_statement L_EOS
@END:	PROTO_SLSP
@BEGIN:	PROTO_RDISC
		| rdisc_statement L_EOS
@END:	PROTO_RDISC
@BEGIN:	PROTO_IDPR
    		| idpr_statement L_EOS
@END:	PROTO_IDPR
@BEGIN:	PROTO_IDRP
    		| idrp_statement L_EOS
@END:	PROTO_IDRP
		| rip_statement L_EOS
		| snmp_statement L_EOS
		;

/*  */

kernel_statement
		: T_KERNEL
			{
			    kernel_trace_options = trace_set_global(kernel_trace_types,
								    TR_KRT_SYMBOLS|TR_KRT_IFLIST);
			}
		 '{' kernel_group '}'
		;

kernel_group	: /* Empty */
		| kernel_group kernel_stmt L_EOS
		| kernel_group error L_EOS
		;

kernel_stmt	: T_TRACEOPTIONS trace_file_option trace_control_option kernel_trace_options_none
			{
			    trace_store(kernel_trace_options, $4, $3, $2, kernel_trace_types);
			}
		| T_OPTIONS kernel_options {}
		| T_REMNANTHOLDTIME time
			{
			    if (parse_limit_check("remnantholdtime",
						  (u_int) $2,
						  KRT_LIMIT_EXPIRE)) {
				PARSE_ERROR;
			    }
			    krt_t_expire = $2;
			}
		| T_FLASH kernel_flash_options {}
		| T_BACKGROUND kernel_bg_options {}
		| T_ROUTES number
			{
			    if (parse_limit_check("routes",
						  (u_int) $2,
						  KRT_LIMIT_ROUTES)) {
				PARSE_ERROR;
			    }
			    krt_limit_routes = $2;
			}
		;

kernel_options	: kernel_option
		| kernel_options kernel_option
		;

kernel_option	: T_NOCHANGE
			{
			    BIT_SET(krt_options, KRT_OPT_NOCHANGE);
			}
		| T_NOFLUSHATEXIT
			{
			    BIT_SET(krt_options, KRT_OPT_NOFLUSH);
			}
		;

kernel_flash_options
		: kernel_flash_option
		| kernel_flash_options kernel_flash_option
		;

kernel_flash_option
		: T_TYPE kernel_flash_type
			{
			    krt_flash_routes = $2;
			}
		| T_LIMIT number
			{
			    if (parse_limit_check("flash limit",
						  (u_int) $2,
						  KRT_LIMIT_FLASH)) {
				PARSE_ERROR;
			    }
			    krt_flash_install_count = $2;
			}
		;

kernel_flash_type
		: T_INTERFACE
			{
			    $$ = KRT_FLASH_INTERFACE;
			}
		| T_INTERIOR
			{
			    $$ = KRT_FLASH_INTERNAL;
			}
		| T_ALL
			{
			    $$ = KRT_FLASH_ALL;
			}
		;

kernel_bg_options
		: kernel_bg_option
		| kernel_bg_options kernel_bg_option
		;

kernel_bg_option
		: T_PRIORITY kernel_bg_type
			{
			    krt_install_priority = $2;
			}
		| T_LIMIT number
			{
			    if (parse_limit_check("install limit",
						  (u_int) $2,
						  KRT_LIMIT_INSTALL)) {
				PARSE_ERROR;
			    }
			    krt_install_count = $2;
			}
		;

kernel_bg_type
		: T_FLASH
			{
			    $$ = KRT_INSTALL_PRIO_FLASH;
			}
		| T_HIGHER
			{
			    $$ = KRT_INSTALL_PRIO_HIGH;
			}
		| T_LOWER
			{
			    $$ = KRT_INSTALL_PRIO_LOW;
			}
		;

kernel_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| kernel_trace_options
			{
			    $$ = $1;
			}
		| kernel_trace_options T_EXCEPT kernel_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

kernel_trace_options
		: kernel_trace_option
			{
			    $$ = $1;
			}
		| kernel_trace_options kernel_trace_option
			{
			    $$ = $1 | $2;
			}
		;

kernel_trace_option
		: trace_option
    		| trace_option_detail trace_option_sendrecv kernel_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		| T_SYMBOLS
			{
			    $$ = TR_KRT_SYMBOLS;
			}
		| T_REMNANTS
			{
			    $$ = TR_KRT_REMNANTS;
			}
		| T_IFLIST
			{
			    $$ = TR_KRT_IFLIST;
			}
		| T_REQUEST
			{
			    $$ = TR_KRT_REQUEST;
			}
@BEGIN:	KRT_RT_SOCK
		| T_INFO
			{
			    $$ = TR_KRT_INFO;
			}
@END:	KRT_RT_SOCK
		;

kernel_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_KRT_INDEX_PACKETS;
			}
		| T_ROUTES
			{
			    $$ = TR_KRT_INDEX_ROUTES;
			}
@BEGIN:	KRT_RT_SOCK
		| T_REDIRECT
			{
			    $$ = TR_KRT_INDEX_REDIRECT;
			}
		| T_INTERFACE
			{
			    $$ = TR_KRT_INDEX_INTERFACE;
			}
		| T_OTHER
			{
			    $$ = TR_KRT_INDEX_OTHER;
			}
@END:	KRT_RT_SOCK
    		;

/*  */

@BEGIN:	PROTO_RIP

rip_statement	: T_RIP
			{
			    PROTO_SEEN(RTPROTO_RIP);

			    parse_gwlist = &rip_gw_list;

			    rip_trace_options = trace_set_global(rip_trace_types,
								 (flag_t) 0);
			}
    		onoff_option rip_group
			{
			    switch ($3) {
			    case T_OFF:
				BIT_RESET(rip_flags, RIPF_ON);
				break;

			    case T_ON:
				BIT_SET(rip_flags, RIPF_ON);
				break;
			    }
			}
		;

rip_group	: /* Empty */
		| '{' rip_group_stmts '}'
		;

rip_group_stmts	: /* Empty */
		| rip_group_stmts rip_group_stmt L_EOS
		| rip_group_stmts error L_EOS
			{
			    yyerrok;
			}
		;

rip_group_stmt	: T_PREFERENCE preference
			{
			    rip_preference = $2;
			}
		| T_DEFAULTMETRIC metric
			{
			    if (parse_metric_check(RTPROTO_RIP, &$2)) {
				PARSE_ERROR;
			    }
			    rip_default_metric = $2.metric;
			}
		| T_BROADCAST
			{
			    BIT_RESET(rip_flags, RIPF_CHOOSE);
			    BIT_SET(rip_flags, RIPF_BROADCAST);
			}
		| T_NONBROADCAST
			{
			    BIT_RESET(rip_flags, RIPF_CHOOSE|RIPF_BROADCAST);
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option rip_trace_options_none
			{
			    trace_store(rip_trace_options, $4, $3, $2, rip_trace_types);
			}
		| T_NOCHECKZERO
			{
			    BIT_SET(rip_flags, RIPF_NOCHECK);
			}
		| T_INTERFACE interface_all_list rip_interface_options
			{
			    config_list *list = config_list_alloc($3, rip_config_free);

			    parse_adv_propagate_config($2, list, RTPROTO_RIP);

			    if (parse_adv_append(&rip_int_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
			}
		| T_TRUSTEDGATEWAYS gateway_list_inet
			{
			    rip_n_trusted += parse_gw_flag($2, RTPROTO_RIP, GWF_TRUSTED);
			    if (!rip_n_trusted) {
				PARSE_ERROR;
			    }
			}
		| T_SOURCEGATEWAYS gateway_list_inet
			{
			    rip_n_source += parse_gw_flag($2, RTPROTO_RIP, GWF_SOURCE);
			    if (!rip_n_source) {
				PARSE_ERROR;
			    }
			    BIT_SET(rip_flags, RIPF_SOURCE);
			}
		;

rip_interface_options
		: rip_interface_option
		| rip_interface_options rip_interface_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

rip_interface_option
		: T_RIPIN
			{
			    $$ = config_alloc(RIP_CONFIG_IN, (void_t) TRUE);
			}
		| T_NORIPIN
			{
			    $$ = config_alloc(RIP_CONFIG_IN, (void_t) FALSE);
			}
		| T_RIPOUT
			{
			    $$ = config_alloc(RIP_CONFIG_OUT, (void_t) TRUE);
			}
		| T_NORIPOUT
			{
			    $$ = config_alloc(RIP_CONFIG_OUT, (void_t) FALSE);
			}
		| T_METRICIN metric
			{
			    if (parse_metric_check(RTPROTO_RIP, &$2)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(RIP_CONFIG_METRICIN, (void_t) $2.metric);
			}
		| T_METRICOUT metric
			{
			    if (parse_metric_check(RTPROTO_RIP, &$2)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(RIP_CONFIG_METRICOUT, (void_t) $2.metric);
			}
		| T_AUTH rip_auth
			{
			    $$ = config_alloc(RIP_CONFIG_AUTH, $2);
			}
		| T_VERSION L_NUMBER rip_v2_options
			{
			    flag_t flag;
			    
			    switch ($2) {
			    case 1:
				if ($3) {
				    (void) sprintf(parse_error, "options not valid with version 1");
				    PARSE_ERROR;
				}
				flag = RIP_IFPS_V1;
				break;

			    case 2:
				if ($3) {
				    flag = $3;
				} else {
				    /* This means whatever options the interface is capable of */
#ifdef	IP_MULTICAST
				    flag = RIP_IFPS_V2;
#else	/* IP_MULTICAST */
				    flag = RIP_IFPS_V2BC;
#endif	/* IP_MULTICAST */
				}
				break;

			    default:
				(void) sprintf(parse_error, "invalid version");
				PARSE_ERROR;
			    }
			    $$ = config_alloc(RIP_CONFIG_FLAG, (void_t) flag);
			}
		;

rip_v2_options	: /* Empty */
			{
			    $$ = 0;
			}
		| T_MULTICAST
			{
			    $$ = RIP_IFPS_V2MC;
			}
		| T_BROADCAST
			{
			    $$ = RIP_IFPS_V2BC;
			}
		;

rip_auth	: T_NONE
			{
			    $$ = (void_t) 0;
			}
		| string
			{
			    struct authinfo *ap = (struct authinfo *) task_block_alloc(rip_auth_block_index);

			    if ($1.len > RIP_AUTH_SIZE) {
				sprintf(parse_error, "authentication-key \"%s\"%d longer than %d characters",
					$1.ptr,
					$1.len,
					RIP_AUTH_SIZE);
				PARSE_ERROR;
			    }

			    ap->auth_family = RIP_AF_AUTH;
			    ap->auth_type = RIP_AUTH_SIMPLE;
			    /* Left justify the authentication key */
			    (void) strncpy((caddr_t) ap->auth_data, $1.ptr, RIP_AUTH_SIZE);

			    free_charstr(&$1);

			    $$ = (void_t) ap;
			}
		;

rip_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| rip_trace_options
			{
			    $$ = $1;
			}
		| rip_trace_options T_EXCEPT rip_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

rip_trace_options
		: rip_trace_option
			{
			    $$ = $1;
			}
		| rip_trace_options rip_trace_option
			{
			    $$ = $1 | $2;
			}
		;

rip_trace_option
		: trace_option
    		| trace_option_detail trace_option_sendrecv rip_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		;

rip_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_RIP_INDEX_PACKETS;
			}
		| T_REQUEST
			{
			    $$ = TR_RIP_INDEX_REQUEST;
			}
		| T_RESPONSE
			{
			    $$ = TR_RIP_INDEX_RESPONSE;
			}
		| T_OTHER
			{
			    $$ = TR_RIP_INDEX_OTHER;
			}
    		;

rip_prop_init	: T_RIP
			{
			    $$ = parse_proto = RTPROTO_RIP;
			    parse_gwlist = &rip_gw_list;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

@END:	PROTO_RIP
@BEGIN:	NOT PROTO_RIP
rip_statement	: T_RIP T_OFF
			{
			}
		;
@END:	NOT PROTO_RIP

/*  */

@BEGIN:	PROTO_HELLO

hello_statement	: T_HELLO
			{
			    PROTO_SEEN(RTPROTO_HELLO);

			    parse_gwlist = &hello_gw_list;

			    hello_trace_options = trace_set_global(hello_trace_types,
								   (flag_t) 0);
			}
		onoff_option hello_group
			{
			    switch ($3) {
			    case T_OFF:
				BIT_RESET(hello_flags, HELLOF_ON);
				break;

			    case T_ON:
				BIT_SET(hello_flags, HELLOF_ON);
				break;
			    }
			}
		;

hello_group	: /* Empty */
		| '{' hello_group_stmts '}'
		;

hello_group_stmts
		: /* Empty */
		| hello_group_stmts hello_group_stmt L_EOS
		| hello_group_stmts error L_EOS
			{
			    yyerrok;
			}
		;

hello_group_stmt
		: T_PREFERENCE preference
			{
			    hello_preference = $2;
			}
		| T_DEFAULTMETRIC metric
			{
			    if (parse_metric_check(RTPROTO_HELLO, &$2)) {
				PARSE_ERROR;
			    }
			    hello_default_metric = $2.metric;
			}
		| T_BROADCAST
			{
			    hello_flags = (hello_flags & ~HELLOF_CHOOSE) | HELLOF_BROADCAST;
			}
		| T_NONBROADCAST
			{
			    hello_flags = hello_flags & ~(HELLOF_CHOOSE|HELLOF_BROADCAST);
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option hello_trace_options_none
			{
			    trace_store(hello_trace_options, $4, $3, $2, hello_trace_types);
			}
		| T_INTERFACE interface_all_list hello_interface_options
			{
			    config_list *list = config_list_alloc($3, 0);

			    parse_adv_propagate_config($2, list, RTPROTO_HELLO);

			    if (parse_adv_append(&hello_int_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
			}
		| T_TRUSTEDGATEWAYS gateway_list_inet
			{
			    hello_n_trusted += parse_gw_flag($2, RTPROTO_HELLO, GWF_TRUSTED);
			    if (!hello_n_trusted) {
				PARSE_ERROR;
			    }
			}
		| T_SOURCEGATEWAYS gateway_list_inet
			{
			    hello_n_source += parse_gw_flag($2, RTPROTO_HELLO, GWF_SOURCE);
			    if (!hello_n_source) {
				PARSE_ERROR;
			    }
			    BIT_SET(hello_flags, HELLOF_SOURCE);
			}
		;

hello_interface_options
		: hello_interface_option
		| hello_interface_options hello_interface_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

hello_interface_option
		: T_HELLOIN
			{
			    $$ = config_alloc(HELLO_CONFIG_IN, (void_t) TRUE);
			}
		| T_NOHELLOIN
			{
			    $$ = config_alloc(HELLO_CONFIG_IN, (void_t) FALSE);
			}
		| T_HELLOOUT
			{
			    $$ = config_alloc(HELLO_CONFIG_OUT, (void_t) TRUE);
			}
		| T_NOHELLOOUT
			{
			    $$ = config_alloc(HELLO_CONFIG_OUT, (void_t) FALSE);
			}
		| T_METRICIN metric
			{
			    if (parse_metric_check(RTPROTO_HELLO, &$2)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(HELLO_CONFIG_METRICIN, (void_t) $2.metric);
			}
		| T_METRICOUT metric
			{
			    if (parse_metric_check(RTPROTO_HELLO, &$2)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(HELLO_CONFIG_METRICOUT, (void_t) $2.metric);
			}
		;

hello_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| hello_trace_options
			{
			    $$ = $1;
			}
		| hello_trace_options T_EXCEPT hello_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

hello_trace_options
		: hello_trace_option
			{
			    $$ = $1;
			}
		| hello_trace_options hello_trace_option
			{
			    $$ = $1 | $2;
			}
		;

hello_trace_option
		: trace_option
    		| trace_option_detail trace_option_sendrecv hello_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		;

hello_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_HELLO_INDEX_PACKETS;
			}
    		;


hello_prop_init	: T_HELLO
			{
			    $$ = parse_proto = RTPROTO_HELLO;
			    parse_gwlist = &hello_gw_list;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;
@END:	PROTO_HELLO

    
/*  */

@BEGIN:	PROTO_OSPF

ospf_statement	: T_OSPF
			{
			    PROTO_SEEN(RTPROTO_OSPF);

			    parse_gwlist = &ospf.gw_list;

			    ospf.trace_options = trace_set_global(ospf_trace_types,
								  (flag_t) 0);

			    /* Somewhere around here is where we will figure out which OSPF global structure we are */
			    /* refering to and initialize it once we support multiple instantations of OSPF that is. */
			}
		onoff_option ospf_group
			{
			    if ($3 == T_OFF) {
				ospf.ospf_admin_stat = OSPF_DISABLED;
			    } else {
				if (ospf_parse_valid_check(parse_error)) {
				    PARSE_ERROR;
				}
				ospf.ospf_admin_stat = OSPF_ENABLED;
			    }
			}
		;

ospf_group	: /* Empty */
		| '{' ospf_group_stmts '}'
		;

ospf_group_stmts	: /* Empty */
		| ospf_group_stmts ospf_group_stmt L_EOS
		| ospf_group_stmts error L_EOS
			{
				yyerrok;
			}
		;

ospf_group_stmt	: T_DEFAULTS '{' ospf_defaults '}'
			{
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option ospf_trace_options_none
			{
			    trace_store(ospf.trace_options, $4, $3, $2, ospf_trace_types);
			}
		| T_EXPORTINTERVAL time
			{
			    ospf.export_interval = $2;
			}
		| T_EXPORTLIMIT number
			{
			    ospf.export_limit = $2;
			}
		| T_MONITORAUTHKEY ospf_auth_key
			{
			    ospf.mon_authtype = OSPF_AUTH_SIMPLE;
			    bcopy((caddr_t) $2.ptr, (caddr_t) ospf.mon_authkey, OSPF_AUTH_SIZE);

			    free_bytestr(&$2);
			}
		| T_SYSLOG ospf_syslog_first ospf_syslog_every
			{
			    ospf.log_first = $2;
			    ospf.log_every = $3;
			}
		| ospf_area_option
			{
			    ospf_AREA = ospf_parse_area_alloc($1, parse_error);
			    if (!ospf_AREA) {
				PARSE_ERROR;
			    }
			    ospf_AREA->authtype = OSPF_AUTH_NONE;		/* Default to no authentication */
			}
		'{' ospf_area_stmts '}'
			{
			    if (ospf_parse_area_check(ospf_AREA, parse_error)) {
				PARSE_ERROR;
			    }
			}
		;

ospf_syslog_first
		: /* Empty */
			{
			    $$ = OSPF_LOG_FIRST;
			}
		| T_FIRST number
			{
			    if (parse_limit_check("syslog first",
						  (u_int) $2,
						  OSPF_LIMIT_LOG_FIRST)) {
				PARSE_ERROR;
			    }
			    $$ = $2;
			}
		;

ospf_syslog_every
		: /* Empty */
			{
			    $$ = OSPF_LOG_EVERY;
			}
		| T_EVERY number
			{
			    if (parse_limit_check("syslog every",
						  (u_int) $2,
						  OSPF_LIMIT_LOG_EVERY)) {
				PARSE_ERROR;
			    }
			    $$ = $2;
			}
		;

ospf_defaults	: /* Empty */
		| ospf_defaults ospf_default L_EOS
    		| ospf_defaults error L_EOS
			{
			    yyerrok;
			}
		;

ospf_default	: T_PREFERENCE preference
			{
			    ospf.preference_ase = $2;
			}
		| T_METRIC ospf_cost
			{
			    ospf.export_metric = $2.metric;
			}
@BEGIN:	PROTO_ASPATHS
		| T_TAG tag_as
			{
			    switch ($2.state) {
			    case PARSE_METRICS_SET:
				ospf.export_tag = $2.metric;
				break;

			    case PARSE_METRICS_ALTERNATE:
				ospf.export_tag = PATH_OSPF_TAG_TRUSTED |
				    (($2.metric << PATH_OSPF_TAG_USR_SHIFT) & PATH_OSPF_TAG_USR_MASK);
				break;
			    }
			}
@END:	PROTO_ASPATHS
		| T_TYPE ospf_type
			{
			    ospf.export_type = $2.metric;
			}
		;

ospf_area_stmts	: /* Empty */
    		| ospf_area_stmts ospf_area_stmt L_EOS
    		| ospf_area_stmts error L_EOS
			{
			    yyerrok;
			}
		;

ospf_area_stmt	: T_AUTHTYPE ospf_auth_type
			{
			    ospf_AREA->authtype = $2;
			}
		| T_STUB ospf_cost_option
			{
			    if (ospf_AREA->area_id == OSPF_BACKBONE) {
				(void) sprintf(parse_error, "stub option not valid for backbone");
				PARSE_ERROR;
			    }

			    /* This is a stub */
			    BIT_SET(ospf_AREA->area_flags, OSPF_AREAF_STUB);

			    /* And we inject a default */
			    if (PARSE_METRIC_ISSET(&$2)) {
				BIT_SET(ospf_AREA->area_flags, OSPF_AREAF_STUB_DEFAULT);
				ospf_AREA->dflt_metric = $2.metric;
			    }
			}    
		| T_STUBHOSTS '{' ospf_stub_list '}' {}
		| T_NETWORKS '{' ospf_area_range_list '}'
			{
			    adv_entry *adv;

			    if (ospf_AREA->nrcnt) {
				(void) sprintf(parse_error, "net range already specified");
				PARSE_ERROR;
			    }

			    /* Install each of the entries */
			    ADV_LIST(adv_destmask_finish($3), adv) {
				ospf_parse_add_net(ospf_AREA,
						   adv->adv_dm.dm_dest,
						   adv->adv_dm.dm_mask);
			    } ADV_LIST_END($3, adv) ;

			    adv_free_list($3);
			}
		| T_INTERFACE ospf_interface
			{
			    if (parse_adv_append(&ospf_AREA->intf_policy, $2)) {
				PARSE_ERROR;
			    }
			}
    		| T_VIRTUALLINK T_NEIGHBORID host T_TRANSITAREA ospf_area ospf_common
			{
			    struct INTF *vif;

			    vif = ospf_parse_virt_parse(ospf_AREA, $3, $5, $6, parse_error);
			    if (!vif) {
				PARSE_ERROR;
			    }

			    config_list_free($6);
			}
		;

ospf_interface
		: interface_all_list ospf_cost_option ospf_common
			{
			    config_list *list = $3;

			    if (PARSE_METRIC_ISSET(&$2)) {

				list = config_list_add(list,
						       config_alloc(OSPF_CONFIG_COST,
								    (void_t) $2.metric),
						       ospf_config_free);
				if (!list) {
				    PARSE_ERROR;
				}
			    }

			    parse_adv_propagate_config($1, list, RTPROTO_OSPF);

			    config_list_free(list);

			    $$ = $1;
			}
		| interface_all_list T_NONBROADCAST ospf_cost_option ospf_nonbroadcast
			{
			    config_list *list = $4;

			    list = config_list_add(list,
						   config_alloc(OSPF_CONFIG_TYPE,
								(void_t) NONBROADCAST),
						   ospf_config_free);
			    if (!list) {
				PARSE_ERROR;
			    }
			    
			    if (PARSE_METRIC_ISSET(&$3)) {

				list = config_list_add(list,
						       config_alloc(OSPF_CONFIG_COST,
								    (void_t) $3.metric),
						       ospf_config_free);
				if (!list) {
				    PARSE_ERROR;
				}
			    }

			    parse_adv_propagate_config($1, list, RTPROTO_OSPF);

			    config_list_free(list);

			    $$ = $1;
			}
		;

ospf_common	: /* Empty */
			{
			    $$ = (config_list *) 0;
			}
		| '{' ospf_common_options '}'
			{
			    $$ = config_list_alloc($2, ospf_config_free);
			}
		;

ospf_common_options
		: ospf_common_option L_EOS
		| ospf_common_options ospf_common_option L_EOS
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| ospf_common_options error L_EOS
			{
				yyerrok;
			}
		;

ospf_nonbroadcast
		: /* Empty */
			{
			    $$ = (config_list *) 0;
			}
		| '{' ospf_nonbroadcast_options '}'
			{
			    $$ = config_list_alloc($2, ospf_config_free);
			}
		;

ospf_nonbroadcast_options
		: ospf_nonbroadcast_option L_EOS
		| ospf_nonbroadcast_options ospf_nonbroadcast_option L_EOS
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| ospf_nonbroadcast_options error L_EOS
			{
				yyerrok;
			}
		;

ospf_common_option
		: T_ENABLE
			{
			    $$ = config_alloc(OSPF_CONFIG_ENABLE, (void_t) TRUE);
			}
		| T_DISABLE
			{
			    $$ = config_alloc(OSPF_CONFIG_ENABLE, (void_t) FALSE);
			}
		| T_RXMITINTERVAL time
			{
			    if (parse_limit_check("retransmit-interval",
						  (u_int) $2,
						  OSPF_LIMIT_RETRANSMITINTERVAL)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(OSPF_CONFIG_RETRANSMIT, (void_t) $2);
			}
		| T_INFTRANSDELAY time
			{
			    if (parse_limit_check("transit-delay",
						  (u_int) $2,
						  OSPF_LIMIT_TRANSITDELAY)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(OSPF_CONFIG_TRANSIT, (void_t) $2);
			}
		| T_PRIORITY ospf_priority
			{
			    $$ = config_alloc(OSPF_CONFIG_PRIORITY, (void_t) $2);
			}
		| T_HELLOINTERVAL time
			{
			    if (parse_limit_check("hello-interval",
						  (u_int) $2,
						  OSPF_LIMIT_HELLOINTERVAL)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(OSPF_CONFIG_HELLO, (void_t) $2);
			}
		| T_ROUTERDEADINTERVAL time
			{
			    if (parse_limit_check("router-dead-interval",
						  (u_int) $2,
						  OSPF_LIMIT_ROUTERDEADINTERVAL)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(OSPF_CONFIG_ROUTERDEAD, (void_t) $2);
			}
		| T_AUTHKEY ospf_auth_key
			{
			    /* Side-effect: The authentication type must be specified first */

			    switch (ospf_AREA->authtype) {
			    case OSPF_AUTH_NONE:
				sprintf(parse_error, "authentication-key specified when authentication-type is none");
				PARSE_ERROR;
				/* break; */

			    case OSPF_AUTH_SIMPLE:
				/* Simple password */
				break;

			    default:
				sprintf(parse_error, "unknown authentication type: %d",
					ospf_AREA->authtype);
				PARSE_ERROR;
			    }

			    $$ = config_alloc(OSPF_CONFIG_AUTHKEY,
					      (void_t) sockdup(sockbuild_byte($2.ptr, $2.len)));

			    free_bytestr(&$2);
			}
		;

ospf_nonbroadcast_option
		: ospf_common_option
		| T_POLLINTERVAL time
			{
			    if (parse_limit_check("poll-interval",
						  (u_int) $2,
						  OSPF_LIMIT_POLLINTERVAL)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(OSPF_CONFIG_POLL, (void_t) $2);
			}
		| T_ROUTERS '{' ospf_router_eligible_list '}'
			{
			    $$ = config_alloc(OSPF_CONFIG_ROUTERS, (void_t) $3);
			}
		;

/* OSPF costs */
ospf_cost_option	: /* Empty */
			{
			    PARSE_METRIC_CLEAR(&$$);
			}
		| T_METRIC ospf_cost
			{
				$$ = $2;
			}
		;

ospf_cost	: metric
			{
			    $$ = $1;
			    if (parse_metric_check(RTPROTO_OSPF, &$$)) {
				PARSE_ERROR;
			    }
			}
		;

/* OSPF external route type */
ospf_type_option	: /* Empty */
			{
			    PARSE_METRIC_CLEAR(&$$);
			}
		| T_TYPE ospf_type
			{
			    $$ = $2;
			}
		;

ospf_type	: L_NUMBER
			{
			    if (parse_limit_check("export-type",
						  (u_int) $1,
						  OSPF_LIMIT_EXPORTTYPE)) {
				PARSE_ERROR;
			    }
			    PARSE_METRIC_SET(&$$, $1);
			}
		;

ospf_area_option
		: T_AREA ospf_area
			{
			    $$ = $2;
			}
		| T_BACKBONE
			{
			    $$ = OSPF_BACKBONE;
			}
		;

ospf_area	: number
			{
			    if (parse_limit_check("area-number",
						  (u_int) $1,
						  OSPF_LIMIT_AREA)) {
				PARSE_ERROR;
			    }
			    $$ = htonl((u_int32) $1);
			}
		;

ospf_auth_type	: L_NUMBER
			{
			    if (parse_limit_check("authentication-type",
						  (u_int) $1,
						  OSPF_LIMIT_AUTHTYPE)) {
				PARSE_ERROR;
			    }
			    $$ = $1;
			}
		| T_NONE
			{
			    $$ = OSPF_AUTH_NONE;
			}
		| T_SIMPLE
			{
			    $$ = OSPF_AUTH_SIMPLE;
			}
		;

ospf_auth_key	: string
			{
			    if ($1.len > OSPF_AUTH_SIZE) {
				sprintf(parse_error, "authentication-key \"%s\"%d longer than %d characters",
					$1.ptr,
					$1.len,
					OSPF_AUTH_SIZE);
				PARSE_ERROR;
			    }

			    $$.type = $1.type;
			    $$.len = OSPF_AUTH_SIZE;
			    $$.ptr = (byte *) task_mem_calloc((task *) 0, 1, OSPF_AUTH_SIZE);
			    
			    /* Left justify the authentication key */
			    (void) strncpy((caddr_t) $$.ptr, $1.ptr, $1.len);

			    free_charstr(&$1);
			}
		| L_NUMBER
			{
			    int offset = OSPF_AUTH_SIZE - sizeof ($1);

			    $$.type = L_NUMBER;
			    $$.len = OSPF_AUTH_SIZE;
			    $$.ptr = (byte *) task_mem_calloc((task *) 0, 1, OSPF_AUTH_SIZE);

			    /* Right justify the authentication key */
			    bcopy((caddr_t) &$1, (caddr_t) $$.ptr + offset, sizeof($1));
			}
		| byte_string
			{
			    int offset = OSPF_AUTH_SIZE - $1.len;

			    if (offset < 0) {
				sprintf(parse_error, "authentication-key longer than %d characters",
					OSPF_AUTH_SIZE);
				PARSE_ERROR;
			    }

			    $$.type = $1.type;
			    $$.len = OSPF_AUTH_SIZE;
			    $$.ptr = (byte *) task_mem_calloc((task *) 0, 1, OSPF_AUTH_SIZE);

			    /* Right justify the authentication key */
			    bcopy((caddr_t) $1.ptr, (caddr_t) $$.ptr + offset, $1.len);

			    free_bytestr(&$1);
			}
    		;



ospf_stub_list	: ospf_stub L_EOS
    		| ospf_stub_list ospf_stub L_EOS
    		| ospf_stub_list error L_EOS
			{
			    yyerrok;
			}
    		;

ospf_stub	: host T_METRIC ospf_cost
			{
			    ospf_parse_add_host(ospf_AREA, sock2ip($1), $3.metric);

			    sockfree($1);
			}
		;

ospf_router_eligible_list
		: ospf_router_eligible L_EOS
		| ospf_router_eligible_list ospf_router_eligible L_EOS
			{
			    ($$ = $2)->ocr_next = $1;
			}
		| ospf_router_eligible_list error L_EOS
			{
			    yyerrok;
			}
    		;

ospf_router_eligible
		: gateway_inet ospf_eligible_option
			{
			    $$ = ospf_parse_router_alloc(sock2in($1->gw_addr), (u_int) $2);
			}
		;

ospf_eligible_option
		: /* Empty */
			{
			    $$ = 0;
			}
		| T_ELIGIBLE
			{
			    $$ = 1;
			}
		;

ospf_priority	: L_NUMBER
			{
			    if (parse_limit_check("priority",
						  (u_int) $1,
						  OSPF_LIMIT_DRPRIORITY)) {
				PARSE_ERROR;
			    }
			    $$ = $1;
			}
		;

ospf_prop_init	: T_OSPF
			{
			    $$ = parse_proto = RTPROTO_OSPF;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

ospf_ase_prop_init
		: T_OSPF_ASE
			{
			    /* Make sure this PS type is known */
			    adv_psfunc_add(RTPROTO_OSPF_ASE, &ospf_adv_psfunc);

			    $$ = parse_proto = RTPROTO_OSPF_ASE;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

ospf_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| ospf_trace_options
			{
			    $$ = $1;
			}
		| ospf_trace_options T_EXCEPT ospf_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

ospf_trace_options
		: ospf_trace_option
			{
			    $$ = $1;
			}
		| ospf_trace_options ospf_trace_option
			{
			    $$ = $1 | $2;
			}
		;

ospf_trace_option
		: trace_option
    		| trace_option_detail trace_option_sendrecv ospf_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		| T_LSA_BLD
			{
			    $$ = TR_OSPF_LSA_BLD;
			}
		| T_LSA_TX
			{
			    $$ = TR_OSPF_LSA_TX;
			}
		| T_LSA_RX
			{
			    $$ = TR_OSPF_LSA_RX;
			}
		| T_SPF
			{
			    $$ = TR_OSPF_SPF;
			}
		| T_TRAP
			{
			    $$ = TR_OSPF_TRAP;
			}
		| T_DEBUG
			{
#ifdef	DEBUG
			    $$ = TR_OSPF_DEBUG;
#else	/* DEBUG */
			    $$ = 0;
#endif	/* DEBUG */
			}
		;

ospf_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_OSPF_INDEX_PACKETS;
			}
		| T_HELLO
			{
			    $$ = TR_OSPF_INDEX_HELLO;
			}
		| T_DD
			{
			    $$ = TR_OSPF_INDEX_DD;
			}
		| T_REQUEST
			{
			    $$ = TR_OSPF_INDEX_LSR;
			}
		| T_UPDATE
			{
			    $$ = TR_OSPF_INDEX_LSU;
			}
		| T_ACK
			{
			    $$ = TR_OSPF_INDEX_ACK;
			}
		;
		

ospf_area_range_list
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| ospf_area_range_list ospf_area_range L_EOS
			{
			    if (sock2ip($2.dm_dest) == INADDR_ANY) {
				sprintf(parse_error, "invalid range %A/%A",
					$2.dm_dest,
					$2.dm_mask);
				PARSE_ERROR;
			    }
			    $$ = adv_alloc(ADVFT_DM, (proto_t) 0);
			    $$->adv_dm = $2;
			    $$ = adv_destmask_insert(parse_error, $1, $$);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| ospf_area_range_list error L_EOS
			{
			    yyerrok;
			}
		
		;

ospf_area_range	: host_mask_inet
		| network_mask_inet
		;

@END:	PROTO_OSPF
    
/*  */

@BEGIN:	PROTO_ISIS

/* ISIS protocol statements & etc, in the format of other protocols */

isis_statement  : T_ISIS
                        {
			    PROTO_SEEN(RTPROTO_ISIS);

#ifdef	notyet
			    parse_gwlist = &isis.gw_list;
#endif	/* notyet */

			    isis_trace_options = trace_set_global(isis_trace_types,
								  (flag_t) 0);

			    /* XXX - should be done by above */
			    isis_plevel = 1;
                        }
		  isis_option isis_group 
			{

			    ip_supported = 0;
			    clnp_supported = 0;
			    switch ($3) {
			    case T_OFF:
				break;
			    /* XXX - Check validity of configuration for the following */
			    case T_IP:
				ip_supported = 1;
				doing_isis = TRUE;
				break;
			    case T_ISO:
				clnp_supported = 1;
				doing_isis = TRUE;
				break;
			    case T_ON:
			    case T_DUAL:
				ip_supported = clnp_supported = 1;
				doing_isis = TRUE;
			    }
			}
		;

isis_option	: onoff_option
		| T_IP		{ $$ = T_IP; }
		| T_ISO		{ $$ = T_ISO; }
		| T_DUAL	{ $$ = T_DUAL; }
		;

isis_group      : /* Empty */
                | '{' isis_group_stmts '}'
		;

isis_group_stmts	: /* Empty */
		| isis_group_stmts isis_group_stmt L_EOS
		| isis_group_stmts error L_EOS
			{
				yyerrok;
			}
		;

isis_group_stmt	: isis_level
			{
			    isis_plevel = $1;
			}
		| T_CIRCUIT string
			{
			    if (BIT_TEST(task_state, TASKS_RECONFIG)) {
				if ((isis_ci = isis_GetIspcByName($2)) == 0) {
				    /* this is a config of a new circuit */    
				    isis_ci = ++isis_circuits_parsed;
				    bzero(&isis_ca[isis_ci], sizeof(struct is_pc));
				    strcpy(isis_ca[isis_ci].name, $2.ptr);
			    	    /* isis_init_ca(&isis_ca[isis_ci], $2); */
				    trace_tf(trace_global,
					     TR_PARSE,
					     0,
					     ("parse: %s IS-IS reconfig parsed new circuit #%d -> %s",
					      parse_where(),
					      isis_ci,
					      $2));
				} else {
				    trace_tf(trace_global,
					     TR_PARSE,
					     0,
					     ("parse: %s IS-IS reconfig parsed existing circuit #%d -> %s",
					      parse_where(),
					      isis_ci,
					      $2));
				} 
			    } else {
				/* remember new circuit */
			    	isis_ci = ++isis_circuits_parsed;
				trace_tf(trace_global,
					 TR_PARSE,
					 0,
					 ("parse: %s IS-IS config parsed new circuit #%d -> %s",
					  parse_where(),
					  isis_ci,
					  $2));
				bzero(&isis_ca[isis_ci], sizeof(struct is_pc));
				strcpy(isis_ca[isis_ci].name, $2.ptr);
			    	/* isis_init_ca(&isis_ca[isis_ci], $2); */
			    }
			}
		isis_coptions
			{
			}
		| T_SYSTEMID string
			{
			    isis_set_sysid($2);
			}
		| T_TRACEOPTIONS isis_trace_options
			{
			    isis_save_trace($2);
			}
		| T_SNPA number
			{
			    /* we need an index in lieu of the NSAP address; used to use getpid */
			    isis_snpa = $2;
			}
		| T_AREA string
			{
			    isis_saveArea($2);
			}
		| T_IPREACH isis_level ipreach_type network_inet mask T_METRIC number 
			{
			    save_ipreach($2,$3,&$4,&$5,$7);
			}
		| T_PREFIX prefix_type T_METRIC number string
			{
			    isis_savePrefix($5.ptr, $4, $2);
			}
		| T_INTDOMINFO string
			{
			    isis_saveInterDomInfo($2);
			}
		| T_SET L_KEYWORD number
			{
			    isis_set_parm($2.ptr, $3);
			}
    		/* nothing else for now */
		;

isis_level	: T_LEVEL number
			{
			    $$ = $2;
			}
		| /* empty */
			{
			    $$ = 1;
			}
		;

isis_mode	: T_IP
			{
			    $$ = T_IP;
			}
                | T_ISO
			{
			    $$ = T_ISO;
			}
                | T_DUAL
			{
			    $$ = T_DUAL;
			}
                ;

isis_coptions	: /* Empty */
		| isis_coptions isis_coption
		;

isis_coption	: T_METRIC isis_level number
			{
			    if ($2 == 2) {
				isis_ca[isis_ci].l2metric = $3;
			    } else {
				isis_ca[isis_ci].metric = $3;
			    }
			}
		| T_PRIORITY isis_level number
			{
			    if ($2 == 2) {
				isis_ca[isis_ci].l2prior = $3;
			    } else {
				isis_ca[isis_ci].prior = $3;
			    }
			}
		;

ipreach_type	: T_INTERNAL
			{
			    $$ = ISIS_INTERNAL;
			}
		| T_EXTERNAL
			{
			    $$ = ISIS_EXTERNAL;
			}
		| TISIS_SUMMARY
			{
			    $$ = ISIS_SUMMARY;
			}
		;

prefix_type	: T_INTERNAL
			{
			    $$ = ISIS_INTERNAL;
			}
		| T_EXTERNAL
			{
			    $$ = ISIS_EXTERNAL;
			}
		;

isis_trace_options	: isis_trace_option
			| isis_trace_options isis_trace_option
				{
				    $$ = $1 | $2;
				}
			| isis_trace_options T_EXCEPT isis_trace_option
				{
				    $$ = $1 & ~$2;
				}
			;

isis_trace_option
    		: T_ALL         { $$ = T_ISISALL; }
		| TISIS_IIH		{ $$ = T_DUMPIIH; }
		| TISIS_DUMPLSP         { $$ = T_DUMPLSP; }
		| TISIS_EVENTS          { $$ = T_EVENTS; }
		| TISIS_LANADJ          { $$ = T_LANADJ; }
		| TISIS_FLOODING        { $$ = T_FLOODING; }
		| TISIS_BUILDLSP        { $$ = T_BUILDLSP; }
		| TISIS_CSNP            { $$ = T_CSNP; }
		| TISIS_PSNP            { $$ = T_PSNP; }
		| TISIS_LSPINPUT        { $$ = T_LSPINPUT; }
		| TISIS_P2PADJ          { $$ = T_P2PADJ; }
		| T_SPF             	{ $$ = T_TRSPF; }
		| TISIS_LSPDB           { $$ = T_DUMPDB; }
		| T_ROUTE		{ $$ = T_ROUTE2; }
		| T_UPDATE		{ $$ = T_ROUTE1; }
		| TISIS_PATHS		{ $$ = T_ROUTE3; }
		| TISIS_LSPCONTENT	{ $$ = T_LSPCONTENT; }
		;


isis_prop_init	: T_ISIS
			{
			    $$ = parse_proto = RTPROTO_ISIS;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

@END:	PROTO_ISIS

/*  */

@BEGIN:	PROTO_SLSP

slsp_statement : T_SLSP
			{
			    PROTO_SEEN(RTPROTO_SLSP);

			    slsp_global_trace_options = trace_set_global(slsp_trace_types,
								  (flag_t) 0);
                        }
		onoff_option slsp_group
			{

			    switch ($3) {
			    case T_OFF:
				doing_slsp = FALSE;
				break;
				
			    case T_ON:
				/* XXX - Check validity of configuration */
				doing_slsp = TRUE;
			    }
			}
		;
    
slsp_group      : /* Empty */
                | '{' slsp_group_stmts '}'
		;

slsp_group_stmts
		: /* Empty */
		| slsp_group_stmts slsp_group_stmt L_EOS
		| slsp_group_stmts error L_EOS
			{
				yyerrok;
			}
		;

slsp_group_stmt	: T_INSTANCE T_NODE network_mask_inet T_NODEMASK mask_inet preference_option
			{
			    slsp_parse_instance = slsp_parse_instance_alloc($3.dm_dest,
									    $3.dm_mask,
									    $5);

			    if (PARSE_METRIC_ISSET(&$6)) {
				slsp_parse_instance->slsp_preference = $6.metric;
			    }
			}
		  '{' slsp_instance_list '}'
			{
			    if (slsp_parse_instance_check(&slsp_parse_instance, parse_error)) {
				PARSE_ERROR;
			    }
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option slsp_trace_options_none
			{
			    trace_store(slsp_global_trace_options, $4, $3, $2, slsp_trace_types);
			}
		;

slsp_instance_list
		: slsp_instance L_EOS
		| slsp_instance_list slsp_instance L_EOS
		;

slsp_instance	: T_DEFAULTS '{' slsp_defaults '}' {}
		| T_TRACEOPTIONS trace_file_option trace_control_option slsp_trace_options_none
			{
			    trace_store(slsp_parse_instance->slsp_trace_options, $4, $3, $2, slsp_trace_types);
			}
		| T_INTERFACE interface_all_list slsp_interfaces
			{
			    config_list *list = config_list_alloc($3, slsp_config_free);

			    parse_adv_propagate_config($2, list, RTPROTO_SLSP);

			    if (parse_adv_append(&slsp_parse_instance->slsp_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
			}
		| T_NEIGHBOR
			{
			    parse_gwlist = &parse_gwp;
			}
		  gateway_inet
			{
			    slsp_parse_gateway = slsp_parse_gateway_alloc(slsp_parse_instance, $3->gw_addr);

			    gw_freelist(*parse_gwlist);
			    parse_gwlist = (gw_entry **) 0;
			    parse_gwp = (gw_entry *) 0;
			}
		  slsp_gateway_list
			{
			    if (slsp_parse_gateway_check(slsp_parse_instance, &slsp_parse_gateway, parse_error)) {
				PARSE_ERROR;
			    }
			}
		;


slsp_defaults	: slsp_default
		| slsp_defaults slsp_default
		;

slsp_default	: slsp_hello
			{
			    slsp_parse_instance->slsp_def_hellointerval = $1;
			}
		| slsp_dead
			{
			    slsp_parse_instance->slsp_def_routerdeadinterval = $1;
			}
		| slsp_cost
			{
			    slsp_parse_instance->slsp_def_cost = $1.metric;
			}
		| slsp_priority
			{
			    slsp_parse_instance->slsp_def_priority = $1;
			}
		;

slsp_interfaces
		: slsp_interface
		| slsp_interfaces slsp_interface
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

slsp_interface	: slsp_hello
			{
			    $$ = config_alloc(SLSP_CONFIG_HELLO, (void_t) $1);
			}
		| slsp_dead
			{
			    $$ = config_alloc(SLSP_CONFIG_ROUTER, (void_t) $1);
			}
		| slsp_cost
			{
			    $$ = config_alloc(SLSP_CONFIG_COST, (void_t) $1.metric);
			}
		| slsp_priority
			{
			    $$ = config_alloc(SLSP_CONFIG_PRIORITY, (void_t) $1);
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option slsp_trace_options_none
			{
			    trace *trp = (trace *) 0;
			    
			    trace_store(trp, $4, $3, $2, slsp_trace_types);

			    if (trp) {
				$$ = config_alloc(SLSP_CONFIG_TRACE, (void_t) trp);
			    } else {
				$$ = (config_entry *) 0;
			    }
			}
		;

slsp_gateway_list
		: slsp_gateway
		| slsp_gateway_list slsp_gateway
		;

slsp_gateway	: slsp_hello
			{
			    slsp_parse_gateway->slsp_gw_hellointerval = $1;
			}
		| slsp_dead
			{
			    slsp_parse_gateway->slsp_gw_routerdeadinterval = $1;
			}
		| slsp_cost
			{
			    slsp_parse_gateway->slsp_gw_cost = $1.metric;
			}
		| slsp_priority
			{
			    slsp_parse_gateway->slsp_gw_priority = $1;
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option slsp_trace_options_none
			{
			    trace_store(slsp_parse_gateway->slsp_gw_trace_options, $4, $3, $2, slsp_trace_types);
			}
		;

slsp_hello	: T_HELLOINTERVAL time
			{
			    $$ = $2;
			    if (parse_limit_check("hello-interval",
						  (u_int) $$,
						  SLSP_LIMIT_HELLOINTERVAL)) {
				PARSE_ERROR;
			    }
			}
		;

slsp_dead	: T_ROUTERDEADINTERVAL time
			{
			    $$ = $2;
			    if (parse_limit_check("router-dead-interval",
						  (u_int) $$,
						  SLSP_LIMIT_ROUTERDEADINTERVAL)) {
				PARSE_ERROR;
			    }
			}
		;

slsp_cost	: T_METRIC metric
			{
			    $$ = $2;
			    if (parse_metric_check(RTPROTO_SLSP, &$$)) {
				PARSE_ERROR;
			    }
			}
		;

slsp_priority	: T_PRIORITY L_NUMBER
			{
			    $$ = $2;
			    if (parse_limit_check("priority",
						  (u_int) $$,
						  SLSP_LIMIT_PRIORITY)) {
				PARSE_ERROR;
			    }
			}
		;

slsp_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| slsp_trace_options
			{
			    $$ = $1;
			}
		| slsp_trace_options T_EXCEPT slsp_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

slsp_trace_options
		: slsp_trace_option
			{
			    $$ = $1;
			}
		| slsp_trace_options slsp_trace_option
			{
			    $$ = $1 | $2;
			}
		;

slsp_trace_option
		: trace_option
    		| trace_option_detail trace_option_sendrecv slsp_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		| T_SPF
			{
			    $$ = TR_OSPF_SPF;
			}
		;

slsp_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_SLSP_INDEX_PACKETS;
			}
		| T_REQUEST
			{
			    $$ = TR_SLSP_INDEX_HELLO;
			}
		| T_RESPONSE
			{
			    $$ = TR_SLSP_INDEX_LSP;
			}
    		;

slsp_prop_init	: T_SLSP
			{
			    $$ = parse_proto = RTPROTO_SLSP;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

@END:	PROTO_SLSP    

/*  */

@BEGIN:	PROTO_RDISC

rdisc_statement : T_ROUTERDISCOVERY
			{
			    PROTO_SEEN(RTPROTO_RDISC);

			    rdisc_global_trace_options = trace_set_global(rdisc_trace_types,
								  (flag_t) 0);
                        }
		onoff_option rdisc_group
			{

			    switch ($3) {
			    case T_OFF:
				doing_rdisc = FALSE;
				break;
				
			    case T_ON:
				/* XXX - Check validity of configuration */
				doing_rdisc = TRUE;
			    }
			}
		;
    
rdisc_group	: /* Empty */
                | '{' rdisc_group_stmts '}'
		;

rdisc_group_stmts
		: /* Empty */
		| rdisc_group_stmts rdisc_group_stmt L_EOS
		| rdisc_group_stmts error L_EOS
			{
			    yyerrok;
			}
		;

/* address <interface_list> preference <pref> rdisc nordisc multicast broadcast */
/* interface <link_list> maxadvinterval <time> minadvinerval <time> advlife <time> */

rdisc_group_stmt
		: T_INTERFACE intf_phys_all_list rdisc_phys_options
			{
			    config_list *list = config_list_alloc($3, 0);

			    parse_adv_propagate_config($2, list, 0);

			    if (parse_adv_append(&rdisc_interface_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
			}
		| T_ADDRESS interface_all_list rdisc_addr_options
			{
			    config_list *list = config_list_alloc($3, 0);

			    parse_adv_propagate_config($2, list, 0);

			    if (parse_adv_append(&rdisc_address_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
			}
		;

rdisc_phys_options
		: rdisc_phys_option
		| rdisc_phys_options rdisc_phys_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

rdisc_phys_option
		: rdisc_phys_type
			{
			    $$ = config_alloc(RDISC_CONFIG_MULTICAST, (void_t) $1);
			}
		| T_MAXADVINTERVAL time
			{
			    if (parse_limit_check("maxadvertisementlinterval",
						  (u_int) $2,
						  RDISC_LIMIT_MAXADVINTV)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(RDISC_CONFIG_MAXADVINTV, (void_t) $2);
			}
		| T_MINADVINTERVAL time
			{
			    if (parse_limit_check("minadvertisementlinterval",
						  (u_int) $2,
						  RDISC_LIMIT_MINADVINTV)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(RDISC_CONFIG_MINADVINTV, (void_t) $2);
			}
		| T_LIFETIME time
			{
			    if (parse_limit_check("advertisementlifetime",
						  (u_int) $2,
						  RDISC_LIMIT_LIFETIME)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(RDISC_CONFIG_LIFETIME, (void_t) $2);
			}
		;

rdisc_phys_type	: T_MULTICAST
			{
			    $$ = TRUE;
			}
		| T_BROADCAST
			{
			    $$ = FALSE;
			}
		;

rdisc_addr_options
		: rdisc_addr_option
		| rdisc_addr_options rdisc_addr_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

rdisc_addr_option
		: rdisc_addr_ignore
			{
			    $$ = config_alloc(RDISC_CONFIG_IGNORE, (void_t) $1);
			}
		| T_PREFERENCE rdisc_addr_preference
			{
			    $$ = config_alloc(RDISC_CONFIG_PREFERENCE, (void_t) $2);
			}
		;

rdisc_addr_ignore
		: T_ADVERTISE
			{
			    $$ = FALSE;
			}
		| T_IGNORE
			{
			    $$ = TRUE;
			}
		;

rdisc_addr_preference
		: T_INELIGIBLE
			{
			    $$ = RDISC_PREFERENCE_INELIGIBLE
			}
		| T_PREFERENCE L_NUMBER
			{
			    if (parse_limit_check("preferencelevel",
						  (u_int) $2,
						  RDISC_LIMIT_PREFERENCE)) {
				PARSE_ERROR;
			    }
			    $$ = $2;
			}
		;

@END:	PROTO_RDISC

/*  */

@BEGIN:	PROTO_IDPR

idpr_statement	: T_IDPR onoff_option idpr_config_file
			{
			    PROTO_SEEN(RTPROTO_IDPR);
			    
			    doing_idpr = ($2 == T_OFF) ? FALSE : TRUE;
			    (void) strcpy(idpr_db_name, $3.ptr);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s idpr %s config = %s",
				      parse_where(), 
				      doing_idpr ? "on" : "off",
				      idpr_db_name));
 			}
		;

idpr_config_file
		: string
		| /* Empty */
			{
			    $$.ptr = task_mem_strdup((task *) 0, IDPR_CONFIG_DEFAULT);
			    $$.len = strlen($$.ptr);
			}
		;

@END:	PROTO_IDPR

/*  */

@BEGIN:	PROTO_EGP

egp_statement	: T_EGP
			{
			    PROTO_SEEN(RTPROTO_EGP);

			    egp_trace_options = trace_set_global(egp_trace_types,
								 (flag_t) 0);
			}
		onoff_option egp_group
			{
			    switch ($3) {
			    case T_ON:
				doing_egp = TRUE;

				if (!inet_autonomous_system) {
				    (void) sprintf(parse_error, "autonomous-system not specified");
				    PARSE_ERROR;
				}
				if (!egp_neighbors) {
				    (void) sprintf(parse_error, "no EGP neighbors specified");
				    PARSE_ERROR;
				}

#if	defined(PROTO_SNMP)
				egp_sort_neighbors((egp_neighbor *) 0);
#endif	/* defined(PROTO_SNMP) */
				break;

			    case T_OFF:
				doing_egp = FALSE;
			    }
			}
		;

egp_group	: /* Empty */
		| '{' egp_group_stmts '}'
		;

egp_group_stmts	: /* Empty */
		| egp_group_stmts egp_group_stmt L_EOS
		| egp_group_stmts error L_EOS
			{
			    yyerrok;
			}
		;

egp_group_stmt	: T_PREFERENCE preference
			{
			    egp_preference = $2;
			}
		| T_PREFERENCE2 preference
			{
			    egp_preference2 = $2;
			}
		| T_DEFAULTMETRIC metric
			{
			    if (parse_metric_check(RTPROTO_EGP, &$2)) {
				PARSE_ERROR;
			    }
			    egp_default_metric = $2.metric;
			}
		| T_PKTSIZE number
			{
			    if (parse_limit_check("packetsize",
						  (u_int) $2,
						  EGP_LIMIT_PKTSIZE)) {
				PARSE_ERROR;
			    }
			    egp_pktsize = $2;
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option egp_trace_options_none
			{
			    trace_store(egp_trace_options, $4, $3, $2, egp_trace_types);
			}
		| T_GROUP
			{
			    /* Clear group structure and set fill pointer */
			    bzero((caddr_t) &egp_group, sizeof(egp_group));
			    ngp = &egp_group;
			    ngp->ng_trace_options = trace_alloc(egp_trace_options);
			    /* First neighbor in group is head of group */
			    gr_ngp = (egp_neighbor *) 0;
			    parse_group_index++;
			}
		egp_group_options '{' egp_peer_stmts '}'
			{
			    if (gr_ngp->ng_gr_acquire > gr_ngp->ng_gr_number) {
				(void) sprintf(parse_error,
					       "maxacquire %u is greater than number of neighbors %u in group %d",
					       gr_ngp->ng_gr_acquire,
					       gr_ngp->ng_gr_number,
					       parse_group_index);
				PARSE_ERROR;
			    } else if (!gr_ngp->ng_gr_acquire) {
				gr_ngp->ng_gr_acquire = gr_ngp->ng_gr_number;
			    }

			}
		;

egp_peer_stmts	: /* Empty */
		| egp_peer_stmts egp_peer_stmt L_EOS
		| egp_peer_stmts error L_EOS
			{
			    yyerrok;
			}
		;

egp_peer_stmt	: T_NEIGHBOR
			{
			    ngp = egp_ngp_alloc(&egp_group);

			    if (!gr_ngp) {
				/* This neighbor is head of the group */

				gr_ngp = ngp;
			    } else {
				/* Not the head of the group, inherit the trace options */

				ngp->ng_trace_options = trace_alloc(gr_ngp->ng_trace_options);
			    }
			    parse_gwlist = &parse_gwp;
			}
		host_inet egp_peer_options
                        {
			    int add = TRUE;
			    egp_neighbor *ngp2;

			    /* Set neighbor's address */
			    ngp->ng_addr = $3;
			    ngp->ng_gw.gw_proto = RTPROTO_EGP;
			    ngp->ng_gw.gw_rtq.rtq_forw = ngp->ng_gw.gw_rtq.rtq_back = &ngp->ng_gw.gw_rtq;
			    (void) sprintf(ngp->ng_name, "%A",
					   ngp->ng_addr);

			    /* Set group pointer and count this neighbor */
			    ngp->ng_gr_head = gr_ngp;
			    ngp->ng_gr_index = parse_group_index;
			    gr_ngp->ng_gr_number++;

			    EGP_LIST(ngp2) {
				if (sockaddrcmp_in(ngp->ng_addr, ngp2->ng_addr)) {
				    if (BIT_TEST(ngp2->ng_flags, NGF_DELETE)) {
					if (!egp_neighbor_changed(ngp2, ngp)) {
					    BIT_RESET(ngp2->ng_flags, NGF_DELETE);
					    egp_ngp_free(ngp);
					    add = FALSE;
					    break;
					} else {
					    ngp->ng_flags = NGF_WAIT;
					}
				    } else {
					(void) sprintf(parse_error, "duplicate EGP neighbor at %A",
						       ngp->ng_addr);
					PARSE_ERROR;
				    }
				}
			    } EGP_LIST_END(ngp2) ;
			    
			    /* Add this neighbor to end of the list */
			    if (add) {
				INSQUE(ngp, egp_neighbor_head.ng_back);
				egp_neighbors++;
			    }
			}
		;

egp_group_options
		: /* Empty */
		| egp_group_options egp_group_option
		| egp_group_options egp_peer_option
		;

egp_group_option
		: T_PEERAS as
			{
			    BIT_SET(ngp->ng_options, NGO_PEERAS);
			    ngp->ng_peer_as = $2;
			}
		| T_LOCALAS as
			{
			    BIT_SET(ngp->ng_options, NGO_LOCALAS);
			    ngp->ng_local_as = $2;
#ifdef	PROTO_ASPATHS
			    aslocal_set($2, 0);
#endif	/* PROTO_ASPATHS */
			}
		| T_MAXUP L_NUMBER
			{
			    /* XXX - Limit check maxup value */
			    BIT_SET(ngp->ng_options, NGO_MAXACQUIRE);
			    ngp->ng_gr_acquire = $2;
			}
		| T_VERSION L_NUMBER
			{
			    if ( !(EGPVMASK & (1 << ($2 - 2))) ) {
				(void) sprintf(parse_error, "unsupported EGP version: %d",
					       $2);
				PARSE_ERROR;
			    }
			    BIT_SET(ngp->ng_options, NGO_VERSION);
			    ngp->ng_version = $2;
			}
		;

egp_peer_options
		: /* Empty */
		| egp_peer_options egp_peer_option
		;

egp_peer_option	: T_METRICOUT metric
			{
			    if (parse_metric_check(RTPROTO_EGP, &$2)) {
				PARSE_ERROR;
			    }
			    ngp->ng_metricout = $2.metric;
			    BIT_SET(ngp->ng_options, NGO_METRICOUT);
			}
		| T_NOGENDEFAULT
			{
			    BIT_SET(ngp->ng_options, NGO_NOGENDEFAULT);
			}
		| T_DEFAULTIN
			{
			    BIT_SET(ngp->ng_options, NGO_DEFAULTIN);
			}
		| T_DEFAULTOUT
			{
			    BIT_SET(ngp->ng_options, NGO_DEFAULTOUT);
			}
		| T_GATEWAY gateway_inet
			{
			    BIT_SET(ngp->ng_options, NGO_GATEWAY);
			    ngp->ng_gateway = sockdup($2->gw_addr);
			    gw_freelist(*parse_gwlist);
			    parse_gwlist = (gw_entry **) 0;
			    parse_gwp = (gw_entry *) 0;
			}
		| T_LCLADDR interface_local
			{
			    BIT_SET(ngp->ng_options, NGO_LCLADDR);
			    ngp->ng_lcladdr = $2;
			}
		| T_SOURCENET network_inet
			{
			    BIT_SET(ngp->ng_options, NGO_SADDR);
			    ngp->ng_saddr = $2;
			}
 		| T_P1 time
 			{
 			    if (parse_limit_check("P1",
						  (u_int) $2,
						  EGP_LIMIT_P1)) {
 				PARSE_ERROR;
 			    }
 			    BIT_SET(ngp->ng_options, NGO_P1);
 			    ngp->ng_P1 = $2;
 			}
 		| T_P2 time
 			{
 			    if (parse_limit_check("P2",
						  (u_int) $2,
						  EGP_LIMIT_P2)) {
 				PARSE_ERROR;
 			    }
 			    BIT_SET(ngp->ng_options, NGO_P2);
 			    ngp->ng_P2 = $2;
			}
		| T_TTL inet_ttl
			{
			    BIT_SET(ngp->ng_options, NGO_TTL);
			    ngp->ng_ttl = $2;
			}
		| T_PREFERENCE preference
			{
			    BIT_SET(ngp->ng_options, NGO_PREFERENCE);
			    ngp->ng_preference = $2;
			}
		| T_PREFERENCE2 preference
			{
			    BIT_SET(ngp->ng_options, NGO_PREFERENCE2);
			    ngp->ng_preference2 = $2;
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option egp_trace_options_none
			{
			    trace_store(ngp->ng_trace_options, $4, $3, $2, egp_trace_types);
			}
		;


egp_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| egp_trace_options
			{
			    $$ = $1;
			}
		| egp_trace_options T_EXCEPT egp_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

egp_trace_options
		: egp_trace_option
			{
			    $$ = $1;
			}
		| egp_trace_options egp_trace_option
			{
			    $$ = $1 | $2;
			}
		;

egp_trace_option
		: trace_option
    		| trace_option_detail trace_option_sendrecv egp_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		| T_DEBUG
			{
#ifdef	DEBUG
			    $$ = TR_EGP_DEBUG;
#else	/* DEBUG */
			    $$ = 0;
#endif	/* DEBUG */
			}
		;

egp_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_EGP_INDEX_PACKETS;
			}
		| T_UPDATE
			{
			    $$ = TR_EGP_INDEX_UPDATE;
			}
		| T_ACQUIRE
			{
			    $$ = TR_EGP_INDEX_ACQUIRE;
			}
		| T_HELLO
			{
			    $$ = TR_EGP_INDEX_HELLO;
			}
		;

egp_prop_init
		: T_EGP
			{
			    $$ = parse_proto = RTPROTO_EGP;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;


@END:	PROTO_EGP
    
/*  */

@BEGIN:	PROTO_BGP

bgp_statement	: T_BGP
			{
			    PROTO_SEEN(RTPROTO_BGP);

			    parse_gwlist = &parse_gwp;

			    bgp_default_trace_options = trace_set_global(bgp_trace_types,
									 (flag_t) 0);
			}
		onoff_option bgp_group
			{
			    switch ($3) {
			    case T_ON:
				doing_bgp = TRUE;

				if (!bgp_conf_check(parse_error)) {
				    PARSE_ERROR;
				}
				break;

			    case T_OFF:
				doing_bgp = FALSE;
			    }

			    parse_gwlist = (gw_entry **) 0;
			}
		;

bgp_group	: /* Empty */
		| '{' bgp_group_stmts '}'
		;

bgp_group_stmts	: /* Empty */
		| bgp_group_stmts bgp_group_stmt L_EOS
		| bgp_group_stmts error L_EOS
			{
			    yyerrok;
			}
		;

bgp_group_stmt	: T_PREFERENCE preference
			{
			    bgp_default_preference = $2;
			}
		| T_PREFERENCE2 preference
			{
			    bgp_default_preference2 = $2;
			}
		| T_DEFAULTMETRIC metric
			{
			    if (parse_metric_check(RTPROTO_BGP, &$2)) {
				PARSE_ERROR;
			    }
			    bgp_default_metric = $2.metric;
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option bgp_trace_options_none
			{
			    trace_store(bgp_default_trace_options, $4, $3, $2, bgp_trace_types);
			}
		| T_GROUP T_TYPE bgp_linktype T_PEERAS as bgp_proto_option
			{
			    /* Allocate a Group structure */
			    bgp = bgp_conf_group_alloc();

			    /* Set the type and AS */
			    bgp->bgpg_type = $3;
			    bgp->bgpg_peer_as = $5;

			    /* Point at this configuration information */
			    bcp = &bgp->bgpg_conf;

			    /* Inherit global trace flags */
			    bgp->bgpg_trace_options = trace_alloc(bgp_default_trace_options);

			    /* Set the protocol for routing peers */
			    bgp->bgpg_proto = $6;
			}
		bgp_peer_options
			{
			    /* Add this group */
			    bgp = bgp_conf_group_add(bgp, parse_error);
			    if (!bgp) {
				PARSE_ERROR;
			    }
			}
		'{' bgp_peer_stmts '}'
			{
			    /* Check group */
			    if (!bgp_conf_group_check(bgp, parse_error)) {
				PARSE_ERROR;
			    }
			}
		;

bgp_peer_options
		: /* Empty */
		| bgp_peer_options bgp_peer_option
		;

bgp_peer_stmts	: /* Empty */
		| bgp_peer_stmts bgp_peer_stmt L_EOS
		| bgp_peer_stmts error L_EOS
			{
				yyerrok;
			}
		;

bgp_peer_stmt	: T_NEIGHBOR
    			{
			    /* Allocate this peer */
			    bnp = bgp_conf_peer_alloc(bgp);

			    /* Point at this configuration information */
			    bcp = &bnp->bgp_conf;
			}
		host bgp_peer_options
			{
			    /* Set peer address */
			    bnp->bgp_addr = $3;

			    bnp = bgp_conf_peer_add(bgp, bnp, parse_error);
			    if (!bnp) {
				PARSE_ERROR;
			    }
			}
		| T_ALLOW
			{
			    parse_contig_masks = FALSE;
			}
			'{' bgp_allow_list '}'
			{
			    parse_contig_masks = TRUE;

			    bgp->bgpg_allow = adv_destmask_finish($4);
			}
		;

bgp_peer_option	: T_METRICOUT metric
			{
			    if (parse_metric_check(RTPROTO_BGP, &$2)) {
				PARSE_ERROR;
			    }
			    BIT_SET(bcp->bgpc_options, BGPO_METRIC_OUT);
			    bcp->bgpc_metric_out = $2.metric;
			}
		| T_LOCALAS as
			{
			    BIT_SET(bcp->bgpc_options, BGPO_LOCAL_AS);
			    bcp->bgpc_local_as = $2;
			    aslocal_set($2, 0);
			}
		| T_NOGENDEFAULT
			{
			    BIT_SET(bcp->bgpc_options, BGPO_NOGENDEFAULT);
			}
		| T_GATEWAY gateway_inet
			{
			    if (bcp->bgpc_gateway) {
				/* Free the old one */
				sockfree(bcp->bgpc_gateway);
			    }
			    BIT_SET(bcp->bgpc_options, BGPO_GATEWAY);
			    bcp->bgpc_gateway = sockdup($2->gw_addr);
			    gw_freelist(*parse_gwlist);
			    *parse_gwlist = parse_gwp = (gw_entry *) 0;
			}
		| T_PREFERENCE preference
			{
			    BIT_SET(bcp->bgpc_options, BGPO_PREFERENCE);
			    bcp->bgpc_preference = $2;
			}
		| T_PREFERENCE2 preference
			{
			    BIT_SET(bcp->bgpc_options, BGPO_PREFERENCE2);
			    bcp->bgpc_preference2 = $2;
			}
		| T_LCLADDR interface_local
			{
			    if (bcp->bgpc_lcladdr) {
				/* Free the old one */
				ifae_free(bcp->bgpc_lcladdr);
			    }
			    BIT_SET(bcp->bgpc_options, BGPO_LCLADDR);
			    bcp->bgpc_lcladdr = $2;
			}
		| T_HOLDTIME time
			{
			    if (parse_limit_check("hold time",
						  (u_int) $2,
						  BGP_LIMIT_HOLDTIME)) {
				PARSE_ERROR;
			    }
			    BIT_SET(bcp->bgpc_options, BGPO_HOLDTIME);
			    bcp->bgpc_holdtime_out = $2;
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option bgp_trace_options_none
			{
			    trace_store(bcp->bgpc_trace_options, $4, $3, $2, bgp_trace_types);
			}
		| T_VERSION L_NUMBER
			{
			    if (!BGP_KNOWN_VERSION($2)) {
				(void) sprintf(parse_error, "unsupported BGP version: %d",
					       $2);
				PARSE_ERROR;
			    }
			    BIT_SET(bcp->bgpc_options, BGPO_VERSION);
			    bcp->bgpc_conf_version = $2;
			}
		| T_PASSIVE
			{
			    BIT_SET(bcp->bgpc_options, BGPO_PASSIVE);
			}
		| T_KEEP T_ALL
			{
			    BIT_SET(bcp->bgpc_options, BGPO_KEEPALL);
			}
		| T_KEEP T_NONE
			{
			    BIT_SET(bcp->bgpc_options, BGPO_KEEPNONE);
			}
		| T_ANALRETENTIVE
			{
			    BIT_SET(bcp->bgpc_options, BGPO_ANALRETENTIVE);
			}
		| T_KEEPALIVESALWAYS
			{
			    BIT_SET(bcp->bgpc_options, BGPO_KEEPALIVESALWAYS);
			}
		| T_NOAGGRID
			{
			    BIT_SET(bcp->bgpc_options, BGPO_NOAGGRID);
			}
		| T_NOAUTHCHECK
			{
			    BIT_SET(bcp->bgpc_options, BGPO_NOAUTHCHECK);
			}
		| T_SETPREF preference
			{
			    BIT_SET(bcp->bgpc_options, BGPO_SETPREF);
			    bcp->bgpc_setpref = $2;
			}
		| T_SENDBUF bgp_kbufsize
			{
			    bcp->bgpc_send_bufsize = $2;
			}
		| T_RECVBUF bgp_kbufsize
			{
			    bcp->bgpc_recv_bufsize = $2;
			}
		| T_INDELAY time
			{
			    bcp->bgpc_rti_time = $2;
			}
		| T_OUTDELAY time
			{
			    bcp->bgpc_rto_time = $2;
			}
		| T_TTL inet_ttl
			{
			    BIT_SET(bcp->bgpc_options, BGPO_TTL);
			    bcp->bgpc_ttl = $2;
			}
		;

bgp_kbufsize	: number
			{
			    if (parse_limit_check("kernel buffer size",
						  (u_int) $1,
						  BGP_LIMIT_KBUF)) {
				PARSE_ERROR;
			    }
			    $$ = $1;
			}
		;

bgp_linktype	: T_INTERNAL
			{
			    $$ = BGPG_INTERNAL;
			}
		| T_EXTERNAL
			{
			    $$ = BGPG_EXTERNAL;
			}
		| T_IGP
			{
			    $$ = BGPG_INTERNAL_IGP;
			}
		| T_ROUTING
			{
			    $$ = BGPG_INTERNAL_RT;
			}
		| T_TEST
			{
			    $$ = BGPG_TEST;
			}
		;

bgp_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| bgp_trace_options
			{
			    $$ = $1;
			}
		| bgp_trace_options T_EXCEPT bgp_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

bgp_trace_options
		: bgp_trace_option
			{
			    $$ = $1;
			}
		| bgp_trace_options bgp_trace_option
			{
			    $$ = $1 | $2;
			}
		;

bgp_proto_option
		: /* Empty */
			{
			    $$ = (proto_t) 0;
			}
		| T_PROTO bgp_proto
			{
			    $$ = $2;
			}
		;

bgp_proto
		: T_NOP_PROTO
			{
			    assert(FALSE);
			}
@BEGIN:	PROTO_RIP
		| T_RIP
			{
			    $$ = RTPROTO_RIP;
			}
@END:	PROTO_RIP
@BEGIN:	PROTO_HELLO
		| T_HELLO
			{
			    $$ = RTPROTO_HELLO;
			}
@END:	PROTO_HELLO
@BEGIN:	PROTO_OSPF
		| T_OSPF
			{
			    $$ = RTPROTO_OSPF;
			}
@END:	PROTO_OSPF
@BEGIN:	PROTO_ISIS
		| T_ISIS
			{
			    $$ = RTPROTO_ISIS;
			}
@END:	PROTO_ISIS
@BEGIN:	PROTO_SLSP
		| T_SLSP
			{
			    $$ = RTPROTO_SLSP;
			}
@END:	PROTO_SLSP
		;

bgp_trace_option
		: trace_option
		| T_ASPATH
			{
			    $$ = TR_BGP_ASPATH;
			}
    		| trace_option_detail trace_option_sendrecv bgp_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		;

bgp_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_BGP_INDEX_PACKETS;
			}
		| T_OPEN
			{
			    $$ = TR_BGP_INDEX_OPEN;
			}
		| T_UPDATE
			{
			    $$ = TR_BGP_INDEX_UPDATE;
			}
		| T_KEEPALIVE
			{
			    $$ = TR_BGP_INDEX_KEEPALIVE;
			}
		;

bgp_prop_init
		: T_BGP
			{
			    $$ = parse_proto = RTPROTO_BGP;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;


bgp_allow_list	: /* Empty */
			{
			    $$ = bgp->bgpg_allow;
			}
		| bgp_allow_list bgp_allow L_EOS
			{
			    $$ = adv_alloc(ADVFT_DM, (proto_t) 0);
			    $$->adv_dm = $2;
			    $$ = adv_destmask_insert(parse_error, $1, $$);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| bgp_allow_list error L_EOS
			{
			    yyerrok;
			}
		;
		
/* Destination and mask pair used for control lists */
bgp_allow	: all_mask_inet
		| host_mask_inet
		| network_mask_inet
		;

@END:	PROTO_BGP

/*  */



@BEGIN:	PROTO_IDRP

idrp_statement : T_IDRP
        {
                idrp_trace_options = trace_set_global(idrp_trace_types, (flag_t) 0);
                parse_proto = RTPROTO_IDRP;
        	idrp_parse_group_index = 0;
#ifdef	IDRP_QOS
		idrp_init_def_rib();
#endif
        }
        onoff_option idrp_group 
        {
		PROTO_SEEN(RTPROTO_IDRP);
                if ($3 == T_OFF) {
                        doing_idrp = FALSE;
                        trace_tf(trace_global, TR_PARSE, 0,
				 ("parse: %s idrp off ;", parse_where()));
                } else {
			/* set flag and initialize local nodes idrpPeer struct */
                        doing_idrp = TRUE;
			idrp_local_peer_init();
			adv_psfunc_add(RTPROTO_IDRP,&idrp_adv_psfunc);	

			/* check to make sure RDI specified */
                        if (!rt_rdi.isoa_len) {
                                (void) sprintf(parse_error, "RDI not specified");
                                PARSE_ERROR;
                        }
                        /* %% */
			/* here we need to change for */
			/* idrp for IP */
		
                        if (!rt_net[0].isoa_len) {
                                (void) sprintf(parse_error, "NET not specified");
                                PARSE_ERROR;
                        }

                        if (!idrp_neighbors) {
                        	(void) sprintf(parse_error, "no IDRP neighbors specified");
                                PARSE_ERROR;
                        }
                        IDRP_LIST(idgp,idrp_peers) {
                                trace_tf(trace_global, TR_PARSE, 0,
				 	("parse:  %s, IDRP neighbor %s, addr %A",
					 parse_where(), idgp->name, 
					 sockbuild_iso((byte *)idgp->neighbor.isoa_genaddr,
					 idgp->neighbor.isoa_len)));
                	} IDRP_LIST_END;
        	}
        }
	;


idrp_group              : /* empty */
                        | '{' idrp_group_stmts '}'
                        ;

idrp_group_stmts        : /* empty */
                        | idrp_group_stmts idrp_group_stmt L_EOS
                        | idrp_group_stmts error L_EOS
                                {
                                        yyerrok;
                                }
                        ;

idrp_group_stmt : T_TRACEOPTIONS trace_file_option trace_control_option idrp_trace_options_none
                                {
				  trace_store(idrp_trace_options, $4, $3, $2, idrp_trace_types);
                                }

	| T_LOCALNODE
		{
		idgp = &idrp_this_node;
		idrp_local_config_def();	
		}
       '{' idrp_local_node_stmts '}'

        | T_GROUP
                {
		/* zero the group address functions */
 
                bzero((caddr_t) &idrp_grp, sizeof(idrp_group_parms));
                }
          idrp_group_options '{' idrp_peer_stmts '}'

        | T_OSILOCAL

          '{' idrp_local_routes '}'
        ;

idrp_peer_stmts         : /* empty */
                        | idrp_peer_stmts idrp_peer_stmt L_EOS
                        | idrp_peer_stmts error L_EOS
                                {
                                        yyerrok;
                                }
                        ;


idrp_local_node_stmts   : /* empty */
                        | idrp_local_node_stmts idrp_local_node_stmt L_EOS
                        | idrp_local_node_stmts error L_EOS
                                {
                                        yyerrok;
                                }
                        ;

idrp_local_node_stmt    : T_PROTOSUPPORT idrp_proto_supp
				{
				/* to get around $$ = $1 */
				}

			| idrp_sock_support 
				{
				/* to get around $$ = $1 */
				}

			| idrp_auth
				{
				/* to get around $$ = $1 */
				}

			| idrp_authcode
				{
				/* to get around $$ = $1 */
				}
				
			| T_CAPACITY idrp_capacity_value
				{
				idgp->Capacity = $2;
				}	

			| idrp_hold
				{
				/* to get around $$ = $1 */
				}

			| idrp_snpa_option
				{
				/* to get around $$ = $1 */
				}

			| T_EXPENSE idrp_expense_value
				{
				idgp->Expense = $2;
				}

			| T_MAXCPU L_NUMBER
				{
				idgp->cpu_overload_time = $2;
				}

			| idrp_max_pdu
				{
				/* to get around $$ = $1 */
				}
			
			| T_RIBCHECK L_NUMBER
				{
				idrp_this_node.ribcheck_timer = $2;
				}

			| T_MINADVRD L_NUMBER
				{
				idrp_this_node.min_advRD_time = $2;
				}

			| T_MULTIEXIT onoff_option
                                {
                                if ($2 == T_ON)
                                        idgp->multi_exit = TRUE;
                                else
                                        idgp->multi_exit = FALSE;
                                }

			| T_PRIORITY idrp_priority_value
				{
					idrp_this_node.Priority = $2;
				}

			| T_RDLRE idrp_rdlre_value
				{
				idrp_this_node.rdLRE = $2;
				}	

			| T_TRANSITDELAY idrp_transit_delay_value
				{
				idrp_this_node.rdTransitDelay = $2;
				}

			| idrp_rexmit 
				{
				/* to get around $$ = $1 */
				}
				

			| T_ROUTESERVER onoff_option
				{
				if ($2 == T_ON)
					idrp_this_node.route_server = TRUE;
				else
					idrp_this_node.route_server = FALSE;
				}

			| T_VERSION L_NUMBER
				{	
				if ($2 <= IDRP_MAX_VERSION )
					{
					idrp_this_node.version = $2;
					}
				} 
				
/* idrp peer variables that can be set for local peer */
	
			| idrp_close_time
				{
				/* to get around $$ = $1 */
				}
			| idrp_minadv
				{
				/* to get around $$ = $1 */
				}
			| idrp_max_outpdu
				{
				/* to get around $$ = $1 */
				}


/* idrp for ip variables */
			| T_ASRDI osi_address	
				{
				struct iso_net_addr *p_iso_net;

				ISO_NET_FROM_SOCKUN(p_iso_net, $1);
				rt_as_rdi.isoa_family = AF_ISO;
				rt_as_rdi.isoa_len = p_iso_net->isoa_len;
                                bcopy(p_iso_net->isoa_genaddr,&rt_as_rdi.isoa_genaddr, p_iso_net->isoa_len);
				}

/* special MERIT function switches */
		
			| idrp_closestay
				{
				/* to get around $$ = $1 */
				}

			| T_EXTINFO 
				{
				p_idrp_opts_old = idgp->p_ext_info;
				idrp_test_stopper(); 
				}
 			'{' idrp_ps_attribute_entries '}'
				{
				p_idrp_ps_atts->status |= IDRP_OPTS_EXT_INFO;
				if (p_idrp_ps_atts == NULL)
					{
					PARSE_ERROR;
			  		}
				/* set the rib_id to equal the options
				 */
 
				if (!idrp_rib_set(p_idrp_ps_atts))
					{
					PARSE_ERROR;
					}
				idgp->p_ext_info = p_idrp_ps_atts;
				if (opts_compare(p_idrp_opts_old,idgp->p_ext_info))
					{
					/* same option - but back old option into peer structure */
					idrp_free_opts(idgp->p_ext_info);
					idgp->p_ext_info = p_idrp_opts_old;
					}
				else
					{
					/* Not the same option - just free
					 */
					if (p_idrp_opts_old)
						{
						idrp_free_opts(p_idrp_opts_old);
						}
					} 
				idrp_test_stopper(); 
				p_idrp_ps_atts = (idrpRoute_options *) NULL;
				}

			| T_LOCALINFO
				{
				p_idrp_opts_old = idgp->p_local_info;  
				}		
 			'{' idrp_ps_attribute_entries '}'
				{
				idgp->p_local_info = p_idrp_ps_atts;
				if (p_idrp_ps_atts == NULL)
					{
					PARSE_ERROR;
			  		}
				if (!idrp_rib_set(p_idrp_ps_atts))
					{
					PARSE_ERROR;
					}
				if (opts_compare(p_idrp_opts_old,idgp->p_local_info))
					{
					/* same option - but back old option into peer structure */

					idrp_free_opts(idgp->p_local_info);
					idgp->p_local_info = p_idrp_opts_old;
					}
				else
					{
					/* Not the same option - just free
					 * - old option
					 */
					if (p_idrp_opts_old)
						{
						idrp_free_opts(p_idrp_opts_old);
						}
					}
				idrp_test_stopper(); 
				p_idrp_ps_atts = (idrpRoute_options *) NULL;
				}

                        | T_NET_AUTO_NLRI onoff_option
                                {
                                /* default is off, and each reconfig sets to off
                                 * - if it is deleted it will be cleared out
                                 *   as reconfigured route without re-init
                                 */

                                if ($2 == T_ON)
                                        {
                                        idrp_this_node.config_options |= IDRP_CNF_OPT_NET_AUTO_CONFIG;
                                        }
                                }

                        | T_EXPAND_NEXT_HOP onoff_option
                                {
                                /* default is off */

                                if ($2 = T_ON)
                                        {
                                        idrp_this_node.config_options |= IDRP_CNF_OPT_EXPAND_NEXT_HOP;
                                        }
				}

			| T_RIBSUPPORT 
				{
#ifdef	IDRP_QOS
				/* if reparsing, the old rib pointers have been copied to
				 * last_qos_rib, count has gone to last_rib_cnt
				 *
				 */
				idrp_init_def_rib();
				rib_cnt = 1;
#else	/* IDRP_QOS */ 
                        	(void) sprintf(parse_error, "no qos support and rib_support specified");
                                PARSE_ERROR;
#endif
				}
 				'{' idrp_rib_entries '}'
				{
#ifndef	IDRP_QOS
                        	(void) sprintf(parse_error, "no qos support and rib_support specified");
                                PARSE_ERROR;
			
#endif
				}

			;	


/* these clauses shared by local node and peers */

idrp_auth		: T_AUTHTYPE idrp_auth_type
				{
				idgp->AuthType = $2;
				}
			;	

idrp_authcode		: T_AUTHCODE L_HEXSTRING
				{
				idgp->AuthCodelen = $2.len;
                                bcopy($2.ptr,&idgp->AuthCode, $2.len);
				}
			;	

idrp_auth_type: T_TEST
		{
		$$ = IDRP_AUTH_CODE_TEST;
		}
		| T_CLEAR
		{
		$$ = IDRP_AUTH_CODE_CLEAR;
		}
		| T_CRYPT
		{
		$$ = IDRP_AUTH_CODE_CRYPT;
		}
		| T_SIMPLE
		{
		$$ = IDRP_AUTH_CODE_SIMPLE;
		}
	;

idrp_close_time		: T_CLOSEWAIT L_NUMBER 
				{
				idgp->close_wait = $2;
				}
			;

idrp_closestay		: T_CLOSESTAY L_NUMBER
				{
				idgp->closestay = $2;
				}
			;	

idrp_hold	: T_HOLDTIME idrp_hold_time_value
			{
			idgp->hold_time = $2;
			}

		;

idrp_listenopen		: T_LISTENOPEN onoff_option
				{
				idgp->listen_for_open = FALSE;
				if ($2 == T_ON)
					{
					idgp->listen_for_open = TRUE;
					}
				}
			;

idrp_max_output		: T_OUTPDUS L_NUMBER
				{
				if ($2 <= IDRP_MAX_OUTSTANDING_PDU) 
					{	
					idgp->rcv_credit = $2;
					}
				}
			;

idrp_max_pdu	: T_MAXPDUSIZE L_NUMBER
			{
			idgp->pdu_maxrcvsize = $2;
			} 
		;	

idrp_max_outpdu	: T_OUTPDUS L_NUMBER
                 	{
			if ($2 <= IDRP_MAX_OUTSTANDING_PDU)
                       		{
                                idgp->rcv_credit = $2;
                                }
			}
                        ;

idrp_minadv 	: T_MINADV idrp_minadv_value
	{
		idrp_this_node.min_adv_time = $2;
	}
	;

idrp_minadv_value	: L_NUMBER
	{
		if (parse_limit_check("IDRP min. adv",
			(u_int) $1,
			LIMIT_IDRP_MINADV_INTERVAL)) {
		PARSE_ERROR;
	    	}
		$$ = $1;
	}
	;



idrp_rexmit     : T_REXMIT L_NUMBER
			{
			idgp->rexmit_time = $2;
			}
			;

idrp_rib_entries : 	idrp_rib_entry L_EOS	
		 	| idrp_rib_entries idrp_rib_entry L_EOS
			| idrp_rib_entries error L_EOS
			{
			  PARSE_ERROR;
			}
			; 


idrp_rib_entry:		T_RIB idrp_rib_value  
				{
				p_rib = (idrp_qos_rib *) idrp_local_mem_fit(sizeof(idrp_qos_rib)); 
				p_rib->att.rib_id = p_rib->rib_id = rib_cnt;
				p_rib->parse_id = $2; 
				p_qos = &p_rib->att;
				}
 			'{' idrp_ps_rib_entries '}'
				{
#ifdef	IDRP_QOS
				/* done with the entries -
				 * - fill up the fake pdu for strings
				 *   and rest so local routes are easily created
				 */

				if (!idrp_check_qos_vals(p_rib))
					{	
					idrp_free_rib(p_rib);	
					p_rib = (idrp_qos_rib *) NULL;
					}
				else
					{
					/* rib values OK */
 
				 	idrp_qos_rib *p_rib_found = NULL;

					idrp_fill_qospdu(p_rib);

					/* check to see if new rib was equal to old rib
				 	*/

					p_rib_found = idrp_find_rib(p_rib); 

					if (p_rib_found)
						{
						/* routine that found
						 * copied old ribs into new spot
						 * just get rid of new data structure
						 */

						idrp_free_rib(p_rib);
						p_rib = p_rib_found;
						}
					else	
						{
						/* no rib found -
						 * just store in this spot
						 */
			
						qos_rib[rib_cnt] = p_rib;
						p_rib->status = IDRP_STATUS_RIB_NEW;
						}
					rib_cnt++;
					/* if neither the ISO or IP set for rib - set both as default
					 */

					if ((p_rib->nlri_supp[IDRP_NLRI_ISO] == 0) && p_rib->nlri_supp[IDRP_NLRI_IP] == 0)
						{
						p_rib->nlri_supp[IDRP_NLRI_ISO] = p_rib->nlri_supp[IDRP_NLRI_IP] = 1; 	
						}
					}
#else
				trace_tf (trace_global, TR_PARSE, 0, ("this idrp does not support qos - cannot use RIB stmt"));

	
#endif 	/* IDRP_QOS */ 
				}
			;	

/* idrp rib id number */

idrp_rib_value : L_NUMBER
			{
			$$ = $1;
			}
			;

idrp_ps_rib_entries	: idrp_ps_rib_entry L_EOS
			| idrp_ps_rib_entries idrp_ps_rib_entry L_EOS
			| idrp_ps_rib_entries error L_EOS
				{
				PARSE_ERROR
				}
			;  

idrp_ps_rib_entry	:  T_TRANSITDELAY idrp_transit_delay_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_TRANSIT_DELAY; 
				p_qos->delay.value = $2;
				}
			| T_RDLRE idrp_rdlre_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_RESIDUAL_ERROR; 
				p_qos->error.value = $2;
				}
			| T_EXPENSE idrp_expense_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_EXPENSE; 
				p_qos->expense.value = $2;
				}
			| T_PRIORITY idrp_priority_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_PRIORITY; 
				p_qos->priority.value = $2;
				}
			| T_SECURITY idrp_security_type idrp_security_value
				{
				p_qos->idrp_mask |=IDRP_ATTBT_SECURITY;
				p_qos->sec_type.value = $2;
				p_qos->sec_value.value = $3;
				}
			| T_KERNEL L_HEXSTRING 
				{
				p_rib->kern_len = $2.len;
				p_rib->p_qos_str = (byte *) idrp_local_mem_fit(p_rib->kern_len);
				bcopy($2.ptr,p_rib->p_qos_str,$2.len);
				}
			| T_ISO
				{
				p_rib->nlri_supp[IDRP_NLRI_ISO] = TRUE;
				} 
			| T_INET
				{	
				p_rib->nlri_supp[IDRP_NLRI_IP] = TRUE;
				}
			;	
/* this _was_ idrp_sock_options (i.e., plural form) */

idrp_sock_support: T_PROTOSOCK idrp_sock_option
		;


/* begin peer clauses */

idrp_peer_stmt          : T_NEIGHBOR
        {
		/* allocate a peer */

		idgp = (idrpPeer *) idrp_local_mem_fit(sizeof(idrpPeer));
		idrp_peer_preconfig_init(idgp);	
		trace_inherit(idgp->trace_options, idrp_trace_options);
	 
        }
        onoff_option osi_tagged_address host T_RDI osi_address idrp_options
        {
                idrpPeer *idgp2;
		struct iso_net_addr *p_iso_net;

                if ($3 == T_OFF) {
			idgp->idrp_flags = IDRPF_IDLED;
		} else {
			idgp->idrp_flags = IDRPF_TRY_CONNECT;
		}   		

		/* copy in group trace flags 
		 * in this sequence, the RDI is not copied 
		 */

		idgp->type = idrp_grp.type;

		/* copy rdi, NET, IP address for now */
		/* need to put interface someplace */

		ISO_NET_FROM_SOCKUN(p_iso_net, $4);
		bcopy(p_iso_net->isoa_genaddr, idgp->neighbor.isoa_genaddr,p_iso_net->isoa_len);
		idgp->neighbor.isoa_len = p_iso_net->isoa_len;
		idgp->neighbor.isoa_family = AF_ISO;

		/* make it an actual count on the wire */ 	

		p_iso_net = (struct iso_net_addr *) $7;
                idgp->rdi.isoa_len = p_iso_net->isoa_len - 2;
                bcopy(p_iso_net->isoa_genaddr, idgp->rdi.isoa_genaddr, idgp->rdi.isoa_len);

	        sprintf(idgp->name, "%A", 
			sockbuild_iso((byte *) idgp->neighbor.isoa_genaddr, 
						idgp->neighbor.isoa_len));
	
		/* is it my rdi - if so, internal neighbor */
		if (idgp->type == IDRP_PEER_INTERNAL) {
			if (isoaddrcmp(&idgp->rdi,&rt_rdi)) {
				/* rdi does not match */
				trace_tf(trace_global,TR_PARSE, 0, 
					("internal neighbor %s has internal neighbor but rdi is not ours", idgp->name));
				PARSE_ERROR;
			}					 
		}

                idgp->ip_neighbor = $5;
                idgp->gw.gw_proto = RTPROTO_IDRP;
		idgp->gw.gw_addr->in.sin_port = IDRP_PORT;

		/* if reparsing - check for this peer in
		 * existing list
		 */

		/* check for this peer being on the chain
		 * already
		 */

		idgp2 = idrp_find_peer(idgp);
		if (idgp2) {
			/* found a peer structure */
			if (idrp_reparsing) {
				/* re-use old structure, update
				 * with the new parameters  so far
				 * and free duplicate peer structure
				 */
 
				idrp_peer_update(idgp2,idgp);
				IDRP_MEM_FIT_FREE(idgp);
				idgp = idgp2;	
			} else {
				trace_tf(trace_global,TR_PARSE, 0, ("duplicate peer %s",idgp->name));
				PARSE_ERROR;
			}	
		} else {
			/* not a duplicate and not a reparsing re-used
			 * peer structure 
			 */

			idrp_link_peer(idgp);
		}
	}
        ;
			
idrp_options: /* empty */
	| idrp_options idrp_option
	| idrp_options error
		{
			yyerrok;
		}
	;

idrp_option: idrp_intf_option
	| idrp_proto_option
	| idrp_peer_option
	;

idrp_local_routes: /* empty */
        | idrp_local_routes idrp_local_route L_EOS  
        | idrp_local_routes error L_EOS  
		{
			yyerrok;
		}
        ;

idrp_local_route: osi_prefix osi_prefix 
	{
	/* create a local route with this NLRI information */

	struct iso_net_addr *p_iso_net1, *p_iso_net2;
	int _bits; 

	ISO_NET_FROM_SOCKUN(p_iso_net1, $1);
	ISO_NET_FROM_SOCKUN(p_iso_net2, $2);
	_bits = p_iso_net1->isoa_len * 8; 

	if (!idrp_local_rt(p_iso_net1->isoa_genaddr,
			   p_iso_net1->isoa_len,
			   _bits,
			   AF_ISO,
			   p_iso_net2->isoa_genaddr,
			   p_iso_net2->isoa_len,
			   IDRP_LOCAL_STATIC,
			   (idrpRoute_options *) NULL)) { 
	trace_tf(trace_global,
		TR_PARSE,
		0,
		("maximum number of local routes exceeded, no more added to routing table"));
	}
        }
	| osi_prefix osi_prefix idrp_atts_clause
	{
	/* create a local route with this NLRI information */

	struct iso_net_addr *p_iso_net1, *p_iso_net2;
	int _bits; 

	ISO_NET_FROM_SOCKUN(p_iso_net1, $1);
	ISO_NET_FROM_SOCKUN(p_iso_net2, $2);
	_bits = p_iso_net1->isoa_len * 8; 

	if (!idrp_local_rt(p_iso_net1->isoa_genaddr,
			   p_iso_net1->isoa_len,
			   _bits,
			   AF_ISO,
			   p_iso_net2->isoa_genaddr,
			   p_iso_net2->isoa_len,
			   IDRP_LOCAL_SPECIAL_STATIC,
			   p_idrp_ps_atts)) { 
	trace_tf(trace_global,
		TR_PARSE,
		0,
		("maximum number of local routes exceeded, no more added to routing table"));
	}

	/* Reset for the next use. */
	p_idrp_ps_atts = (idrpRoute_options *) NULL;
        }
	| osi_prefix osi_prefix T_EXTERIOR
	{
        /* create a local route with this NLRI information */

	struct iso_net_addr *p_iso_net1, *p_iso_net2;
        int _bits;

	ISO_NET_FROM_SOCKUN(p_iso_net1, $1);
	ISO_NET_FROM_SOCKUN(p_iso_net2, $2);
        _bits = p_iso_net1->isoa_len * 8;

        if (!idrp_local_rt(p_iso_net1->isoa_genaddr,
			   p_iso_net1->isoa_len,
			   _bits,
			   AF_ISO,
			   p_iso_net2->isoa_genaddr,
			   p_iso_net2->isoa_len,
			   IDRP_LOCAL_EXTERIOR_OSISTATIC,
			   (idrpRoute_options *) NULL)) {       
	trace_tf(trace_global,
		TR_PARSE,
		0,
		("maximum number of local routes exceeded, no more added to routing table"));
        }
	}
	;

/* idrp route parsing - for both export and local route parsing
 * - routines are used in both
 */


/* gated parsing routines */

/* interior routes that idrp will translate to IDRP options
 * -all implies any that idrp is ready to do
 */
   
idrp_interior_export	: T_ALL

@BEGIN:	PROTO_ISIS
			| T_ISIS
@END:	PROTO_ISIS
			| T_ALL
			; 	
	
@BEGIN:	PROTO_TODO
/* here where we put all the idrp attributes including the QOS */
idrp_attribute_list	: T_IDRP_ATTS
				{
				/* allocate the idrp options list */
				p_idrp_opts = (idrpRoute_options *) idrp_local_mem_fit(sizeof(idrpRoute_options));
				bzero(p_idrp_opts,sizeof(idrpRoute_options));
				p_idrp_opts->rib_id = IDRP_OPTIONS_EMPTY;
				p_qos = (idrp_distinguish_att *) idrp_local_mem_fit(sizeof(idrp_distinguish_att));
				bzero(p_qos, sizeof(idrp_distinguish_att));
				}
			     '{' idrp_attribute_entries '}'
				{
				/* here I have to adv_alloc something - code below  is a major guess  
				p_idrp_opts->rib_id = set_rib_id(p_qos);
			    	$$ = adv_alloc(ADVFT_DM, (proto_t)PROTO_IDRP);
				$$.attr = p_idrp_opts; */
				idrp_ps_flag = PS_NONE;    
				} 
				;

idrp_attribute_entries	: idrp_attribute_entry 
			| idrp_attribute_entries idrp_attribute_entry
			{
			    $$ = $1;
			    if (parse_adv_append($$, $2)) {
				PARSE_ERROR;
			    }
			}
			; 

idrp_attribute_entry	: idrp_route_options
			| idrp_pref_calc
			| idrp_QOS_options
@BEGIN:	PROTO_RDPATHS
			| idrp_dist_options
@END:	PROTO_RDPATHS
			;
 
idrp_route_options	: idrp_route_option L_EOS  
			| idrp_route_options idrp_route_option L_EOS
			;


idrp_route_option	: idrp_snpa_rt_option
			| T_ROUTESERVER T_ON
				{
				IDRP_STATUS_BIT_SET(p_idrp_opts,IDRP_OPTS_ROUTE_SERVER);
				}
			| T_ROUTESERVER T_OFF
				{
				IDRP_STATUS_BIT_CLEAR(p_idrp_opts,IDRP_OPTS_ROUTE_SERVER);
				}
			| T_ROUTESERVER  
				{
				IDRP_STATUS_BIT_SET(p_idrp_opts,IDRP_OPTS_ROUTE_SERVER);
				}
			| osi_tagged_address
				{
				struct iso_net_addr *p_iso_net;

				idrp_test_stopper();	
				ISO_NET_FROM_SOCKUN(p_iso_net, $1);
				/* if problems, could be due to removing +2 here */
				p_idrp_opts->next_hop[IDRP_NLRI_ISO].net.isoa_len = p_iso_net->isoa_len;
				p_idrp_opts->next_hop[IDRP_NLRI_ISO].net.isoa_family = AF_ISO;
				bcopy(p_iso_net->isoa_genaddr,&p_idrp_opts->next_hop[IDRP_NLRI_ISO].net.isoa_genaddr,p_iso_net->isoa_len);
				}
			| T_GATEWAY host
				{
				p_idrp_opts->next_hop[IDRP_NLRI_IP] = (struct iso_net_addr) $2;
				}
			| T_INTERFACE host 
				{
				p_idrp_opts->p_intf = $2;
				}
			| idrp_multi
				{
				/* go get rid of $$ = $1 problem */
				}
			; 


idrp_multi_exit_topeers	: idrp_multi_exit_topeer
			| idrp_multi_exit_topeers idrp_multi_exit_topeer 
			;

idrp_multi_exit_topeer	: L_NUMBER 
				{
				p_idrp_opts->multi_exit[p_idrp_opts->multi_exit_peers] = $1;	
				p_idrp_opts->multi_exit_peers++;
				if (p_idrp_opts->multi_exit_peers > (IDRP_MAX_PEERS - 1))
					{
					PARSE_ERROR;
					}	
				}
			;

idrp_pref_calc		: T_HOPCOUNT L_NUMBER L_EOS
				{
				p_idrp_opts->hopcnt_pref = $2;
				}
			;

@BEGIN:	PROTO_RDPATHS
idrp_dist_options	: idrp_dist_option
			| idrp_dist_options idrp_dist_option
			;

idrp_dist_option	: T_PROHIBIT_DIST idrp_dist_list L_EOS
                                {
                                if (p_idrp_opts->p_DIST_LIST_EXCL)
                                        {
                                        p_idrp_excl_rdi_tail->p_next = p_rdi_head;
                                        p_idrp_excl_rdi_tail = p_rdi_tail;
                                        }
                                else
                                        {
                                        p_idrp_opts->p_DIST_LIST_EXCL = p_idrp_excl_rdi_head = p_rdi_head;
                                        p_idrp_excl_rdi_tail = p_rdi_tail;
                                        }
                                p_rdi_head = p_rdi_tail = (idrp_canon_rdpath *) 0;
                                idrp_local_rdi_print(p_rdi_head);
                                }

                        | T_ALLOW_DIST idrp_dist_list L_EOS
                                {
                                if (p_idrp_opts->p_DIST_LIST_INCL)
                                        {
                                        p_idrp_incl_rdi_tail->p_next = p_rdi_head;
                                        p_idrp_incl_rdi_tail = p_rdi_tail;
                                        }
                                else
                                        {
                                        p_idrp_opts->p_DIST_LIST_INCL = p_idrp_incl_rdi_head = p_rdi_head;
                                        p_idrp_incl_rdi_tail = p_rdi_tail;
                                        }
                                p_rdi_head = p_rdi_tail = (idrp_canon_rdpath *) 0;
                                idrp_local_rdi_print(p_rdi_head);
                                }
			;


idrp_dist_list		: idrp_dist_list idrp_dist_rdi 
				{
					idrp_canon_rdpath *p_idrp_path_part;

					/* TODO also:  can move this pointer up
					 * get a new element of the list
					 * 	set the rdi
					 *		this sets  the info in $2 
					*/

					$$ = $1;
					$$->p_next = p_idrp_path_part;
				}
			| idrp_dist_rdi 
			;

/* TODO:  HUH? */

idrp_dist_rdi		: osi_prefix				
	{
		struct iso_net_addr *p_iso_net;

		ISO_NET_FROM_SOCKUN(p_iso_net, $1);
		if (!p_rdi_head) {
			p_rdi_head = p_rdi_tail = create_local_rd_path(p_iso_net->isoa_len,p_iso_net->isoa_genaddr);
		} else {
			p_rdi_tail->p_next = create_local_rd_path(p_iso_net->isoa_len,p_iso_net->isoa_genaddr);
			p_rdi_tail = p_rdi_tail->p_next;
			p_rdi_tail->p_next = (idrp_canon_rdpath *) 0;
		}
	} 	
	;	
@END:	PROTO_RDPATHS

 

idrp_QOS_options	: idrp_QOS_option L_EOS
			| idrp_QOS_options idrp_QOS_option L_EOS

idrp_QOS_option		: T_TRANSITDELAY idrp_transit_delay_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_TRANSIT_DELAY; 
				p_qos->delay.value = $1;
				}
			| T_RDLRE idrp_rdlre_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_RESIDUAL_ERROR; 
				p_qos->error.value = $2;
				}
			| T_EXPENSE idrp_expense_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_EXPENSE; 
				p_qos->expense.value = $1;
				}
			| T_PRIORITY idrp_priority_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_PRIORITY; 
				p_qos->priority.value = $2;
				}
			| T_CAPACITY idrp_capacity_value
				{
				p_qos->idrp_mask |= IDRP_ATTBT_CAPACITY; 
				p_idrp_opts->capacity.value = $2;
				p_idrp_opts->rib_id = 0;
				}
			| T_SECURITY idrp_security_type idrp_security_value
				{
				p_qos->idrp_mask |=IDRP_ATTBT_SECURITY;
				p_qos->sec_type.value = $2;
				p_qos->sec_value.value = $3;
				}	
			;
@END:	PROTO_TODO

idrp_transit_delay_value : L_NUMBER	
	{
		if (parse_limit_check("IDRP transit delay",
			(u_int) $1,
			LIMIT_IDRP_RD_TRANSIT_DELAY)) {
		PARSE_ERROR;
	    	}
		$$ = $1;
	}
	;

idrp_expense_value : L_NUMBER
	{
		if (parse_limit_check("IDRP expense",
			(u_int) $1,
			LIMIT_IDRP_EXPENSE)) {
		PARSE_ERROR;
	    	}
		$$ = $1;
	}
	;

idrp_rdlre_value : L_NUMBER
	{
		if (parse_limit_check("IDRP RDLRE",
			(u_int) $1,
			LIMIT_IDRP_RDLRE)) {
		PARSE_ERROR;
	    	}
		$$ = $1;
	}
	;


idrp_priority_value: L_NUMBER
	{
		if (parse_limit_check("IDRP priority",
			(u_int) $1,
			LIMIT_IDRP_PRIORITY)) {
		PARSE_ERROR;
	    	}
		$$ = $1;
	}
	;

idrp_capacity_value: L_NUMBER
	{
        	if (parse_limit_check("IDRP capacity",
        		(u_int) $1,
        		LIMIT_IDRP_CAPACITY)) {
        		PARSE_ERROR;
       		}
		$$ = $1;
       	}
	;

idrp_security_type: T_FAA_ADMIN
			{
			$$ = IDRP_QOS_SEC_TYPE_ADMIN;
			}
		   | T_FAA_GENCOM
			{
			$$ = IDRP_QOS_SEC_TYPE_GENCOM;
			}
		   | T_FAA_OPS
			{
			$$ = IDRP_QOS_SEC_TYPE_OPERATIONS;
			}
		   | T_FAA_SYSMGT
			{
			$$ = IDRP_QOS_SEC_TYPE_SYSMGT;
			}	
		;	

idrp_security_value: L_NUMBER
	{
        	if (parse_limit_check("IDRP security",
        		(u_int) $1,
        		LIMIT_IDRP_CAPACITY)) {
        		PARSE_ERROR;
       		}
		$$ = $1;
       	}
	;

idrp_multiexit_value: L_NUMBER
	{
        	if (parse_limit_check("IDRP multiexit",
        		(u_int) $1,
        		LIMIT_IDRP_MULTIEXIT)) {
        		PARSE_ERROR;
       		}
		$$ = $1;
       	}
	;

idrp_hold_time_value: L_NUMBER
	{
        	if (parse_limit_check("IDRP hold time",
        		(u_int) $1,
        		LIMIT_IDRP_HOLD_TIME)) {
        		PARSE_ERROR;
       		}
		$$ = $1;
	}
	;

idrp_intf_options	: idrp_intf_option
			| idrp_snpa_option
			| idrp_intf_option idrp_snpa_option
			| idrp_snpa_option idrp_intf_option
			;
		
idrp_snpa_option	: T_SNPA 
				{
				trace_tf(trace_global, TR_PARSE, 0, ("idrp snpa for local node"));
				p_snpa_list = &idgp->snpa;
				}
			  idrp_snpa 
				{
				/* Reset for next use. */
				p_snpa_list = (snpa_list *) NULL;
				}
			;

idrp_snpa_rt_option	: T_SNPA T_ISO
				{
				trace_tf(trace_global,TR_PARSE,0, ("OSI idrp snpa for local route"));
				p_snpa_list = &p_idrp_opts->next_hop[IDRP_NLRI_ISO].next_hop_snpas;
				} 
			  idrp_snpas
				{
				/* Reset for next use. */
				p_snpa_list = (snpa_list *) NULL;
				} 
			| T_SNPA T_IP
				{
				trace_tf(trace_global,TR_PARSE,0, ("IP idrp snpa for local route"));
				p_snpa_list = &p_idrp_opts->next_hop[IDRP_NLRI_IP].next_hop_snpas;
				}	
			  idrp_snpas
				{
				/* Reset for next use. */
				p_snpa_list = (snpa_list *) NULL;
				}	
			| T_SNPA
				{
				trace_tf(trace_global,TR_PARSE,0, ("OSI idrp snpa for local route"));
				p_snpa_list = &p_idrp_opts->next_hop[IDRP_NLRI_ISO].next_hop_snpas;
				}	
			  idrp_snpas
				{
				/* Reset for next use. */
				p_snpa_list = (snpa_list *) NULL;
				}	
			;



idrp_intf_option        :  T_INTERFACE host
                                {
                                        idgp->ip_intf_addr = $2;
					idgp->ip_intf_addr->in.sin_port = IDRP_PORT;
					trace_tf(trace_global,TR_PARSE, 0, ("ip interface address configed"));
                                }
			| T_INTERFACE osi_tagged_address
				{
					struct iso_net_addr *p_iso_net;

					ISO_NET_FROM_SOCKUN(p_iso_net, $1);
					idrp_set_iso_sockun((struct sockadd_un *)&idgp->iso_intf_addr,p_iso_net->isoa_len,p_iso_net->isoa_genaddr);	
					trace_tf(trace_global,TR_PARSE, 0, ("iso interface address configed"));
				}
			| T_INTERFACE host osi_tagged_address
				{
					struct iso_net_addr *p_iso_net;

					ISO_NET_FROM_SOCKUN(p_iso_net, $3);
	                                idgp->ip_intf_addr = $2;
					idgp->ip_intf_addr->in.sin_port = IDRP_PORT;
					trace_tf(trace_global,TR_PARSE, 0, ("ip interface address configed"));
					idrp_set_iso_sockun((struct sockadd_un *)&idgp->iso_intf_addr,p_iso_net->isoa_len,p_iso_net->isoa_genaddr);	
					trace_tf(trace_global,TR_PARSE, 0, ("iso interface address configed"));
				}
			| T_INTERFACE osi_tagged_address host
				{
					struct iso_net_addr *p_iso_net;

					ISO_NET_FROM_SOCKUN(p_iso_net, $3);
	                                idgp->ip_intf_addr = $3;
					idgp->ip_intf_addr->in.sin_port = IDRP_PORT;
					trace_tf(trace_global,TR_PARSE, 0, ("ip interface address configed"));
					idrp_set_iso_sockun((struct sockadd_un *)&idgp->iso_intf_addr,p_iso_net->isoa_len,p_iso_net->isoa_genaddr);	
					trace_tf(trace_global,TR_PARSE, 0, ("iso interface address configed"));
				}
                        ;


idrp_snpas		: idrp_snpa
			| idrp_snpas idrp_snpa 
			;

idrp_snpa		: L_HEXSTRING 
				{
				create_local_snpa_entry(&p_snpa_list,$1.len,$1.ptr);
				}
			;

idrp_group_options      : idrp_group_option
                        | idrp_group_options idrp_group_option
                        ;

idrp_group_option       : T_RDI osi_rdi
                                {
					struct iso_net_addr *p_iso_net;

					ISO_NET_FROM_SOCKUN(p_iso_net, $2);
                                        bcopy(p_iso_net->isoa_genaddr,idrp_grp.rdi.isoa_genaddr, p_iso_net->isoa_len);
                                        idrp_grp.rdi.isoa_len = p_iso_net->isoa_len;
                                }
                        | T_INTERNAL
                                {
                                        idrp_grp.type = IDRP_PEER_INTERNAL;
                                }
                        | T_EXTERNAL
                                {
                                        idrp_grp.type = IDRP_PEER_EXTERNAL;
                                }
                        ;

/*
idrp_proto_options	: idrp_proto_option
			| idrp_proto_options idrp_proto_option
			;
*/

idrp_proto_option :  T_PROTOSUPPORT idrp_proto_supp
	{
	/* to get around $$ = $1; */
	}
	| T_SOCKSUPPORT idrp_sock_support 
	{
	/* to get around $$ = $1; */
	}
	| idrp_sock_support
	{
	/* to get around $$ = $1; */
	}
	;

/*
idrp_sock_options	: idrp_sock_options idrp_sock_option
			| idrp_sock_option
			;
*/

idrp_sock_option	:  T_IP
				{
				idgp->proto_sock = IDRP_PDU_PROTO_IP_RAW;
				} 
			| T_UDP
				{
				idgp->proto_sock = IDRP_PDU_PROTO_UDP;
				}

			|  T_ISO		 	 
				{
				/*  raw clnp socket */
				idgp->proto_sock = IDRP_PDU_PROTO_CLNP;
				}
			| T_IDRP
				{
				idgp->proto_sock = IDRP_PDU_PROTO_IDRP;
				}
			;

idrp_proto_supp		: T_ISO 
				{
				idrp_this_node.nlri_supp[IDRP_NLRI_ISO] = TRUE;
				}
			| T_IP
				{
				idrp_this_node.nlri_supp[IDRP_NLRI_IP] = TRUE;
				}

			| T_IP T_ISO
				{
				idrp_this_node.nlri_supp[IDRP_NLRI_IP] = TRUE;
				idrp_this_node.nlri_supp[IDRP_NLRI_ISO] = TRUE;
				}

			| T_ISO T_IP
				{
				idrp_this_node.nlri_supp[IDRP_NLRI_IP] = TRUE;
				idrp_this_node.nlri_supp[IDRP_NLRI_ISO] = TRUE;
				}
			;

idrp_peer_options       : idrp_peer_options idrp_peer_option
                        | idrp_peer_option
                        ;

idrp_peer_option        : T_TRACEOPTIONS trace_file_option trace_control_option idrp_trace_options_none
				{
                                trace_store(idgp->trace_options, $4, $3, $2, idrp_trace_types);
                       		}
			| idrp_auth
				{
				/* to get around $$ = $1 */
				}
			| idrp_authcode
				{
				/* to get around $$ = $1 */
				}
			| idrp_close_time
				{
				/* to get around $$ = $1 */
				}
			| idrp_max_outpdu
				{
				/* to get around $$ = $1 */
				}
			| idrp_hold
				{
				/* to get around $$ = $1 */
				}
			| idrp_minadv
				{
				/* to get around $$ = $1 */
				}
			| idrp_listenopen
				{
				/* to get around $$ = $1 */
				}
			| idrp_rexmit
				{
				/* to get around $$ = $1 */
				}
			| idrp_closestay
				{
				/* to get around $$ = $1 */
				}

			| T_MULTIEXIT L_NUMBER
				{
				/* set the default multi_exit value for this peer
				*/

				/*@@@ if ($2 >= 0 && $2 <= IDRP_MAX_MULTI_EXIT_VALUE) 
				*/
					{
					idgp->multi_exit = $2;
					}
				}
			| T_RIB_REFRESH onoff_option
				{
				if ($2 == T_ON)
					{
					idgp->refresh_flags = SEND_RIB_REFRESH_ON_HUP;
					}
				else
					{
					idgp->refresh_flags = SEND_UPDATE_ON_HUP;
					}
				}
			| T_RIB_REFRESH
				{
				idgp->refresh_flags = SEND_RIB_REFRESH_ON_HUP;
				}

			| T_RIBSUPPORT T_ALL
				{
#ifdef	IDRP_QOS
				idrp_supp_all_ribs(idgp);
#endif	/* IDRP_QOS */
				}

			| T_RIBSUPPORT idrp_peer_rib_ids
				{
				/* Add in support for the default rib
				 */

				idgp->nrib_supp++;

				}
			;

idrp_peer_rib_ids	: idrp_peer_rib_id 		
                        | idrp_peer_rib_ids idrp_peer_rib_id
			;

idrp_peer_rib_id	: L_NUMBER
				{
#ifdef	IDRP_QOS
				int id;
				id = find_rib_parseid($1);
				if (id)
					{
					/* set the value to parse id
					 */

					idgp->rib_supp[id] = $1;
					idgp->nrib_supp++;
					}   	    
#endif
				}
			;

/*
 * this formerly had 'osi_nsap' as an option, which caused 14 reduce/reduce
 * conflicts between the osi_nsap and host productions  -- sjr
 */
osi_tagged_address    : osi_address_name osi_nsap
	{
		idrp_test_stopper();
		$$ = $2;
	}
        ;

osi_address     : addr_iso
		| osi_hex
                ;

osi_nsap        : addr_iso
		| osi_hex
                ;

osi_rdi         : addr_iso
		| osi_hex
		;

osi_rdi_or_any  : osi_rdi
		| T_ANY
		{
			$$ = iso_addr_default;
		}
                ;

osi_prefix      : addr_iso
		| osi_hex
                ;


osi_address_name: T_NET
		| T_NSAP
                ;

idrp_prop_init : T_IDRP
			{
			    $$ = parse_proto = RTPROTO_IDRP;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

idrp_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| idrp_trace_options
			{
			    $$ = $1;
			}
		| idrp_trace_options T_EXCEPT idrp_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

idrp_trace_options
		: idrp_trace_option
			{
			    $$ = $1;
			}
		| idrp_trace_options idrp_trace_option
			{
			    $$ = $1 | $2;
			}
		;



idrp_trace_option : trace_option
		{
			$$ = $1;
		}
		| T_PHASE1	
		{
			$$ = TR_PHASE1;
		}
		| T_MINADVTIMER	
		{
			$$ = TR_MINADV;
		}
		| T_PHASE3	
		{
			$$ = TR_PHASE3;
		}
		| T_ROUTE_TIES	
		{
			$$ = TR_ROUTE_TIES;
		}
		| T_IDRP_DEBUG	
		{
			$$ = TR_IDRP_DEBUG;
		}
		| T_IDRP
		{
			/* use all IDRP traceoptions */
			$$ =  TR_PHASE1|TR_MINADV|TR_PHASE3|TR_ROUTE_TIES|TR_IDRP_DEBUG;
		}
		;

@BEGIN:	PROTO_TODO
idrp_trace_option_index
		: T_PACKETS 
			{
			    $$ = IDRP_TRACE_PDUS;
			}/* TODO
		| T_OPEN
			{
			    $$ = TR_BGP_INDEX_OPEN;
			}
		| T_UPDATE
			{
			    $$ = TR_BGP_INDEX_UPDATE;
			}
		| T_KEEPALIVE
			{
			    $$ = TR_BGP_INDEX_KEEPALIVE;
			}
		| T_PHASE1
			{
			    $$ = TR_PHASE1;
			}*/
		;

@END:	PROTO_TODO
@END:	PROTO_IDRP



/*  */

@BEGIN:	PROTO_ICMP

icmp_statement	: T_ICMP
			{
			    icmp_trace_options = trace_set_global(icmp_trace_types,
								  (flag_t) 0);
			}
		'{' icmp_group_stmts '}'
		;

icmp_group_stmts
		: /* Empty */
		| icmp_group_stmts icmp_group_stmt L_EOS
		| icmp_group_stmts error L_EOS
			{
			    yyerrok;
			}
		;


icmp_group_stmt
		: T_TRACEOPTIONS trace_file_option trace_control_option icmp_trace_options_none
			{
			    trace_store(icmp_trace_options, $4, $3, $2, icmp_trace_types);
			}
		;

icmp_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| icmp_trace_options
			{
			    $$ = $1;
			}
		| icmp_trace_options T_EXCEPT icmp_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

icmp_trace_options
		: icmp_trace_option
			{
			    $$ = $1;
			}
		| icmp_trace_options icmp_trace_option
			{
			    $$ = $1 | $2;
			}
		;

icmp_trace_option
		: trace_option
    		| trace_option_detail trace_option_sendrecv icmp_trace_option_index
			{
			    $$ = trace_parse_packet($1, $2, $3);
			}
		;

icmp_trace_option_index
		: T_PACKETS
			{
			    $$ = TR_ICMP_INDEX_PACKETS;
			}
		| T_REDIRECT
			{
			    $$ = TR_ICMP_INDEX_REDIRECT;
			}
		| T_ROUTERDISCOVERY
			{
			    $$ = TR_ICMP_INDEX_ROUTER;
			}
		| T_INFO
			{
			    $$ = TR_ICMP_INDEX_INFO;
			}
		| T_ERROR
			{
			    $$ = TR_ICMP_INDEX_ERROR;
			}
    		;


@END:	PROTO_ICMP

/*  */

redirect_statement
		: T_REDIRECT
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    PROTO_SEEN(RTPROTO_REDIRECT);

			    parse_gwlist = &redirect_gw_list;

			    redirect_trace_options = trace_set_global(redirect_trace_types,
								      (flag_t) 0);
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
		onoff_option redirect_group
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    switch ($3) {
			    case T_ON:
				/* Enabled by default */
				break;

			    case T_OFF:
				redirect_disable(RTPROTO_REDIRECT);
				break;
			    }
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
		;

redirect_group	: /* Empty */
		| '{' redirect_group_stmts '}'
		;

redirect_group_stmts
		: /* Empty */
		| redirect_group_stmts redirect_group_stmt L_EOS
		| redirect_group_stmts error L_EOS
			{
			    yyerrok;
			}
		;

redirect_group_stmt	: T_PREFERENCE preference
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    redirect_preference = $2;
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
		| T_INTERFACE interface_all_list redirect_interface_options
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    config_list *list = config_list_alloc($3, 0);

			    parse_adv_propagate_config($2, list, RTPROTO_REDIRECT);

			    if (parse_adv_append(&redirect_int_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
		| T_TRUSTEDGATEWAYS gateway_list
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    redirect_n_trusted += parse_gw_flag($2, RTPROTO_REDIRECT, GWF_TRUSTED);
			    if (!redirect_n_trusted) {
				PARSE_ERROR;
			    }
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
		| T_TRACEOPTIONS trace_file_option trace_control_option redirect_trace_options_none
			{
			    trace_store(redirect_trace_options, $4, $3, $2, redirect_trace_types);
			}
		;

redirect_interface_options
		: redirect_interface_option
		| redirect_interface_options redirect_interface_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

redirect_interface_option
		: T_REDIRECTS
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    $$ = config_alloc(REDIRECT_CONFIG_IN, (void_t) TRUE);
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
		| T_NOREDIRECTS
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    $$ = config_alloc(REDIRECT_CONFIG_IN, (void_t) FALSE);
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
		;

redirect_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| redirect_trace_options
			{
			    $$ = $1;
			}
		| redirect_trace_options T_EXCEPT redirect_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

redirect_trace_options
		: redirect_trace_option
			{
			    $$ = $1;
			}
		| redirect_trace_options redirect_trace_option
			{
			    $$ = $1 | $2;
			}
		;

redirect_trace_option
		: trace_option
		;

/*  */

@BEGIN:	PROTO_DVMRP

dvmrp_statement : T_DVMRP
			{
			    PROTO_SEEN(RTPROTO_DVMRP);

			    dvmrp_trace_options = trace_set_global(dvmrp_trace_types,
								   (flag_t) 0);
                        }
		onoff_option dvmrp_group L_EOS
			{

			    switch ($3) {
			    case T_OFF:
				doing_dvmrp = FALSE;
				break;
				
			    case T_ON:
				/* XXX - Check validity of configuration */
				doing_dvmrp = TRUE;
			    }
			}
		;
    
dvmrp_group	: /* Empty */
                | '{' dvmrp_group_stmts '}'
		;

dvmrp_group_stmts	: /* Empty */
		| dvmrp_group_stmts dvmrp_group_stmt L_EOS
		| dvmrp_group_stmts error L_EOS
			{
				yyerrok;
			}
		;

dvmrp_group_stmt
		: T_INTERFACE interface_all_list dvmrp_interface_statements L_EOS
			{
			    config_list *list = config_list_alloc($3, 0);

			    parse_adv_propagate_config($2, list, (proto_t) 0);

			    if (parse_adv_append(&dvmrp_policy, $2)) {
				PARSE_ERROR;
			    }

			    config_list_free(list);
			}
		| T_TUNNEL host dvmrp_tunnel_options L_EOS
			{
			    if (dvmrp_parse_tunnel($2, $3, parse_error)) {
				PARSE_ERROR;
			    }

			    /* Sorta gross */
			    config_list_free(config_list_alloc($3, 0));
			}
		;

dvmrp_interface_statements
		: T_IGNORE
			{
			    $$ = config_alloc(DVMRP_CONFIG_IGNORE, (void_t) TRUE);
			}
		| dvmrp_interface_options
			{
			    $$ = $1;
			}
		;

dvmrp_tunnel_options
		: dvmrp_interface_option 
		| dvmrp_tunnel_option 
		| dvmrp_tunnel_options dvmrp_interface_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| dvmrp_tunnel_options dvmrp_tunnel_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

dvmrp_tunnel_option
		: T_LCLADDR interface_local
			{
			    $$ = config_alloc(DVMRP_CONFIG_LCLADDR, (void_t) $2);
			}
		;

dvmrp_interface_options
		: dvmrp_interface_option
		| dvmrp_interface_options dvmrp_interface_option
			{
			    $$ = config_append($1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		;

dvmrp_interface_option
		: T_METRIC metric
			{
			    if (parse_metric_check(RTPROTO_DVMRP, &$2)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(DVMRP_CONFIG_METRIC, (void_t) $2.metric);
			}
		| T_THRESHOLD number
			{
			    if (parse_limit_check("dvmrp threshold",
						  (u_int) $2,
						  DVMRP_LIMIT_THRESHOLD)) {
				PARSE_ERROR;
			    }
			    $$ = config_alloc(DVMRP_CONFIG_THRESHOLD, (void_t) $2);
			}
		;


@END:	PROTO_DVMRP


/*  */    

@BEGIN:	PROTO_SNMP

snmp_statement	: T_SNMP
		        {
			    PROTO_SEEN(RTPROTO_SNMP);

			    snmp_trace_options = trace_set_global(snmp_trace_types,
								  (flag_t) 0);
			}
		onoff_option snmp_group
			{
			    /* XXX - trace options */

			    switch ($3) {
			    case T_ON:
				doing_snmp = TRUE;
				break;

			    case T_OFF:
				doing_snmp = FALSE;
				break;
			    }
			}
		;

snmp_group	: /* Empty */
		| '{' snmp_group_stmts '}'
		;

snmp_group_stmts
		: /* Empty */
		| snmp_group_stmts snmp_group_stmt L_EOS
		| snmp_group_stmts error L_EOS
			{
				yyerrok;
			}
		;

snmp_group_stmt
    		: T_PREFERENCE preference
			{
			    snmp_preference = $2;
			}
    		| T_TRACEOPTIONS trace_file_option trace_control_option snmp_trace_options_none
			{
			    trace_store(snmp_trace_options, $4, $3, $2, snmp_trace_types);
			}
		| T_PORT port
			{
			    snmp_port = $2;
			}
		| T_DEBUG
			{
			    snmp_debug = TRUE;
			}
		;

snmp_trace_options_none
		: T_NONE
			{
			    $$ = (flag_t) 0;
			}
		| snmp_trace_options
			{
			    $$ = $1;
			}
		| snmp_trace_options T_EXCEPT snmp_trace_options
			{
			    $$ = $1 & ~$3;
			}
    		;

snmp_trace_options
		: snmp_trace_option
			{
			    $$ = $1;
			}
		| snmp_trace_options snmp_trace_option
			{
			    $$ = $1 | $2;
			}
		;

snmp_trace_option
		: trace_option
		| T_RECEIVE
			{
			    $$ = TR_SNMP_RECV;
			}
		| T_REGISTER
			{
			    $$ = TR_SNMP_REGISTER;
			}
		| T_RESOLVE
			{
			    $$ = TR_SNMP_RESOLVE;
			}
		| T_TRAP
			{
			    $$ = TR_SNMP_TRAP;
			}
		;

@END:	PROTO_SNMP
@BEGIN:	NOT PROTO_SNMP
snmp_statement	: T_SNMP T_OFF
			{
			}
		;
@END:	NOT PROTO_SNMP

/*  */

route_order	: /* Empty */
			{
			    if (parse_new_state(PS_ROUTE)) {
				PARSE_ERROR;
			    }
			}
		;

route_statement : T_STATIC
			{
			    /* Need to set this for static routes, not used for interface routes */
			    parse_proto = RTPROTO_STATIC;
			    parse_gwlist = &rt_gw_list;
			    rt_open(rt_task);
			}
		'{' route_stmts '}'
			{
			    rt_close(rt_task, (gw_entry *) 0, 0, NULL);
			}
		;

route_stmts	: route_stmt L_EOS
		| route_stmts route_stmt L_EOS
		| error L_EOS
			{
				yyerrok;
			}
		;

route_stmt	: route_dest T_INTERFACE interface_all preference_option rts_options
			{
			    /* Route to an interface */

			    if (rt_parse_route($1.dm_dest,
					       $1.dm_mask,
					       (adv_entry *) 0,
					       $3,
					       PARSE_METRIC_ISSET(&$4) ? (pref_t) $4.metric : RTPREF_STATIC,
					       $5,
					       parse_error)) {
				PARSE_ERROR;
			    }

			    sockfree($1.dm_dest);
			}
@BEGIN:	PROTO_ASPATHS
		| route_dest T_GATEWAY gateway_list interface_list_option route_aspath preference_option rts_options
			{
			    /* Route to a gateway */

			    if (rt_parse_route_aspath($1.dm_dest,
						      $1.dm_mask,
						      $3,
						      $4,
						      PARSE_METRIC_ISSET(&$6) ? (pref_t) $6.metric : RTPREF_STATIC,
						      $7 | RTS_GATEWAY,
						      $5,
						      parse_error)) {
				PARSE_ERROR;
			    }

			    sockfree($1.dm_dest);
			}
@END:	PROTO_ASPATHS
@BEGIN:	NOT PROTO_ASPATHS
		| route_dest T_GATEWAY gateway_list interface_list_option preference_option rts_options
			{
			    /* Route to a gateway */

			    if (rt_parse_route($1.dm_dest,
					       $1.dm_mask,
					       $3,
					       $4,
					       PARSE_METRIC_ISSET(&$5) ? (pref_t) $5.metric : RTPREF_STATIC,
					       $6 | RTS_GATEWAY,
					       parse_error)) {
				PARSE_ERROR;
			    }

			    sockfree($1.dm_dest);
			}
@END:	NOT PROTO_ASPATHS
		;

@BEGIN:	PROTO_ASPATHS
route_aspath	: /* Empty */
			{
			    $$ = (as_path *) 0;
			}
		| T_AS as
			{
			    $$ = aspath_create($2);
			}
		;
@END:	PROTO_ASPATHS

route_dest	: T_NOP_DM
			{
			    assert(FALSE);
			}
@BEGIN:	PROTO_INET
		| host_mask_inet
    		| network_mask_inet
    		| T_DEFAULT
			{
			    $$.dm_dest = sockdup(inet_addr_default);
			    $$.dm_mask = inet_mask_default;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
		| host_mask_iso
    		| network_mask_iso
		| T_ISO T_DEFAULT
			{
			    $$.dm_dest = sockdup(iso_addr_default);
			    $$.dm_mask = iso_mask_default;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
@END:	PROTO_ISO
    		;

rts_options	: /* Empty */
			{
			    $$ = 0;
			}
		| rts_options rts_option
			{
			    $$ = $1 | $2;
			}
		;

rts_option	: T_RETAIN
			{
			    $$ = RTS_RETAIN;
			}
		| T_REJECT
			{
			    $$ = RTS_REJECT;
			}
		| T_BLACKHOLE
			{
			    $$ = RTS_BLACKHOLE;
			}
		| T_NOINSTALL
			{
			    $$ = RTS_NOTINSTALL;
			}
		| T_EXTERIOR
			{
			    $$ = RTS_EXTERIOR;
			}
		;

/*  */

control_order	: /* Empty */
			{
			    if (parse_new_state(PS_CONTROL)) {
				PARSE_ERROR;
			    }
			}
		;
		
control_statement
		: T_NOP1
			{
			    assert(FALSE);
			}
@BEGIN:	AUTONOMOUS_SYSTEM
		| T_IMPORT T_PROTO control_exterior 
			{
			    parse_proto = $3.proto;
			} 
		  T_AS as import_option_inet L_EOS
			{
#if	defined(PROTO_EGP) || defined(PROTO_BGP)
			    adv_entry *adv;
			    pmet_t *pp = &$7.metric;

			    /*
			     *	Tack the list of destinations onto the end of the list
			     *	for neighbors with the specified AS.
			     */
			    adv = adv_alloc(ADVFT_AS, $3.proto);
			    adv->adv_as = $6;
			    adv->adv_list = $7.adv;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    if (!parse_adv_as($3.import_list, adv)) {
				PARSE_ERROR;
			    }
#endif	/* defined(PROTO_EGP) || defined(PROTO_BGP) */
			}
@END:	AUTONOMOUS_SYSTEM
@BEGIN:	PROTO_BGP
		| T_IMPORT T_PROTO T_BGP 
			{
			    parse_proto = RTPROTO_BGP;
			} 
		  aspath_match import_option_inet L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$6.metric;

			    /*
			     *	Tack the list of destinations onto the end of the list
			     *	for neighbors with the specified AS.
			     */
			    adv = adv_alloc(ADVFT_ASPATH, RTPROTO_BGP);
			    adv->adv_aspath = $5;
			    adv->adv_list = $6.adv;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    if (parse_adv_append(&bgp_import_aspath_list, adv)) {
				PARSE_ERROR;
			    }
			}
@END:	PROTO_BGP
@BEGIN:	PROTO_IDRP
	| T_IMPORT T_PROTO control_idrp 
	{
	    	parse_proto = RTPROTO_IDRP;
		idrp_test_stopper();
	} 
	  T_RDI osi_rdi_or_any idrp_import_optional_info idrp_import_option L_EOS
	{
              	adv_entry *adv, *adv_end;
              	pmet_t *pp = &$8.metric;
		struct iso_net_addr *p_iso_net;
		idrpRoute_info *p_info;

               	/*
               	 *  Tack the list of destinations onto the end of the list
               	 *  for neighbors with the specified RDI.
               	 */
		ISO_NET_FROM_SOCKUN(p_iso_net, $6);
               	adv = adv_alloc(ADVFT_RDI, RTPROTO_IDRP);
		adv->adv_rdi = (struct iso_net_addr *) idrp_local_mem_fit(sizeof(struct iso_net_addr));
               	bzero((caddr_t) adv->adv_rdi->isoa_genaddr, ISO_MAXADDRLEN);
                bcopy(p_iso_net->isoa_genaddr, adv->adv_rdi->isoa_genaddr, p_iso_net->isoa_len);
		adv->adv_rdi->isoa_len = p_iso_net->isoa_len;
		adv->adv_rdi->isoa_family = AF_ISO;

		if ($8.adv) {
/* this would work for the older format...
			parse_adv_propagate_idrp_info($8.adv, pp, p_idrp_ps_atts);
*/
			p_info = (idrpRoute_info *) idrp_local_mem_fit(sizeof(*p_info));
			p_info->idrp_pref = pp->idrp_pref;
			p_info->route_options = p_idrp_ps_atts;

			/* Reset for the next use. */
			p_idrp_ps_atts = (idrpRoute_options *) NULL;

			/* Tag p_info into the "global info" ps_info. */
			$8.adv->adv_result.ps_info = (void_t) p_info;
		}
		if ($7) {
			if (PARSE_METRIC_ISSET(pp) && PARSE_METRIC_ISRESTRICT(pp)) {
				parse_adv_propagate_idrp_restrict($7); 
			}

			/* put the auxiliary test(s) in place */
                	adv->adv_list = $7;

			/* add $8.adv to the adv_list of $7's last element */
			FIND_ADV_LIST_END($7, adv_end);
			adv_end->adv_list = $8.adv;
		} else {
                	adv->adv_list = $8.adv;
		}

                if (PARSE_METRIC_ISSET(pp)) {
                	if (PARSE_METRIC_ISRESTRICT(pp)) {
                   		BIT_SET(adv->adv_flag, ADVF_NO);
                	} else {
                    		BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
                   		adv->adv_result.res_preference = pp->metric;
                	}
                }

		if ($6 != iso_addr_default) {
                	if (!parse_adv_rdi($3.import_list, adv)) {
                	PARSE_ERROR;
                	}
                } else {
			/* Add to the list of global entries. */
			if (idrp_import_list_any_rdi == (adv_entry *) NULL)
				{
				idrp_import_list_any_rdi = adv;
				}
			else
				{
				/* Add to the list of global entries
				 */

				FIND_ADV_LIST_END(idrp_import_list_any_rdi, adv_end);
				adv_end->adv_next = adv;
				}
		}
	}
	| T_IMPORT T_PROTO control_idrp 
	{
	    	parse_proto = RTPROTO_IDRP;
	} 
	  T_RDPATH rdpath_spec idrp_import_optional_info idrp_import_option L_EOS
	{
              	adv_entry *adv, *adv_end;
              	pmet_t *pp = &$8.metric;
		struct iso_net_addr *p_iso_net;
		idrpRoute_info *p_info;

               	/*
               	 *  Tack the list of destinations onto the end of the list
               	 *  for neighbors with the specified RD path.
               	 */
               	adv = adv_alloc(ADVFT_RDPATH, RTPROTO_IDRP);
		adv->adv_rdpath = $6;

		if ($8.adv) {
/* this would work for the older format...
			parse_adv_propagate_idrp_info($8.adv, pp, p_idrp_ps_atts);
*/
			p_info = (idrpRoute_info *) idrp_local_mem_fit(sizeof(idrpRoute_info));
			p_info->idrp_pref = pp->idrp_pref;
			p_info->route_options = p_idrp_ps_atts;
			/* Reset for the next use. */

			p_idrp_ps_atts = (idrpRoute_options *) NULL;

			/* Tag p_info into the "global info" ps_info. */
			$8.adv->adv_result.ps_info = (void_t) p_info;
		}
		if ($7) {
			if (PARSE_METRIC_ISSET(pp) && PARSE_METRIC_ISRESTRICT(pp)) {
				parse_adv_propagate_idrp_restrict($7); 
			}

			/* put the auxiliary test(s) in place */
                	adv->adv_list = $7;

			/* add $8.adv to the adv_list of $7's last element */
			FIND_ADV_LIST_END($7, adv_end);
			adv_end->adv_list = $8.adv;
		} else {
                	adv->adv_list = $8.adv;
		}

                if (PARSE_METRIC_ISSET(pp)) {
                	if (PARSE_METRIC_ISRESTRICT(pp)) {
                   		BIT_SET(adv->adv_flag, ADVF_NO);
                	} else {
                    		BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
                   		adv->adv_result.res_preference = pp->metric;
                	}
                }

		/* Add to the list of global entries. */
	 	if (parse_adv_append(&idrp_import_rdpath_list, adv)) {
			PARSE_ERROR;
		}
	}
@END:	PROTO_IDRP
		| T_IMPORT T_PROTO import_interior 
			{
			    parse_proto = $3.proto;
			} 
		  interface_gateway_list import_option_inet L_EOS
			{
			    /*
			     *	Append the dest_mask list to the end of the import list
			     *	for the specified protocol.
			     */
			    (void) parse_adv_propagate_preference($5, $3.proto, &$6.metric, $6.adv);

			    switch ($5->adv_flag & ADVF_TYPE) {
			    case ADVFT_GW:
				/* Gateway list */
			        {
				    adv_entry *adv = $5;
				    adv_entry *advn;

				    do {
					advn = adv->adv_next;
					adv->adv_next = NULL;
					/* Reset the type */
					adv->adv_flag = (adv->adv_flag & ~ADVF_TYPE) | ADVFT_ANY;
					if (parse_adv_append(&adv->adv_gwp->gw_import, adv)) {
					    PARSE_ERROR;
					}
				    } while ((adv = advn));
				}
				break;

			    case ADVFT_ANY:
				/* Global list */
				if (parse_adv_append($3.import_list, $5)) {
				    PARSE_ERROR;
				}
				break;

			    case ADVFT_IFN:
			    case ADVFT_IFAE:
				/* Interface list */
				if (parse_adv_append(&int_import[$3.proto], $5)) {
				    PARSE_ERROR;
				}
				break;

			    default:
				assert(FALSE);
			    }
			}
@BEGIN:	PROTO_OSPF
		| T_IMPORT T_PROTO T_OSPF_ASE 
			{
			    parse_proto = RTPROTO_OSPF_ASE;
			} 
		  tag_option import_option_inet L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$6.metric;

			    /* Make sure this PS type is known */
			    adv_psfunc_add(RTPROTO_OSPF_ASE, &ospf_adv_psfunc);

			    /*
			     *	Append the dest_mask list to the end of the OSPF import list.
			     */
			    adv = adv_alloc(ADVFT_PS, RTPROTO_OSPF_ASE);
			    adv->adv_list = $6.adv;
			    adv->adv_ps = (caddr_t) adv;

			    /* Set Tag */
			    if (PARSE_METRIC_ISSET(&$5)) {
				BIT_SET(adv->adv_flag, ADVFOT_METRIC);
				BIT_SET(adv->adv_result.res_flag, OSPF_EXPORT_TAG);
				adv->adv_result.res_metric = $5.metric;
			    }

			    /* Set Preference */
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    if (parse_adv_append(&ospf.import_list, adv)) {
				PARSE_ERROR;
			    }
			}
@END:	PROTO_OSPF
@BEGIN:	PROTO_ISIS
		| T_IMPORT T_PROTO T_ISIS
			{
			    parse_proto = RTPROTO_ISIS;
			} 
		  import_option_iso L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$5.metric;

			    /*
			     *	Append the dest_mask list to the end of the ISIS import list.
			     */
			    adv = adv_alloc(ADVFT_ANY, RTPROTO_ISIS);
			    adv->adv_list = $5.adv;

			    /* Set Preference */
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    if (parse_adv_append(&isis_import_list_iso, adv)) {
				PARSE_ERROR;
			    }
			}
@BEGIN:	PROTO_INET
		| T_IMPORT T_PROTO T_ISIS 
			{
			    parse_proto = RTPROTO_ISIS;
			} 
		  T_IP import_option_iso L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$6.metric;

			    /*
			     *	Append the dest_mask list to the end of the ISIS import list.
			     */
			    adv = adv_alloc(ADVFT_ANY, RTPROTO_ISIS);
			    adv->adv_list = $6.adv;

			    /* Set Preference */
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    if (parse_adv_append(&isis_import_list_ip, adv)) {
				PARSE_ERROR;
			    }
			}
@END:	PROTO_INET
@END:	PROTO_ISIS
@BEGIN:	AUTONOMOUS_SYSTEM
		| T_EXPORT T_PROTO control_exterior 
			{
			    parse_proto = $3.proto;
			} 
		  T_AS as prop_source_option_inet L_EOS
			{
#if	defined(PROTO_EGP) || defined(PROTO_BGP)
			    adv_entry *adv;
			    adv_entry *adv_prop = $7.adv;
			    pmet_t *mp = &$7.metric;

			    /*
			     *	Tack the list of destinations onto the end of the list
			     *	for neighbors with the specified AS.
			     */
			    adv = adv_alloc(ADVFT_AS, $3.proto);
			    adv->adv_as = $6;
			    adv->adv_list = adv_prop;
			    if (PARSE_METRIC_ISRESTRICT(mp)) {
				BIT_SET(adv->adv_flag, ADVF_NO);
			    } else if (PARSE_METRIC_ISSET(mp)) {
				BIT_SET(adv->adv_flag, ADVFOT_METRIC);
				adv->adv_result.res_metric = mp->metric;
			    }

			    if (!parse_adv_as($3.export_list, adv)) {
				PARSE_ERROR;
			    }
#endif	/* defined(PROTO_EGP) || defined(PROTO_BGP) */
			}
@END:	AUTONOMOUS_SYSTEM
@BEGIN:	PROTO_IDRP
	| T_EXPORT T_PROTO control_idrp 
	{
	    	parse_proto = RTPROTO_IDRP;
	    	parse_export_proto = RTPROTO_IDRP;
	} 
	  T_RDI osi_rdi_or_any prop_source_option_idrp L_EOS
	{
		adv_entry *adv, *adv_end;
		adv_entry *adv_prop = $7.adv;
		pmet_t *mp = &$7.metric;
                struct iso_net_addr *p_iso_net;
                idrpRoute_info *p_info;

                /*
                 *  Tack the list of destinations onto the end of the list
                 *  for neighbors with the specified RDI.
                 */
                ISO_NET_FROM_SOCKUN(p_iso_net, $6);
                adv = adv_alloc(ADVFT_RDI, RTPROTO_IDRP);
                adv->adv_rdi = (struct iso_net_addr *)
                        idrp_local_mem_fit(sizeof(struct iso_net_addr));
                bzero((caddr_t) adv->adv_rdi->isoa_genaddr, ISO_MAXADDRLEN);
                bcopy(p_iso_net->isoa_genaddr, adv->adv_rdi->isoa_genaddr,
                        p_iso_net->isoa_len);
                adv->adv_rdi->isoa_len = p_iso_net->isoa_len;
                adv->adv_rdi->isoa_family = AF_ISO;

		adv->adv_list = adv_prop;
		if (PARSE_METRIC_ISRESTRICT(mp)) {
			BIT_SET(adv->adv_flag, ADVF_NO);
		} else if (PARSE_METRIC_ISSET(mp)) {
			BIT_SET(adv->adv_flag, ADVFOT_METRIC);
			adv->adv_result.res_metric = mp->metric;
		}

                if ($6 != iso_addr_default) {
                        if (!parse_adv_rdi($3.export_list, adv)) {
                        PARSE_ERROR;
                        }
                } else {
                        /* Add to the list of global entries. */
                        FIND_ADV_LIST_END(idrp_export_list_any_rdi, adv_end);
                        adv_end->adv_next = adv;
                }
	}
@END:	PROTO_IDRP
		| T_EXPORT T_PROTO export_interior 
			{
			    parse_proto = $3.proto;
			} 
		  interface_gateway_list prop_source_option_inet L_EOS
			{
			    /*
			     *	Append the dest_mask list to the end of the export list
			     *	for the specified protocol.
			     */

			    (void) parse_adv_propagate_metric($5, $3.proto, &$6.metric, $6.adv);

			    switch ($5->adv_flag & ADVF_TYPE) {
			    case ADVFT_GW:
				/* Gateway list */
			        {
				    adv_entry *adv = $5;
				    adv_entry *advn;
				
				    do {
					advn = adv->adv_next;
					adv->adv_next = NULL;
					if (parse_adv_append(&adv->adv_gwp->gw_export, adv)) {
					    PARSE_ERROR;
					}
				    } while ((adv = advn));
				}
				break;

			    case ADVFT_ANY:
				/* Global list for the protocol */
				if (parse_adv_append($3.export_list, $5)) {
				    PARSE_ERROR;
				}
				break;

			    case ADVFT_IFN:
			    case ADVFT_IFAE:
				/* Interface list */
				if (parse_adv_append(&int_export[$3.proto], $5)) {
				    PARSE_ERROR;
				}
				break;

			    default:
				assert(FALSE);
			    }
			}
@BEGIN:	PROTO_OSPF
    		| T_EXPORT T_PROTO export_ospf_ase 
			{
			    parse_proto = RTPROTO_OSPF_ASE;
			} 
    		  ospf_type_option tag_as_option prop_source_option_inet L_EOS
			{
			    adv_entry *adv;
			    adv_entry *adv_prop = $7.adv;
			    pmet_t *mp = &$7.metric;

			    /* If we export then we are a border router */
			    IAmASBorderRtr = TRUE;

			    /* Make sure this PS type is known */
			    adv_psfunc_add(RTPROTO_OSPF_ASE, &ospf_adv_psfunc);

			    /*
			     *	Append the dest_mask list to the end of the export list
			     *	for the specified protocol.
			     */
			    adv = adv_alloc(ADVFT_PS, RTPROTO_OSPF_ASE);
			    adv->adv_ps = (caddr_t) adv;
			    adv->adv_list = adv_prop;

			    /* Metric */
			    if (PARSE_METRIC_ISRESTRICT(mp)) {
				BIT_SET(adv->adv_flag, ADVF_NO);
			    } else if (PARSE_METRIC_ISSET(mp)) {
				BIT_SET(adv->adv_flag, ADVFOT_METRIC);
				adv->adv_result.res_metric = mp->metric;
			    }

			    /* Type */
			    if (PARSE_METRIC_ISSET(&$5)) {
				BIT_SET(adv->adv_flag, ADVFOT_FLAG);
				adv->adv_result.res_flag = $5.metric;
			    }

			    /* Tag */
			    switch ($6.state) {
			    case PARSE_METRICS_SET:
				BIT_SET(adv->adv_flag, ADVFOT_METRIC2|ADVFOT_FLAG);
				BIT_SET(adv->adv_result.res_flag, OSPF_EXPORT_TAG|OSPF_EXPORT_TAG_METRIC2);
				adv->adv_result.res_metric2 = $6.metric;
				break;

			    case PARSE_METRICS_ALTERNATE:
				BIT_SET(adv->adv_flag, ADVFOT_METRIC2|ADVFOT_FLAG);
				BIT_SET(adv->adv_result.res_flag, OSPF_EXPORT_TAG|OSPF_EXPORT_TAG_METRIC2);
				adv->adv_result.res_metric2 = PATH_OSPF_TAG_TRUSTED |
				    (($6.metric << PATH_OSPF_TAG_USR_SHIFT) & PATH_OSPF_TAG_USR_MASK);
				break;
			    }

			    if (parse_adv_append(&ospf.export_list, adv)) {
				PARSE_ERROR;
			    }
			}
@END:	PROTO_OSPF
@BEGIN:	PROTO_ISIS
    		| T_EXPORT T_PROTO export_isis
			{
			    parse_proto = RTPROTO_ISIS;
			} 
    		  prop_source_option_iso L_EOS
			{
			    adv_entry *adv;
			    adv_entry *adv_prop = $5.adv;
			    pmet_t *mp = &$5.metric;

			    adv = adv_alloc(ADVFT_ANY, RTPROTO_ISIS);
			    adv->adv_list = adv_prop;

			    /* Metric */
			    if (PARSE_METRIC_ISRESTRICT(mp)) {
				BIT_SET(adv->adv_flag, ADVF_NO);
			    } else if (PARSE_METRIC_ISSET(mp)) {
				BIT_SET(adv->adv_flag, ADVFOT_METRIC);
				adv->adv_result.res_metric = mp->metric;
			    }

			    if (parse_adv_append(&isis_export_list_iso, adv)) {
				PARSE_ERROR;
			    }
			}
@BEGIN:	PROTO_INET
    		| T_EXPORT T_PROTO export_isis
			{
			    parse_proto = RTPROTO_ISIS;
			} 
    		  T_IP prop_source_option_inet L_EOS
			{
			    adv_entry *adv;
			    adv_entry *adv_prop = $6.adv;
			    pmet_t *mp = &$6.metric;

			    adv = adv_alloc(ADVFT_ANY, RTPROTO_ISIS);
			    adv->adv_list = adv_prop;

			    /* Metric */
			    if (PARSE_METRIC_ISRESTRICT(mp)) {
				BIT_SET(adv->adv_flag, ADVF_NO);
			    } else if (PARSE_METRIC_ISSET(mp)) {
				BIT_SET(adv->adv_flag, ADVFOT_METRIC);
				adv->adv_result.res_metric = mp->metric;
			    }

			    if (parse_adv_append(&isis_export_list_ip, adv)) {
				PARSE_ERROR;
			    }
			}
@END:	PROTO_INET
@END:	PROTO_ISIS
@BEGIN:	PROTO_INET
		| T_AGGREGATE aggregate_dest_inet preference_option aggregate_options '{' aggregate_list_inet '}' L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$3;

			    /*
			     *	Tack the list of destinations onto the end of the list
			     *	for neighbors with the specified AS.
			     */
			    adv = adv_alloc(ADVFT_DM | $4, 0);
			    adv->adv_dm = $2;	/* struct copy */
			    BIT_RESET(adv->adv_dm.dm_flags, DMF_EXACT);
			    BIT_SET(adv->adv_dm.dm_flags, DMF_REFINE);
			    adv->adv_list = $6;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    aggregate_list_inet = adv_destmask_insert(parse_error, aggregate_list_inet, adv);
			    if (!aggregate_list_inet) {
				PARSE_ERROR;
			    }
			}
		| T_GENERATE aggregate_dest_inet preference_option '{' aggregate_list_inet '}' L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$3;

			    /*
			     *	Tack the list of destinations onto the end of the list
			     *	for neighbors with the specified AS.
			     */
			    adv = adv_alloc(ADVFT_DM | ADVF_AGGR_GENERATE, 0);
			    adv->adv_dm = $2;	/* struct copy */
			    BIT_RESET(adv->adv_dm.dm_flags, DMF_EXACT);
			    BIT_SET(adv->adv_dm.dm_flags, DMF_REFINE);
			    adv->adv_list = $5;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    aggregate_list_inet = adv_destmask_insert(parse_error, aggregate_list_inet, adv);
			    if (!aggregate_list_inet) {
				PARSE_ERROR;
			    }
			}
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
		| T_AGGREGATE aggregate_dest_iso preference_option aggregate_options '{' aggregate_list_iso '}' L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$3;

			    /*
			     *	Tack the list of destinations onto the end of the list
			     *	for neighbors with the specified AS.
			     */
			    adv = adv_alloc(ADVFT_DM | $4, 0);
			    adv->adv_dm = $2;	/* struct copy */
			    BIT_RESET(adv->adv_dm.dm_flags, DMF_EXACT);
			    BIT_SET(adv->adv_dm.dm_flags, DMF_REFINE);
			    adv->adv_list = $6;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    aggregate_list_iso = adv_destmask_insert(parse_error, aggregate_list_iso, adv);
			    if (!aggregate_list_iso) {
				PARSE_ERROR;
			    }
			}
		| T_GENERATE aggregate_dest_iso preference_option '{' aggregate_list_iso '}' L_EOS
			{
			    adv_entry *adv;
			    pmet_t *pp = &$3;

			    /*
			     *	Tack the list of destinations onto the end of the list
			     *	for neighbors with the specified AS.
			     */
			    adv = adv_alloc(ADVFT_DM | ADVF_AGGR_GENERATE, 0);
			    adv->adv_dm = $2;	/* struct copy */
			    BIT_RESET(adv->adv_dm.dm_flags, DMF_EXACT);
			    BIT_SET(adv->adv_dm.dm_flags, DMF_REFINE);
			    adv->adv_list = $5;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET(adv->adv_flag, ADVF_NO);
				} else {
				    BIT_SET(adv->adv_flag, ADVFOT_PREFERENCE);
				    adv->adv_result.res_preference = pp->metric;
				}
			    }

			    aggregate_list_iso = adv_destmask_insert(parse_error, aggregate_list_iso, adv);
			    if (!aggregate_list_iso) {
				PARSE_ERROR;
			    }
			}
@END:	PROTO_ISO
		;	

/*  */

/* Support for aggregate clauses */

aggregate_options
		: /* Empty */
			{
			    $$ = 0;
			}
		| T_BRIEF
			{
			    $$ = ADVF_AGGR_BRIEF;
			}
		;

@BEGIN:	PROTO_INET
aggregate_dest_inet
		: network_mask_inet
		| default_mask_inet
		;

aggregate_list_inet
		: aggregate_proto_inet
			{
			    $$ = $1;
			    BIT_SET($$->adv_flag, ADVF_FIRST);
			}
		| aggregate_list_inet aggregate_proto_inet
			{
			    $$ = $1;
			    if (parse_adv_append(&$$, $2)) {
				PARSE_ERROR;
			    }
			}
		| aggregate_list_inet error L_EOS
			{
			    yyerrok;
			}
		;

aggregate_proto_inet
		: T_PROTO aggregate_protos_inet import_option_inet L_EOS
			{
			    pmet_t *pp = &$3.metric;
			    
			    $$ = adv_alloc(ADVFT_ANY, $2);
			    $$->adv_list = $3.adv;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET($$->adv_flag, ADVF_NO);
				} else {
				    BIT_SET($$->adv_flag, ADVFOT_PREFERENCE);
				    $$->adv_result.res_preference = pp->metric;
				}
			    }
			}
		;

aggregate_protos_inet
		: T_ALL
			{
			    $$ = RTPROTO_ANY;
			}
		| T_DIRECT
			{
			    $$ = RTPROTO_DIRECT;
			}
		| T_STATIC
			{
			    $$ = RTPROTO_STATIC;
			}
		| T_KERNEL
			{
			    $$ = RTPROTO_KERNEL;
			}
		| T_AGGREGATE
			{
			    $$ = RTPROTO_AGGREGATE;
			}
@BEGIN:	PROTO_HELLO
		| T_HELLO
			{
			    $$ = RTPROTO_HELLO;
			}
@END:	PROTO_HELLO
@BEGIN:	PROTO_RIP
		| T_RIP
			{
			    $$ = RTPROTO_RIP;
			}
@END:	PROTO_RIP
@BEGIN:	PROTO_OSPF
		| T_OSPF
			{
			    $$ = RTPROTO_OSPF;
			}
		| T_OSPF_ASE
			{
			    $$ = RTPROTO_OSPF_ASE;
			}
@END:	PROTO_OSPF
@BEGIN:	PROTO_ISIS
		| T_ISIS
			{
			    $$ = RTPROTO_ISIS;
			}
@END:	PROTO_ISIS
@BEGIN:	PROTO_SLSP
		| T_SLSP
			{
			    $$ = RTPROTO_SLSP;
			}
@END:	PROTO_SLSP
@BEGIN:	PROTO_BGP
		| T_BGP
			{
			    $$ = RTPROTO_BGP;
			}
@END:	PROTO_BGP
@BEGIN:	PROTO_EGP
		| T_EGP
			{
			    $$ = RTPROTO_EGP;
			}
@END:	PROTO_EGP
@BEGIN:	PROTO_SNMP
		| T_SNMP
			{
			    $$ = RTPROTO_SNMP;
			}
@END:	PROTO_SNMP
		;
@END:	PROTO_INET

@BEGIN:	PROTO_ISO
aggregate_dest_iso
		: T_ISO network_mask_iso
			{
			    $$ = $2;
			}
		| T_ISO default_mask_iso
			{
			    $$ = $2;
			}
		;

aggregate_list_iso
		: aggregate_proto_iso
			{
			    $$ = $1;
			    BIT_SET($$->adv_flag, ADVF_FIRST);
			}
		| aggregate_list_iso aggregate_proto_iso
			{
			    $$ = $1;
			    if (parse_adv_append(&$$, $2)) {
				PARSE_ERROR;
			    }
			}
		| aggregate_list_iso error L_EOS
			{
			    yyerrok;
			}
		;

aggregate_proto_iso
		: T_PROTO aggregate_protos_iso import_option_iso L_EOS
			{
			    pmet_t *pp = &$3.metric;
			    
			    $$ = adv_alloc(ADVFT_ANY, $2);
			    $$->adv_list = $3.adv;
			    if (PARSE_METRIC_ISSET(pp)) {
				if (PARSE_METRIC_ISRESTRICT(pp)) {
				    BIT_SET($$->adv_flag, ADVF_NO);
				} else {
				    BIT_SET($$->adv_flag, ADVFOT_PREFERENCE);
				    $$->adv_result.res_preference = pp->metric;
				}
			    }
			}
		;

aggregate_protos_iso
		: T_ALL
			{
			    $$ = RTPROTO_ANY;
			}
		| T_STATIC
			{
			    $$ = RTPROTO_STATIC;
			}
		| T_KERNEL
			{
			    $$ = RTPROTO_KERNEL;
			}
		| T_AGGREGATE
			{
			    $$ = RTPROTO_AGGREGATE;
			}
@BEGIN:	PROTO_ISIS
		| T_ISIS
			{
			    $$ = RTPROTO_ISIS;
			}
@END:	PROTO_ISIS
@BEGIN:	PROTO_IDRP
		| T_IDRP
			{
			    $$ = RTPROTO_IDRP;
			}
@END:	PROTO_IDRP
@BEGIN:	PROTO_SNMP
		| T_SNMP
			{
			    $$ = RTPROTO_SNMP;
			}
@END:	PROTO_SNMP
		;
@END:	PROTO_ISO

/*  */

/* Support for import clauses */

control_exterior	: proto_exterior
			{
			    parse_export_proto = $$.proto = $1;

			    switch ($1) {
#if	defined(PROTO_EGP)
			    case RTPROTO_EGP:
				$$.import_list = &egp_import_list;
				$$.export_list = &egp_export_list;
				break;
#endif

#if	defined(PROTO_BGP)
			    case RTPROTO_BGP:
				$$.import_list = &bgp_import_list;
				$$.export_list = &bgp_export_list;
				break;
#endif

			    default:
				(void) sprintf(parse_error,
					       "unknown import protocol: %s",
					       gd_lower(trace_state(rt_proto_bits, $1)));
				PARSE_ERROR;
			    }
			}
		;


@BEGIN:	PROTO_IDRP
control_idrp : T_IDRP
			{
				$$.proto = RTPROTO_IDRP;
				$$.import_list = &idrp_import_list;
				$$.export_list = &idrp_export_list;
			}
		;
@END:	PROTO_IDRP

import_interior : proto_interior
			{
			    $$ = $1;
			    
			    parse_proto = $1.proto;
			    parse_gwlist = $1.gw_list;

			    if (!$1.import_list) {
				(void) sprintf(parse_error,
					       "unknown import protocol: %s",
					       gd_lower(trace_state(rt_proto_bits, $1.proto)));
				PARSE_ERROR;
			    }
			    
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $1.proto))));
			}
		;

@BEGIN:	PROTO_IDRP
/* 
	N.B.:  
		This architecture will allow for multiple specification of
		each of the options; you should either:

			- issue a warning and only use the last one specified, or
			- issue an error and exit when a duplicate field tag is
			  found.

*/
idrp_local_intf_test : T_LOCAL_INTERFACE host 
	{
		IDRP_PS_ALLOC($$, IDRP_PSFT_LOCAL_IP_INTF);
		((struct _idrp_ps_t *) $$->adv_ps)->ps_intf = $2;
	}
	/* TODO:  the following only uses NET for now; should be idrp_snpa! */
	| T_LOCAL_NET osi_address
	{
		struct iso_net_addr *p_iso_net;

		ISO_NET_FROM_SOCKUN(p_iso_net, $2);
		IDRP_PS_ALLOC($$, IDRP_PSFT_LOCAL_SNPA);
		IDRP_ISO_NET_ALLOC(((struct _idrp_ps_t *) $$->adv_ps)->ps_nexthop_net, *p_iso_net);

		/* WAS only the following:
		IDRP_PS_ALLOC($$, IDRP_PSFT_LOCAL_SNPA);
		((struct _idrp_ps_t *) $$->adv_ps)->ps_snpas = p_snpa_list;
		p_snpa_list = (snpa_list *) NULL;
		*/
	}
	;

/*
 * "$$" should contain the idrp_policy_atts_clause, if any;
 * the idrp_atts_clause is stored in the global p_idrp_ps_atts.
 */
idrp_import_optional_info : /* Empty */
	{
		$$ = (adv_entry *) NULL;
	}
	| idrp_local_intf_test 
	{
		$$ = $1;
	}
	| idrp_policy_atts_clause
	{
		$$ = $1;
	}
	| idrp_atts_clause
	{
		$$ = (adv_entry *) NULL;
	}
	| idrp_local_intf_test idrp_policy_atts_clause
	{
		$$ = $1;
		$$->adv_next = $2;
	}
	| idrp_local_intf_test idrp_atts_clause
	{
		$$ = $1;
	}
	| idrp_policy_atts_clause idrp_atts_clause
	{
		$$ = $1;
	}
	| idrp_atts_clause idrp_policy_atts_clause
	{
		$$ = $2;
	}
	| idrp_local_intf_test idrp_policy_atts_clause idrp_atts_clause
	{
		$$ = $1;
		$$->adv_next = $2;
	}
	| idrp_local_intf_test idrp_atts_clause idrp_policy_atts_clause
	{
		$$ = $1;
		$$->adv_next = $3;
	}
	;
	
idrp_export_optional_info : /* Empty */
	{
		$$ = (adv_entry *) NULL;
	}
	| idrp_policy_atts_clause
	{
		$$ = $1;
	}
	| idrp_atts_clause
	{
		$$ = (adv_entry *) NULL;
	}
	| idrp_policy_atts_clause idrp_atts_clause
	{
		$$ = $1;
	}
	| idrp_atts_clause idrp_policy_atts_clause
	{
		$$ = $2;
	}
	;
	
idrp_policy_atts_clause: T_IDRP_PS_POLICY_ATTS 
	{
		idrp_ps_flag = PS_ON;
		idrp_have_nexthop = FALSE;
	}
	'{' idrp_ps_policy_attribute_entries '}'
	{
		$$ = $4;
		idrp_ps_flag = PS_NONE;
		idrp_have_nexthop = FALSE;
	}
	;

idrp_atts_clause: T_IDRP_PS_ATTS 
	{
		idrp_ps_flag = PS_ON;
	}
	'{' idrp_ps_attribute_entries '}'
	{
		idrp_ps_flag = PS_NONE;
	}
	;

idrp_ps_policy_attribute_entries: idrp_ps_policy_attribute_entry
	| idrp_ps_policy_attribute_entries idrp_ps_policy_attribute_entry
 	{
		$$ = $1;
 		if (parse_adv_append(&$$, $2)) {
 			PARSE_ERROR;
 	    	}
 	}
	; 

idrp_ps_attribute_entries: idrp_ps_attribute_entry 
	| idrp_ps_attribute_entries idrp_ps_attribute_entry
	; 

idrp_ps_policy_attribute_entry: idrp_ps_policy_route_option L_EOS
	| idrp_ps_policy_hopcount L_EOS
	| idrp_ps_policy_nexthop L_EOS
	| idrp_ps_policy_QOS_option L_EOS
/* TODO @BEGIN:	PROTO_RDPATHS */
	| idrp_ps_policy_dist_option L_EOS
/* @END:	PROTO_RDPATHS */
	;

idrp_ps_attribute_entry: idrp_ps_route_option L_EOS
	| idrp_ps_pref_calc L_EOS
	| idrp_ps_QOS_option L_EOS
/* SJR TODO @BEGIN:	PROTO_RDPATHS
*/
	| idrp_ps_dist_option L_EOS
/* SJR TODO @END:	PROTO_RDPATHS
*/
	;

idrp_ps_policy_route_option: T_ROUTESERVER null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_ROUTESERV);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_EXTINFO null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_EXTINFO);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_HIERARCHICAL_REC null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_HIERARCH);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_MULTIEXIT null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_MULTIEXIT);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
        | T_MULTIEXIT number_compare_op idrp_multiexit_value
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_MULTIEXIT);
			IDRP_QOS_ALLOC(((struct _idrp_ps_t *) $$->adv_ps)->ps_multi_exit, $2, $3);
		}
	; 

idrp_ps_policy_nexthop: T_NET osi_address
		{
			struct iso_net_addr *p_iso_net;

			if (idrp_have_nexthop) {
				trace_tf(trace_global, TR_PARSE, 0, ("%d--already have an IDRP nexthop; exiting", __LINE__));
				assert(FALSE);
			}
			idrp_have_nexthop = TRUE;

			ISO_NET_FROM_SOCKUN(p_iso_net, $2);
			IDRP_PS_ALLOC($$, IDRP_PSFT_NEXTHOP_NET);
			IDRP_ISO_NET_ALLOC(((struct _idrp_ps_t *) $$->adv_ps)->ps_nexthop_net, *p_iso_net);
		}
	/* TODO -- just one SNPA, now--sjr */
	| T_NET osi_address T_SNPA idrp_snpa
		{
			struct iso_net_addr *p_iso_net;

			if (idrp_have_nexthop) {
				trace_tf(trace_global, TR_PARSE, 0, ("%d--already have an IDRP nexthop; exiting", __LINE__));
				assert(FALSE);
			}
			idrp_have_nexthop = TRUE;

			ISO_NET_FROM_SOCKUN(p_iso_net, $2);
			IDRP_PS_ALLOC($$, IDRP_PSFT_NEXTHOP_NET);
			IDRP_ISO_NET_ALLOC(((struct _idrp_ps_t *) $$->adv_ps)->ps_nexthop_net, *p_iso_net);

			IDRP_PS_ALLOC($$->adv_next, IDRP_PSFT_NEXTHOP_SNPA);
			((struct _idrp_ps_t *) $$->adv_next->adv_ps)->ps_nexthop_snpas = p_snpa_list;
			p_snpa_list = (snpa_list *) NULL;
		}
	| T_GATEWAY host
		{
			if (idrp_have_nexthop) {
				trace_tf(trace_global, TR_PARSE, 0, ("%d--already have an IDRP nexthop; exiting", __LINE__));
				assert(FALSE);
			}
			idrp_have_nexthop = TRUE;

			IDRP_PS_ALLOC($$, IDRP_PSFT_NEXTHOP_IPGW);
		        ((struct _idrp_ps_t *) $$->adv_ps)->ps_gw = $2;
		}
	| T_INTERFACE host
		{
			if (idrp_have_nexthop) {
				trace_tf(trace_global, TR_PARSE, 0, ("%d--already have an IDRP nexthop; exiting", __LINE__));
				assert(FALSE);
			}
			idrp_have_nexthop = TRUE;

			IDRP_PS_ALLOC($$, IDRP_PSFT_NEXTHOP_IPINTF);
		        ((struct _idrp_ps_t *) $$->adv_ps)->ps_intf = $2;
		}
	;

idrp_ps_route_option: T_ROUTESERVER onoff_option
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);

		if ($2 == T_ON) {
			IDRP_STATUS_BIT_SET(p_idrp_ps_atts,IDRP_OPTS_ROUTE_SERVER);
		} else {
			IDRP_STATUS_BIT_CLEAR(p_idrp_ps_atts,IDRP_OPTS_ROUTE_SERVER);
		}
	}
	| T_EXTINFO
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		IDRP_STATUS_BIT_SET(p_idrp_ps_atts,IDRP_OPTS_EXT_INFO);
	}
	| T_HIERARCHICAL_REC
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		IDRP_STATUS_BIT_SET(p_idrp_ps_atts,IDRP_OPTS_HIER_REC);
	}
	| T_MULTIEXIT idrp_multiexit_value
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		p_idrp_ps_atts->multi_exit[0] = $2;
	}
/* TODO--it would make sense to use something akin to:
 * "NEXTHOP use-me;" for 7.12.4 a) 1 or b) 1
 * "NEXTHOP none;" for 7.12.4 a) 2 or b) 2
 * This has implications for SNPAs, etc.
 *
 * SJR
 */
	; 

idrp_ps_policy_hopcount : T_HOPCOUNT number_compare_op idrp_rd_hopcount_value
	{
		IDRP_PS_ALLOC($$, IDRP_PSFT_HOPCNT);
		IDRP_QOS_ALLOC(((struct _idrp_ps_t *) $$->adv_ps)->ps_hopcount, $2, $3);
	}
	;

idrp_ps_pref_calc : T_HOPCOUNT_OFFSET idrp_preference
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		p_idrp_ps_atts->hopcount = $2;
	}
	;

idrp_rd_hopcount_value : L_NUMBER
	{
        	if (parse_limit_check("IDRP hop count",
        		(u_int) $1,
        		LIMIT_IDRP_HOPCOUNT)) {
        		PARSE_ERROR;
        	}
		$$ = $1;	
	}
	;

number_compare_op : /* empty */
		{
		$$ = IDRP_QOS_OP_EQ;
		}
	| T_LT
		{
		$$ = IDRP_QOS_OP_LT;
		}
	| T_LE
		{
		$$ = IDRP_QOS_OP_LE;
		}
	| T_EQ
		{
		$$ = IDRP_QOS_OP_EQ;
		}
	| T_NE
		{
		$$ = IDRP_QOS_OP_NE;
		}
	| T_GE
		{
		$$ = IDRP_QOS_OP_GE;
		}
	| T_GT
		{
		$$ = IDRP_QOS_OP_GT;
		}
	;

/* TODO:  sort as they are input */
/* TODO SJR take care of this when PROTO_RDPATHS is not limping @BEGIN:	PROTO_RDPATHS */
idrp_ps_dist_option: T_PROHIBIT_DIST '{' idrp_ps_dist_list '}'
	{
		if (p_idrp_ps_atts->p_DIST_LIST_EXCL) {
			trace_tf(trace_global, TR_PARSE, 0, ("%d--extra 'prohibit-dist' clause", __LINE__));
			assert(FALSE);
		} else {
			p_idrp_ps_atts->p_DIST_LIST_EXCL = $3;
		}
	}
	| T_ALLOW_DIST '{' idrp_ps_dist_list '}'
	{
		if (p_idrp_ps_atts->p_DIST_LIST_INCL) {
			trace_tf(trace_global, TR_PARSE, 0, ("%d--extra 'allow-dist' clause", __LINE__));
			assert(FALSE);
		} else {
			p_idrp_ps_atts->p_DIST_LIST_INCL = $3;
		}
	}
	;

idrp_ps_dist_list: idrp_ps_dist_list idrp_ps_dist_rdi 
	{
		$$ = idrp_insert_canon_rdpath($1, $2);
	}
	| idrp_ps_dist_rdi 
	{
		$$ = $1;
	}
	;

idrp_ps_dist_rdi: osi_rdi				
	{
		struct iso_net_addr *p_iso_net;
		rdi *p_rdi;

		ISO_NET_FROM_SOCKUN(p_iso_net, $1);
		IDRP_RDI_ALLOC(p_rdi);
		iso_net_copy(p_iso_net, &p_rdi->rdi);

		p_rdi = idrp_insert_global_rdi(&p_rdi);
		IDRP_CANON_RDPATH_ALLOC($$);
		$$->p_rdi = p_rdi;
	} 	
	;	
/* TODO SJR take care of this when PROTO_RDPATHS is not limping @END:	PROTO_RDPATHS */

/*TODO--wrap in RDPATH */
idrp_ps_policy_dist_option: T_DIST_LIST_INCL '{' idrp_ps_dist_list '}'
	{
		IDRP_PS_ALLOC($$, IDRP_PSFT_DISTINCL);
	}
	| T_DIST_LIST_EXCL '{' idrp_ps_dist_list '}'
	{
		IDRP_PS_ALLOC($$, IDRP_PSFT_DISTEXCL);
	}
	;

idrp_ps_policy_QOS_option : T_TRANSITDELAY null_or_restrict 
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_TRANSIT_DELAY);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_TRANSITDELAY number_compare_op idrp_transit_delay_value
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_TRANSIT_DELAY);
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_TRANSIT_DELAY);
			IDRP_DIST_ATT_SET(p_qos->delay, $2, $3);
			((struct _idrp_ps_t *) $$->adv_ps)->ps_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
	| T_RDLRE null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_RESIDUAL_ERROR);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_RDLRE number_compare_op idrp_rdlre_value
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_RESIDUAL_ERROR);
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_RESIDUAL_ERROR); 
			IDRP_DIST_ATT_SET(p_qos->error, $2, $3);
			((struct _idrp_ps_t *) $$->adv_ps)->ps_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
	| T_EXPENSE null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_EXPENSE);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_EXPENSE number_compare_op idrp_expense_value
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_EXPENSE);
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_EXPENSE); 
			IDRP_DIST_ATT_SET(p_qos->expense, $2, $3);
			((struct _idrp_ps_t *) $$->adv_ps)->ps_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
	| T_PRIORITY null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_PRIORITY);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_PRIORITY number_compare_op idrp_priority_value
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_PRIORITY);
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_PRIORITY);
			IDRP_DIST_ATT_SET(p_qos->priority, $2, $3);
			((struct _idrp_ps_t *) $$->adv_ps)->ps_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
	| T_CAPACITY null_or_restrict
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_CAPACITY);
			if ($2 == T_RESTRICT)
				IDRP_PS_BIT_SET($$, IDRP_PSFT_RESTRICT);
		}
	| T_CAPACITY number_compare_op idrp_capacity_value
		{
			IDRP_PS_ALLOC($$, IDRP_PSFT_CAPACITY);
			IDRP_QOS_ALLOC(((struct _idrp_ps_t *) $$->adv_ps)->ps_capacity, $2, $3);
		}
	;

idrp_ps_QOS_option: T_TRANSITDELAY idrp_transit_delay_value
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		if (!p_idrp_ps_atts->p_qos) {
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_TRANSIT_DELAY); 
			p_idrp_ps_atts->p_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
		BIT_SET(p_idrp_ps_atts->p_qos->idrp_mask, IDRP_ATTBT_TRANSIT_DELAY);
		IDRP_DIST_ATT_SET(p_idrp_ps_atts->p_qos->delay, IDRP_QOS_OP_EQ, $2);
	}

	| T_RDLRE idrp_rdlre_value
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		if (!p_idrp_ps_atts->p_qos) {
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_RESIDUAL_ERROR); 
			p_idrp_ps_atts->p_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
		BIT_SET(p_idrp_ps_atts->p_qos->idrp_mask, IDRP_ATTBT_RESIDUAL_ERROR);
		IDRP_DIST_ATT_SET(p_idrp_ps_atts->p_qos->error, IDRP_QOS_OP_EQ, $2);
	}

	| T_EXPENSE idrp_expense_value
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		if (!p_idrp_ps_atts->p_qos) {
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_EXPENSE); 
			p_idrp_ps_atts->p_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
		BIT_SET(p_idrp_ps_atts->p_qos->idrp_mask, IDRP_ATTBT_EXPENSE);
		IDRP_DIST_ATT_SET(p_idrp_ps_atts->p_qos->expense, IDRP_QOS_OP_EQ, $2);
	}

	| T_PRIORITY idrp_priority_value
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		if (!p_idrp_ps_atts->p_qos) {
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_PRIORITY); 
			p_idrp_ps_atts->p_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
		BIT_SET(p_idrp_ps_atts->p_qos->idrp_mask, IDRP_ATTBT_PRIORITY);
		IDRP_DIST_ATT_SET(p_idrp_ps_atts->p_qos->priority, IDRP_QOS_OP_EQ, $2);
	}

	| T_CAPACITY idrp_capacity_value
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		IDRP_DIST_ATT_SET(p_idrp_ps_atts->capacity, IDRP_QOS_OP_EQ, $2);
	}

	| T_SECURITY idrp_security_type idrp_security_value
	{
		if (!p_idrp_ps_atts) IDRPROUTE_OPTS_ALLOC(p_idrp_ps_atts);
		if (!p_idrp_ps_atts->p_qos) {
			IDRP_DIST_ATT_ALLOC(p_qos, IDRP_ATTBT_PRIORITY); 
			p_idrp_ps_atts->p_qos = p_qos;
			p_qos = (idrp_distinguish_att *) NULL;
		}
		BIT_SET(p_idrp_ps_atts->p_qos->idrp_mask, IDRP_ATTBT_SECURITY);
		IDRP_DIST_ATT_SET(p_idrp_ps_atts->p_qos->sec_type, IDRP_QOS_OP_EQ, $2);
		IDRP_DIST_ATT_SET(p_idrp_ps_atts->p_qos->sec_type, IDRP_QOS_OP_EQ, $3);

	}
	;
			
idrp_ps_snpa_rt_option	: T_SNPA
				{
				trace_tf(trace_global, TR_PARSE,0, ("idrp snpa for local route"));
				}
	;
			
idrp_ps_snpa_rt_option	: T_SNPA
				{
				trace_tf(trace_global, TR_PARSE,0, ("idrp snpa for local route"));
				p_snpa_list = &p_idrp_opts->next_hop[IDRP_NLRI_ISO].next_hop_snpas;
				}
			  idrp_snpas
				{
				/* Reset for next use. */
				p_snpa_list = (snpa_list *) NULL;
				}
			;

/* TODO--@BEGIN:	PROTO_RDPATHS */
rdpath_prop_init: idrp_prop_init
rdpath_spec: '/' rdpath_parts rdpath_any_or_null '/' rdpath_flag
	{
		policy_rdpath *p_path;

		$$ = $2;
		if ($3) {
			FIND_POLICY_RDPATH_END($2);
			$2->p_next = $3;
		}

		/* 
		 * If the flag is a "SUBSET" flag, then set the path
		 * elements accordingly; if not, then 0 -> exact.  
		 * (See idrp.h and idrp_rdpath.c for more info.)
		 */
		if ($5 == T_SUBSET) {
			for(p_path = $$; (p_path); p_path = p_path->p_next) {
				p_path->status |= IDRP_RDPATH_SUBSET;
			}
		}
	}
	; 

rdpath_parts: rdpath_part
	| rdpath_parts rdpath_part
	{
		$$ = $1;
		FIND_POLICY_RDPATH_END($1);
		$1->p_next = $2;
	}
	;

rdpath_part: rdpath_special_part rdpath_real_part
	{
		$$ = $1;
		$1->p_next = $2;
	}
	| rdpath_real_part
	;

rdpath_special_part: '.'
	{
		/* "any one" */
		IDRP_POLICY_RDPATH_ALLOC($$);
		$$->status = IDRP_RDPATH_SINGLE;
	}
	| rdpath_any 
	;

rdpath_any: '.' '*'
	{
		/* "any" */
		IDRP_POLICY_RDPATH_ALLOC($$);
		$$->status = IDRP_RDPATH_ANY;
	}
	;

rdpath_any_or_null: /* empty */
	{
		$$ = (struct _policy_rdpath *) NULL;
	}
	| rdpath_any
	;

rdpath_real_part: policy_rdpath_rdi
	{
		$1->status = IDRP_RDPATH_SEQ;
		$$ = $1;
	}
	| '[' rdpath_set ']' 
	{
		$$ = $2;
	}
	| '(' rdpath_or_list ')'
	{
		$$ = $2;
	}
	;

rdpath_set: policy_rdpath_rdi
	{
		$1->status = IDRP_RDPATH_SET;
		$$ = $1;
	}
	| rdpath_set policy_rdpath_rdi
	{
		$2->status = IDRP_RDPATH_SET;
		$$ = $1;
		FIND_POLICY_RDPATH_END($1);
		$1->p_next = $2;
	}
	;

rdpath_or_list: policy_rdpath_rdi
	{
		$1->status = IDRP_RDPATH_OR;
		$$ = $1;
	}
	| rdpath_or_list '|' policy_rdpath_rdi
	{
		$3->status = IDRP_RDPATH_OR;
		$$ = $1;
		FIND_POLICY_RDPATH_END($1);
		$1->p_next = $3;
	}
	;

policy_rdpath_rdi: osi_rdi
	{
                struct iso_net_addr *p_iso_net;

                ISO_NET_FROM_SOCKUN(p_iso_net, $1);
		IDRP_POLICY_RDPATH_ALLOC($$);
                IDRP_RDI_ALLOC($$->p_rdi);
                iso_net_copy(p_iso_net, &($$->p_rdi->rdi));

                $$->p_rdi = idrp_insert_global_rdi(&$$->p_rdi);
	}
	;

rdpath_flag: /* Empty */
	{ $$ = T_EXACT; }
	| T_EXACT
	| T_SUBSET
	;
/* TODO--@END:	PROTO_RDPATHS */

idrp_gateway_list: L_NUMBER /* TODO! */
		;

idrp_interface_list: L_NUMBER /* TODO! */
		;

idrp_parse_import_list:  /* Empty */
 			{
 			    $$ = (adv_entry *) NULL;
 			}
 		| idrp_parse_import_list idrp_import_listen L_EOS
 			{
                            $$ = adv_destmask_insert(parse_error, $1, $2);
                            if ($$ == (adv_entry *) NULL) {
                                PARSE_ERROR;
                            }
 			}
 		| idrp_parse_import_list error L_EOS
 			{
 			    yyerrok;
 			}
 		;
 
idrp_import_listen:
 	{
 		parse_contig_masks = FALSE;
 	}
 	idrp_dest_mask idrp_preference_restrict_option
 	{
		struct _idrpRoute_info *p_route_info;
 		parse_contig_masks = TRUE;
 
 		$$ = adv_alloc(ADVFT_DM, parse_proto);
 		$$->adv_dm = $2;
 		if (PARSE_METRIC_ISSET(&$3)) {
 			if (PARSE_METRIC_ISRESTRICT(&$3)) {
 				BIT_SET($$->adv_flag, ADVF_NO);
 			} else {
 				BIT_SET($$->adv_flag, ADVFOT_PREFERENCE);
 				$$->adv_result.res_preference = $3.metric;
 			}
 		}
		if ((!PARSE_METRIC_ISRESTRICT(&$3)) && ($3.idrp_pref != IDRP_INVALID_ROUTE_PREF)) {
			p_route_info = (struct _idrpRoute_info *) idrp_local_mem_fit(sizeof(struct _idrpRoute_info));
			bzero(p_route_info, sizeof(struct _idrpRoute_info));
			p_route_info->idrp_pref = (idrp_pref_t) $3.idrp_pref;
			$$->adv_dm.dm_ps = (void_t) p_route_info;
		}
 	}
	;

idrp_dest_mask: osi_dest_mask
	| T_IP dest_mask_inet
	{ $$ = $2; }
	;

osi_dest_mask: dest_mask_iso
			{
				$$ = $1;
			}
		| dest_mask_iso L_NUMBER
			{
			/* TODO -- fix this up */
				switch (L_NUMBER) {
					case(AF_INET):
						$$ = $1;
						break;

#ifdef PROTO_ISO
#if defined(AF_OSI) || defined(AF_OSINET) || defined(AF_GOSIP)
#ifdef AF_OSI
					case(AF_OSI):
#endif
#ifdef AF_OSINET
					case(AF_OSINET):
#endif
#ifdef AF_GOSIP
					case(AF_GOSIP):
#endif
						$$ = $1;
						break;
#endif
#endif
				}
			}
		;

idrp_import_option
		: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| idrp_preference_option '{' idrp_parse_import_list '}'
			{
			    $$.metric = $1;
			    /* 
			     * The next line used to be:
			     * $$.adv = $3;
			     * TODO:  Will mixed addrs hurt?
			     * Will the whole thing die a sad death?
			     * Will Betty marry Ted?
			     * Tune in for the next episode of AMC... ;-)
			     */
			    $$.adv = adv_destmask_finish($3);
			}
		;

idrp_preference_option
		: /* Empty */
		{
		    PARSE_METRIC_CLEAR(&$$);
		    PARSE_IDRP_PREF_CLEAR(&$$);
		}
		/* just a GateD preference; same form as other GateD imports */
		| T_GATED_PREF preference
		{
		    PARSE_METRIC_SET(&$$, $2);
		    PARSE_IDRP_PREF_CLEAR(&$$);
		}
		| T_IDRP_PREF idrp_preference 
		{
		    PARSE_METRIC_CLEAR(&$$);
		    PARSE_IDRP_PREF_SET(&$$, $2);
		}
		| T_GATED_PREF preference T_IDRP_PREF idrp_preference 
		{
		    PARSE_METRIC_SET(&$$, $2);
		    PARSE_IDRP_PREF_SET(&$$, $4);
		}
		| T_IDRP_PREF idrp_preference T_GATED_PREF preference 
		{
		    PARSE_IDRP_PREF_SET(&$$, $2);
		    PARSE_METRIC_SET(&$$, $4);
		}
		;

idrp_preference_restrict_option
        : idrp_preference_option
        | T_RESTRICT
        {
                PARSE_METRIC_RESTRICT(&$$);
        }
        ;

idrp_preference: L_NUMBER
	{
		if (parse_limit_check("idrp_preference", (u_int) $1,
				  LIMIT_IDRP_PREFERENCE)) {
			PARSE_ERROR;
		}
		$$ = $1;
	}
	;

@END:	PROTO_IDRP

@BEGIN:	PROTO_INET
/* IP Import stuff */

import_option_inet
		: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| preference_option '{' import_list_inet '}'
			{
			    $$.metric = $1;
			    $$.adv = adv_destmask_finish($3);
			}
		;

import_list_inet
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| import_list_inet import_listen_inet L_EOS
			{
			    
			    $$ = adv_destmask_insert(parse_error, $1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| import_list_inet error L_EOS
			{
			    yyerrok;
			}
		;

import_listen_inet
		:
			{
			    parse_contig_masks = FALSE;
			}
			dest_mask_inet preference_restrict_option
			{
			    parse_contig_masks = TRUE;

			    if ($2.dm_dest
				&& (socktype($2.dm_dest) != AF_INET)) {
				sprintf(parse_error, "address not INET");
				PARSE_ERROR
			    }

			    $$ = adv_alloc(ADVFT_DM, parse_proto);
			    $$->adv_dm = $2;
			    if (PARSE_METRIC_ISSET(&$3)) {
				if (PARSE_METRIC_ISRESTRICT(&$3)) {
				    BIT_SET($$->adv_flag, ADVF_NO);
				} else {
				    BIT_SET($$->adv_flag, ADVFOT_PREFERENCE);
				    $$->adv_result.res_preference = $3.metric;
				}
			    }
			}
		;
@END:	PROTO_INET

@BEGIN:	PROTO_ISO
/* ISO Import stuff */

import_option_iso	: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| preference_option '{' import_list_iso '}'
			{
			    $$.metric = $1;
			    $$.adv = adv_destmask_finish($3);
			}
		;

import_list_iso	: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| import_list_iso import_listen_iso L_EOS
			{
			    
			    $$ = adv_destmask_insert(parse_error, $1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| import_list_iso error L_EOS
			{
			    yyerrok;
			}
		;

import_listen_iso	:
			{
			    parse_contig_masks = FALSE;
			}
			dest_mask_iso preference_restrict_option
			{
			    parse_contig_masks = TRUE;

			    if ($2.dm_dest
				&& (socktype($2.dm_dest) != AF_ISO)) {
				sprintf(parse_error, "address not ISO");
				PARSE_ERROR
			    }

			    $$ = adv_alloc(ADVFT_DM, parse_proto);
			    $$->adv_dm = $2;
			    if (PARSE_METRIC_ISSET(&$3)) {
				if (PARSE_METRIC_ISRESTRICT(&$3)) {
				    BIT_SET($$->adv_flag, ADVF_NO);
				} else {
				    BIT_SET($$->adv_flag, ADVFOT_PREFERENCE);
				    $$->adv_result.res_preference = $3.metric;
				}
			    }
			}
		;
@END:	PROTO_ISO

/*  */

/* Support for Export clauses */

export_interior : proto_interior
			{
			    $$ = $1;
			    
			    parse_export_proto = parse_proto = $1.proto;
			    parse_gwlist = $1.gw_list;

			    if (!$1.export_list) {
				(void) sprintf(parse_error,
					       "unknown export protocol: %s",
					       gd_lower(trace_state(rt_proto_bits, $1.proto)));
				PARSE_ERROR;
			    }
			    
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $1.proto))));
			}
		;


@BEGIN:	PROTO_OSPF
export_ospf_ase	: T_OSPF_ASE
			{
			    $$ = parse_export_proto = RTPROTO_OSPF_ASE;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;
@END:	PROTO_OSPF

@BEGIN:	PROTO_ISIS
export_isis	: T_ISIS
			{
			    $$ = parse_export_proto = RTPROTO_ISIS;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
@END:	PROTO_ISIS


@BEGIN:	PROTO_IDRP
prop_source_option_idrp
    		: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| metric_option '{' prop_source_list_idrp '}'
			{
			    $$.metric = $1;
			    $$.adv = $3;
			}
		;

prop_source_list_idrp
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| prop_source_list_idrp prop_source_idrp L_EOS
			{
			    $$ = $1;
			    if (parse_adv_append(&$$, $2)) {
				PARSE_ERROR;
			    }
			}
		| prop_source_list_idrp error L_EOS
			{
			    yyerrok;
			}
		;

prop_source_idrp:
    /* Static routes */
	  T_PROTO prop_static interface_list_option prop_metric_option_idrp
	{
		$$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
	}
    /* IDRP--RDIs */
        | T_PROTO idrp_prop_init T_RDI osi_rdi_or_any idrp_export_optional_info prop_metric_option_idrp
	{
              	pmet_t *pp = &$6.metric;
        	struct iso_net_addr *p_iso_net;
		idrpRoute_info *p_info;
              	adv_entry *adv_list, *adv_end;

		if ($6.adv) {
			p_info = (idrpRoute_info *) idrp_local_mem_fit(sizeof(*p_info));
			bzero((caddr_t) p_info, sizeof(*p_info));
			p_info->idrp_pref = IDRP_INVALID_ROUTE_PREF;
			p_info->route_options = p_idrp_ps_atts;

			/* Reset for the next use. */
			p_idrp_ps_atts = (idrpRoute_options *) NULL;

			/* Tag p_info into the "global info" ps_info. */
			$6.adv->adv_result.ps_info = (void_t) p_info;
		}
		if ($5) {
			if (PARSE_METRIC_ISSET(pp) && PARSE_METRIC_ISRESTRICT(pp)) {
				parse_adv_propagate_idrp_restrict($5); 
			}

			/* put the auxiliary test(s) in place */
                	adv_list = $5;

			/* add $6.adv to the adv_list of $5's last element */
			FIND_ADV_LIST_END($5, adv_end);
			adv_end->adv_list = $6.adv;
		} else {
                	adv_list = $6.adv;
		}

                $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_RDI | ADVF_FIRST,
                                                          (proto_t) 0),
                                                $2,
                                                &$6.metric,
                                                adv_list);

                ISO_NET_FROM_SOCKUN(p_iso_net, $4);
                $$->adv_rdi = (struct iso_net_addr *)
                        idrp_local_mem_fit(sizeof(struct iso_net_addr));
                bzero((caddr_t) $$->adv_rdi->isoa_genaddr, ISO_MAXADDRLEN);
                bcopy(p_iso_net->isoa_genaddr, $$->adv_rdi->isoa_genaddr,
                        p_iso_net->isoa_len);
                $$->adv_rdi->isoa_len = p_iso_net->isoa_len;
                $$->adv_rdi->isoa_family = AF_ISO;
	}
    /* IDRP--RD paths */
        | T_PROTO rdpath_prop_init T_RDPATH rdpath_spec prop_metric_option_idrp
        {
                $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_RDPATH | ADVF_FIRST,
                                                          (proto_t) 0),
                                                $2,
                                                &$5.metric,
                                                $5.adv);
                $$->adv_rdpath = $4;
        }
	;

prop_metric_option_idrp
    	: T_RESTRICT
		{
		    PARSE_METRIC_RESTRICT(&$$.metric);
		    $$.adv = (adv_entry *) 0;
		}
	| metric_option prop_restrict_list_option_idrp
		{
		    $$.metric = $1;
		    $$.adv = $2;
		}
	;

prop_restrict_list_option_idrp
		:	/* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| '{' prop_restrict_list_idrp '}'
			{
			    $$ = adv_destmask_finish($2);
			}
		;
    
prop_restrict_list_idrp
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| prop_restrict_list_idrp prop_restrict_idrp L_EOS
			{
			    $$ = adv_destmask_insert(parse_error, $1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| prop_restrict_list_idrp error L_EOS
			{
			    yyerrok;
			}
		;

prop_restrict_idrp : prop_restrict_iso
@BEGIN:	PROTO_INET
		| T_IP prop_restrict_inet
		{ $$ = $2; }
@END:	PROTO_INET
		;
@END:	PROTO_IDRP

@BEGIN:	PROTO_ISO
prop_source_option_iso
    		: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| metric_option '{' prop_source_list_iso '}'
			{
			    $$.metric = $1;
			    $$.adv = $3;
			}
		;

prop_source_list_iso
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| prop_source_list_iso prop_source_iso L_EOS
			{
			    $$ = $1;
			    if (parse_adv_append(&$$, $2)) {
				PARSE_ERROR;
			    }
			}
		| prop_source_list_iso error L_EOS
			{
			    yyerrok;
			}
		;

prop_source_iso	: T_PROTO prop_direct interface_list_option prop_metric_option_iso
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
    /* Static routes */
		| T_PROTO prop_static interface_list_option prop_metric_option_iso
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
    /* Aggregate routes */
		| T_PROTO prop_aggregate prop_metric_option_iso
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}	
    /* Kernel static routes (routing socket) */
		| T_PROTO prop_kernel interface_list_option prop_metric_option_iso
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
@BEGIN:	PROTO_ISIS
    /* ISIS imports */
		| T_PROTO isis_prop_init prop_metric_option_iso
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}
@END:	PROTO_ISIS
		;

prop_metric_option_iso
    		: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| metric_option prop_restrict_list_option_iso
			{
			    $$.metric = $1;
			    $$.adv = $2;
			}
		;

prop_restrict_list_option_iso
		:	/* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| '{' prop_restrict_list_iso '}'
			{
			    $$ = adv_destmask_finish($2);
			}
		;
    

prop_restrict_list_iso
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| prop_restrict_list_iso prop_restrict_iso L_EOS
			{
			    $$ = adv_destmask_insert(parse_error, $1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| prop_restrict_list_iso error L_EOS
			{
			    yyerrok;
			}
		;

prop_restrict_iso
		:
			{
			    parse_contig_masks = FALSE;
			}
			dest_mask_iso metric_restrict_option
			{
			    parse_contig_masks = TRUE;

			    if ($2.dm_dest
				&& (socktype($2.dm_dest) != AF_ISO)) {
				sprintf(parse_error, "address not ISO");
				PARSE_ERROR
			    }

			    $$ = adv_alloc(ADVFT_DM, (proto_t) 0);
			    $$->adv_dm = $2;
			    if (PARSE_METRIC_ISRESTRICT(&$3)) {
				BIT_SET($$->adv_flag, ADVF_NO);
			    } else if (PARSE_METRIC_ISSET(&$3)) {
				$$->adv_result.res_metric = $3.metric;
				BIT_SET($$->adv_flag, ADVFOT_METRIC);
			    }
			}
		;

@END:	PROTO_ISO

@BEGIN:	PROTO_INET
prop_source_option_inet
    		: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| metric_option '{' prop_source_list_inet '}'
			{
			    $$.metric = $1;
			    $$.adv = $3;
			}
		;

prop_source_list_inet
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| prop_source_list_inet prop_source_inet L_EOS
			{
			    $$ = $1;
			    if (parse_adv_append(&$$, $2)) {
				PARSE_ERROR;
			    }
			}
		| prop_source_list_inet error L_EOS
			{
			    yyerrok;
			}
		;

prop_source_inet
    /* Interfaces */
		: T_PROTO prop_direct interface_list_option prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
    /* Static routes */
		| T_PROTO prop_static interface_list_option prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
    /* Aggregate routes */
		| T_PROTO prop_aggregate prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}	
    /* Kernel static routes (routing socket) */
		| T_PROTO prop_kernel interface_list_option prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
    /* Internal default route */
		| T_PROTO prop_default prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}
@BEGIN:	AUTONOMOUS_SYSTEM
		| T_PROTO proto_exterior T_AS as prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_AS | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$5.metric,
							    $5.adv);
			    $$->adv_as = $4;
			}
@END:	AUTONOMOUS_SYSTEM
@BEGIN:	PROTO_ASPATHS
    /* AS paths */
		| T_PROTO aspath_prop_init aspath_match prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ASPATH | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$4.metric,
							    $4.adv);
			    $$->adv_aspath = $3;
			}
    /* Tags */
    		| T_PROTO tag_prop_init T_TAG tag prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_TAG|ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$5.metric,
							    $5.adv);
			    $$->adv_tag = $4.metric;
			}
@END:	PROTO_ASPATHS
@BEGIN:	PROTO_RIP
    /* RIP Imports */
		| T_PROTO rip_prop_init interface_gateway_list prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
@END:	PROTO_RIP
@BEGIN:	PROTO_HELLO
    /* HELLO Imports */
		| T_PROTO hello_prop_init interface_gateway_list prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric($3, $2, &$4.metric, $4.adv);
			}
@END:	PROTO_HELLO
@BEGIN:	PROTO_OSPF
    /* OSPF imports */
		| T_PROTO ospf_prop_init prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}
		| T_PROTO ospf_ase_prop_init prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}
@END:	PROTO_OSPF
@BEGIN:	PROTO_SLSP
    /* SLSP imports */
		| T_PROTO slsp_prop_init prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}
@END:	PROTO_SLSP
@BEGIN:	PROTO_ISIS
    /* ISIS imports */
		| T_PROTO isis_prop_init prop_metric_option_inet
			{
			    $$ = parse_adv_propagate_metric(adv_alloc(ADVFT_ANY | ADVF_FIRST,
								      (proto_t) 0),
							    $2,
							    &$3.metric,
							    $3.adv);
			}
@END:	PROTO_ISIS
		;

prop_direct	: T_DIRECT
			{
			    $$ = parse_proto = RTPROTO_DIRECT;
			    parse_gwlist = (gw_entry **)0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

prop_static	: T_STATIC
			{
			    $$ = parse_proto = RTPROTO_STATIC;
			    parse_gwlist = &rt_gw_list;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

prop_aggregate	: T_AGGREGATE
			{
			    $$ = parse_proto = RTPROTO_AGGREGATE;
			    parse_gwlist = (gw_entry **) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

prop_kernel	: T_KERNEL
			{
			    $$ = parse_proto = RTPROTO_KERNEL;
			    parse_gwlist = &krt_gw_list;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

prop_default	: T_DEFAULT
			{
			    $$ = parse_proto = RTPROTO_DEFAULT;
			    parse_gwlist = (gw_entry **)0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PROTO: %s",
				      parse_where(),
				      gd_lower(trace_state(rt_proto_bits, $$))));
			}
		;

@BEGIN:	PROTO_INET
prop_metric_option_inet
    		: T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$.metric);
			    $$.adv = (adv_entry *) 0;
			}
		| metric_option prop_restrict_list_option_inet
			{
			    $$.metric = $1;
			    $$.adv = $2;
			}
		;

prop_restrict_list_option_inet
		:	/* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| '{' prop_restrict_list_inet '}'
			{
			    $$ = adv_destmask_finish($2);
			}
		;
    

prop_restrict_list_inet
		: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| prop_restrict_list_inet prop_restrict_inet L_EOS
			{
			    $$ = adv_destmask_insert(parse_error, $1, $2);
			    if ($$ == NULL) {
				PARSE_ERROR;
			    }
			}
		| prop_restrict_list_inet error L_EOS
			{
			    yyerrok;
			}
		;

prop_restrict_inet
		:
			{
			    parse_contig_masks = FALSE;
			}
			dest_mask_inet metric_restrict_option
			{
			    parse_contig_masks = TRUE;

			    if (($2.dm_dest != (sockaddr_un *) NULL)  
				&& (socktype($2.dm_dest) != AF_INET)) {
				sprintf(parse_error, "address not INET");
				PARSE_ERROR
			    }

			    $$ = adv_alloc(ADVFT_DM, (proto_t) 0);
			    $$->adv_dm = $2;
			    if (PARSE_METRIC_ISRESTRICT(&$3)) {
				BIT_SET($$->adv_flag, ADVF_NO);
			    } else if (PARSE_METRIC_ISSET(&$3)) {
				$$->adv_result.res_metric = $3.metric;
				BIT_SET($$->adv_flag, ADVFOT_METRIC);
			    }
			}
		;
@END:	PROTO_INET

/*  */

@BEGIN:	PROTO_INET

/* Addresses */

/* IP address */

dest_mask_inet	: all_mask_inet
		| default_mask_inet
		| host_mask_inet
		| network_mask_flags_inet
		;

all_mask_inet	: T_ALL
			{
			    $$.dm_dest = sockdup(inet_addr_default);
			    $$.dm_mask = inet_mask_default;
			    $$.dm_flags = (flag_t) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: all",
				      parse_where()));
			}
		;

default_mask_inet
		: T_DEFAULT
			{
			    $$.dm_dest = sockdup(inet_addr_default);
			    $$.dm_mask = inet_mask_default;
			    $$.dm_flags = (flag_t) DMF_EXACT;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A",
				      parse_where(),
				      $$.dm_dest));
			}
		;

/* Gateway list */
gateway_list_inet
		: gateway_inet
			{
			    $$ = adv_alloc(ADVFT_GW | ADVF_FIRST, (proto_t) 0);
			    $$->adv_gwp = $1;
			}
		| gateway_list_inet gateway_inet
			{
			    adv_entry *adv = adv_alloc(ADVFT_GW, (proto_t) 0);

			    adv->adv_gwp = $2;
			    $$ = $1;
			    if (parse_adv_append(&$$, adv)) {
				PARSE_ERROR;
			    }
			}
		;

/* A gateway is a host on an attached network */
gateway_inet	: host_inet
			{
			    /*
			     *	Make sure host is on a locally attached network then
			     *	find or create a gw structure for it.  Requires that
			     *	parse_proto and parse_gwlist are previously set
			     */
			    if (!if_parse_withdst($1)) {
				(void) sprintf(parse_error, "gateway not a host address on an attached network: '%A'",
					       $1);
				if (BIT_TEST(task_state, TASKS_STRICTIFS)) {
				    PARSE_ERROR;
				} else {
				    yyerror(parse_error);
				}
			    }
			    if (!parse_gwlist) {
				(void) sprintf(parse_error, "gateway specification not valid for %s",
					       trace_state(rt_proto_bits, parse_proto));
				PARSE_ERROR;
			    }
			    $$ = gw_locate(parse_gwlist,
					   parse_proto,
					   (task *) 0,
					   (as_t) 0,
					   (as_t) 0,
					   $1,
					   (flag_t) 0);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s GATEWAY: %A  PROTO: %s",
				      parse_where(),
				      $$->gw_addr,
				      gd_lower(trace_state(rt_proto_bits, $$->gw_proto))));
			    sockfree($1);
			}
		;

host_inet	: host_name
			{ 
			    sockaddr_un *addr;

			    if (BIT_TEST(task_state, TASKS_NORESOLV)
				|| !(addr = parse_addr_hostname($1.ptr))) {
				PARSE_ERROR;
			    }
			    $$ = sockdup(addr);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s HOST: %A",
				      parse_where(),
				      $$));
			    free_charstr(&$1);
			}
		| addr_inet
			{
			    $$ = $1;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s HOST: %A",
				      parse_where(),
				      $$));
			}
		;

host_mask_inet	: T_HOST host_inet
			{
			    $$.dm_dest = $2;
			    $$.dm_mask = inet_mask_host;
			    $$.dm_flags = DMF_EXACT;

			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A",
				      parse_where(),
				      $$.dm_dest));
			}
		;

network_inet	: host_name
			{
			    sockaddr_un *addr;

			    if (BIT_TEST(task_state, TASKS_NORESOLV)
				|| !(addr = parse_addr_netname($1.ptr))) {
				PARSE_ERROR;
			    }
			    $$ = sockdup(addr);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s NETWORK: %A",
				      parse_where(),
				      $$));
			    free_charstr(&$1);
			}
		| addr_inet
			{
			    $$ = $1;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s NETWORK: %A",
				      parse_where(),
				      $$));
			}
		;

network_mask_inet
		: network_inet
			{
			    $$.dm_dest = $1;
			    $$.dm_mask = inet_mask_natural($1);
			    $$.dm_flags = (flag_t) 0;
			    if (sock2ip($$.dm_dest) & ~sock2ip($$.dm_mask)) {
				sprintf(parse_error, "host or mask option needed");
				PARSE_ERROR;
			    }
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
		| network_inet T_MASKLEN number
			{
			    $$.dm_dest = $1;
			    if (parse_limit_check("inet mask bits",
						  (u_int) $3,
						  INET_LIMIT_MASKLEN)) {
				PARSE_ERROR;
			    }
			    $$.dm_mask = inet_masks[$3];
			    $$.dm_flags = (flag_t) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
		| network_inet T_MASK mask_inet
			{
			    register byte *ap = $1->a.sa_data;
			    register byte *mp = $3->a.sa_data;
			    register byte *alp = (byte *) $1 + socksize($1);
			    register byte *mlp = (byte *) $3 + socksize($3);

			    /* Skip zero fields */
			    while (!*ap && ap < alp) {
				ap++, mp++;
			    }
			    
			    while (ap < alp) {
				if (mp < mlp) {
				    if (*ap++ & ~*mp++) {
					break;
				    }
				} else {
				    if (*ap++) {
					break;
				    }
				}
			    }
			    if (ap < alp) {
				sprintf(parse_error, "Non-masked bits not zero for %A mask %A",
					$1,
					$3);
				PARSE_ERROR;
			    }

			    $$.dm_dest = $1;
			    $$.dm_mask = $3;
			    $$.dm_flags = (flag_t) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
		;

network_mask_flags_inet
		: network_mask_inet dm_flags
			{
			    $$ = $1;
			    $$.dm_flags = $2;
			}
		;

mask_inet	: in_addr
			{
			    $$ = inet_mask_locate($1.s_addr);
			    if ($$ == NULL) {
				if (parse_contig_masks) {
				    (void) sprintf(parse_error, "mask not contiguous");
				    PARSE_ERROR;
				} else {
				    $$ = mask_locate(sockbuild_in(0, $1.s_addr));
				}
			    }
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s MASK: %A",
				      parse_where(),
				      $$));
			}
		;


addr_inet	: in_addr
			{
			    $$ = sockdup(sockbuild_in(0, $1.s_addr));

			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s IP_ADDR: %A",
				      parse_where(),
				      $$));
			}
		;


in_addr		: L_NUMBER
			{
			    u_int32 addr = $1;
			    
			    if (addr) {
				/* Normalize the address */
				while (!(addr & 0xff000000)) {
				    addr <<= 8;
				}
			    }
			    $$.s_addr = htonl(addr);
			}
		| byte_string
			{
			    int i;
			    u_int32 addr = 0;

			    if ($1.len > sizeof(addr)) {
				sprintf(parse_error, "octet or hex string too long to be an IP address");
				PARSE_ERROR;
			    }

			    for (i = 0; i < sizeof(addr); i++) {
				addr <<= 8;
				if (i < $1.len) {
				    BIT_SET(addr, $1.ptr[i]);
				}
			    }
			    $$.s_addr = htonl(addr);
			    free_bytestr(&$1);
			}
		;

/* TTLs */
inet_ttl	: L_NUMBER
			{
			    if (parse_limit_check("ttl",
						  (u_int) $1,
						  INET_LIMIT_TTL)) {
				PARSE_ERROR;
			    }
			    $$ = $1;
			}
		;

@END:	PROTO_INET

/**/

@BEGIN:	PROTO_ISO

dest_mask_iso	: all_mask_iso
		| default_mask_iso
		| network_mask_flags_iso
		| host_mask_iso
		;

all_mask_iso	: T_ALL
			{
			    $$.dm_dest = sockdup(iso_addr_default);
			    $$.dm_mask = iso_masks[ISO_MAXADDRLEN*NBBY];
			    $$.dm_flags = (flag_t) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: iso all",
				      parse_where()));
			}
		;

default_mask_iso
		: T_DEFAULT
			{
			    $$.dm_dest = sockdup(iso_addr_default);
			    $$.dm_dest = iso_mask_natural(iso_addr_default);
			    $$.dm_flags = (flag_t) DMF_EXACT;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: iso all",
				      parse_where()));
			}
		;

/* Gateway list */
gateway_list_iso
		: gateway_iso
			{
			    $$ = adv_alloc(ADVFT_GW | ADVF_FIRST, (proto_t) 0);
			    $$->adv_gwp = $1;
			}
		| gateway_list_iso gateway_iso
			{
			    adv_entry *adv = adv_alloc(ADVFT_GW, (proto_t) 0);

			    adv->adv_gwp = $2;
			    $$ = $1;
			    if (parse_adv_append(&$$, adv)) {
				PARSE_ERROR;
			    }
			}
		;

/* A gateway is a host on an attached network */
gateway_iso	: host_iso
			{
			    /*
			     *	Make sure host is on a locally attached network then
			     *	find or create a gw structure for it.  Requires that
			     *	parse_proto and parse_gwlist are previously set
			     */
#ifdef 	KERNEL_SUPPORTS_ISO
			    if (!if_parse_withdst($1)) {
				(void) sprintf(parse_error, "gateway not a host address on an attached network: '%A'",
					       $1);
				if (BIT_TEST(task_state, TASKS_STRICTIFS)) {
				    PARSE_ERROR;
				} else {
				    yyerror(parse_error);
				}
			    }
			    if (!parse_gwlist) {
				(void) sprintf(parse_error, "gateway specification not valid for %s",
					       trace_state(rt_proto_bits, parse_proto));
				PARSE_ERROR;
			    }

#endif
			    $$ = gw_locate(parse_gwlist,
					   parse_proto,
					   (task *) 0,
					   (as_t) 0,
					   (as_t) 0,
					   $1,
					   (flag_t) 0);

			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s GATEWAY: %A  PROTO: %s",
				      parse_where(),
				      $$->gw_addr,
				      gd_lower(trace_state(rt_proto_bits, $$->gw_proto))));
			    sockfree($1);
			}
		;

host_iso	: addr_iso
			{
			    $$ = $1;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s HOST: %A",
				      parse_where(),
				      $$));
			}
		;

host_mask_iso	: T_HOST host_iso
			{
			    $$.dm_dest = $2;
			    $$.dm_mask = iso_mask_natural($2);
			    $$.dm_flags = DMF_EXACT;

			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A",
				      parse_where(),
				      $$.dm_dest));
			}
		;

network_iso	: addr_iso
			{
			    $$ = $1;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s NETWORK: %A",
				      parse_where(),
				      $$));
			}
		;

network_mask_iso
		: network_iso
			{
			    $$.dm_dest = $1;
			    $$.dm_mask = iso_mask_natural($1);
			    $$.dm_flags = (flag_t) 0;

			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
		| network_iso T_MASKLEN number
			{
			    $$.dm_dest = $1;
			    if (parse_limit_check("iso mask bits",
						  (u_int) $3,
						  ISO_LIMIT_MASKLEN)) {
				PARSE_ERROR;
			    }
			    $$.dm_mask = iso_masks[$3];
			    $$.dm_flags = (flag_t) 0;

			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
		| network_iso T_MASK mask_iso
			{
			    register byte *ap = $1->a.sa_data;
			    register byte *mp = $3->a.sa_data;
			    register byte *alp = (byte *) $1 + socksize($1);
			    register byte *mlp = (byte *) $3 + socksize($3);

			    /* Skip zero fields */
			    while (!*ap && ap < alp) {
				ap++, mp++;
			    }
			    
			    while (ap < alp) {
				if (mp < mlp) {
				    if (*ap++ & ~*mp++) {
					break;
				    }
				} else {
				    if (*ap++) {
					break;
				    }
				}
			    }
			    if (ap < alp) {
				sprintf(parse_error, "Non-masked bits not zero for %A mask %A",
					$1,
					$3);
				PARSE_ERROR;
			    }

			    $$.dm_dest = $1;
			    $$.dm_mask = $3;
			    $$.dm_flags = (flag_t) 0;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s DEST: %A MASK: %A",
				      parse_where(),
				      $$.dm_dest,
				      $$.dm_mask));
			}
		;

network_mask_flags_iso
		: network_mask_iso dm_flags
			{
			    $$ = $1;
			    $$.dm_flags = $2;
			}
		;

mask_iso	: addr_iso
			{
			    $$ = iso_mask_locate($1);
			    sockfree($1);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s MASK: %A",
				      parse_where(),
				      $$));
			}
		;

osi_hex: L_HEXSTRING
	{
	    if ($1.len > ISO_MAXADDRLEN) {
		sprintf(parse_error, "ISO address has too many bytes (%d), %d maximum",
			$1.len,
			ISO_MAXADDRLEN);
		PARSE_ERROR;
	    }
			    
	    $$ = sockdup(sockbuild_iso($1.ptr, $1.len));

	    trace_tf(trace_global,
		     TR_PARSE,
		     0,
		     ("parse: %s ADDR_ISO: %A",
		      parse_where(),
		      $$));

	    free_bytestr(&$1);
	}
	;

addr_iso: L_ISOADDR
	{
	    if ($1.len > ISO_MAXADDRLEN) {
		sprintf(parse_error, "ISO address has too many bytes (%d), %d maximum",
			$1.len,
			ISO_MAXADDRLEN);
			PARSE_ERROR;
	    }
		    
	    $$ = sockdup(sockbuild_iso($1.ptr, $1.len));

	    trace_tf(trace_global,
		     TR_PARSE,
		     0,
		     ("parse: %s ADDR_ISO: %A",
		      parse_where(),
		      $$));

	    free_bytestr(&$1);
	}
	;
@END:	PROTO_ISO

/* Common to both */

host		: T_NOP_SOCKADDR
			{
			    assert(FALSE);
			}
@BEGIN:	PROTO_INET
		| host_inet
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
		| host_iso
@END:	PROTO_ISO
		;

mask		: T_NOP_SOCKADDR
			{
			    assert(FALSE);
			}
@BEGIN:	PROTO_INET
		| mask_inet
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
		| mask_iso
@END:	PROTO_ISO
		;

addr		: T_NOP_SOCKADDR
			{
			    assert(FALSE);
			}
@BEGIN:	PROTO_INET
		| addr_inet
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
		| addr_iso
@END:	PROTO_ISO
		;

gateway_list	: T_NOP_ADV
			{
			    assert(FALSE);
			}
@BEGIN:	PROTO_INET
		| gateway_list_inet
@END:	PROTO_INET
@BEGIN:	PROTO_ISO
		| gateway_list_iso
@END:	PROTO_ISO
		;

dm_flags	: /* Empty */
			{
			    $$ = (flag_t) 0;
			}
		| T_EXACT
			{
			    $$ = DMF_EXACT;
			}
		| T_REFINE
			{
			    $$ = DMF_REFINE;
			}
		;


@END:	PROTO_INET

/* Host name */
host_name	: L_HNAME
			{
			    $$ = $1;
			    $$.ptr = task_mem_strdup((task *) 0, $1.ptr);
			}
		| L_KEYWORD
			{
			    $$ = $1;
			    $$.ptr = task_mem_strdup((task *) 0, $1.ptr);
			}
		| string
		;

/* Protocols */
proto_interior	: T_REDIRECT
			{
#if	defined(PROTO_ICMP) || defined(KRT_RT_SOCK)
			    $$.proto = RTPROTO_REDIRECT;
			    $$.import_list = &redirect_import_list;
			    $$.export_list = (adv_entry **) 0;
			    $$.gw_list = &redirect_gw_list;
#endif	/* defined(PROTO_ICMP) || defined(KRT_RT_SOCK) */
			}
@BEGIN:	PROTO_HELLO
		| T_HELLO
			{
			    $$.proto = RTPROTO_HELLO;
			    $$.import_list = &hello_import_list;
			    $$.export_list = &hello_export_list;
			    $$.gw_list = &hello_gw_list;
			}
@END:	PROTO_HELLO
@BEGIN:	PROTO_RIP
		| T_RIP
			{
			    $$.proto = RTPROTO_RIP;
			    $$.import_list = &rip_import_list;
			    $$.export_list = &rip_export_list;
			    $$.gw_list = &rip_gw_list;
			}
@END:	PROTO_RIP
		;


proto_exterior	: T_NOP_PROTO
			{
			    assert(FALSE);
			}
@BEGIN:	PROTO_EGP
		| egp_prop_init
@END:	PROTO_EGP
@BEGIN:	PROTO_BGP
		| bgp_prop_init
@END:	PROTO_BGP
		;

onoff_option	: T_ON		{ $$ = T_ON; }
		| T_OFF		{ $$ = T_OFF; }
		;

null_or_restrict : /* empty */
	{ $$ = T_ON; }
	| T_RESTRICT
	{ $$ = T_RESTRICT; }
	;


/* Metric */

metric		: number
			{
			    PARSE_METRIC_SET(&$$, $1);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s METRIC: %d",
				      parse_where(),
				      $$.metric));
			}
		| T_INFINITY
			{
			    PARSE_METRIC_INFINITY(&$$);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s METRIC: infinity",
				      parse_where()));
			}
		;

metric_option	: /* Empty */
			{
			    PARSE_METRIC_CLEAR(&$$);
			}
		| T_METRIC metric
			{
			    if (parse_metric_check(parse_export_proto, &$2)) {
				PARSE_ERROR;
			    }
			    $$ = $2;
			}
		;
		
metric_restrict_option
		: metric_option
			{
			    $$ = $1;
			}
		| T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$);
			}
		;
		
/* Preference */
preference_option
		: /* Empty */
			{
			    PARSE_METRIC_CLEAR(&$$);
			}
		| T_PREFERENCE preference
			{
			    PARSE_METRIC_SET(&$$, $2);
			}
		;

preference_restrict_option
		: preference_option
		| T_RESTRICT
			{
			    PARSE_METRIC_RESTRICT(&$$);
			}
		;

preference	: L_NUMBER
			{
			    if (parse_limit_check("preference",
						  (u_int) $1,
						  LIMIT_PREFERENCE)) {
				PARSE_ERROR;
			    }
			    $$ = $1;
			}
		;


/* Numbers and such */
string		: L_STRING
			{
			    /* Remove quotes from the string if present */
			    char *cp;

			    $$ = $1;
				
			    switch (*$$.ptr) {
			    case '<':
				*$$.ptr = '>';
				/* Fall through */

			    case '"':
				cp = &$$.ptr[$$.len-1];
				if (*cp == *$$.ptr) {
				    *cp = (char) 0;
				    $$.len -= 2;
				    cp = $$.ptr + 1;
				    break;
				}
				/* Fall Through */

			    default:
				cp = $$.ptr;
			    }

			    $$.ptr = task_mem_strdup((task *) 0, cp);
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s STRING: \"%s\" length: %d",
				      parse_where(),
				      $$.ptr,
				      $$.len));
			}
		;


number		: L_NUMBER
		| byte_string
			{
			    int i = 0;
			    int len = sizeof($$);

			    $$ = 0;
			    if ($1.len > len) {
				sprintf(parse_error, "octet or hex string too long to be a number");
				PARSE_ERROR;
			    } else if ($1.len < len) {
				len = $1.len;
			    }

			    while (i < len) {
				$$ = ($$ << 8) | $1.ptr[i++];
			    }
			    free_bytestr(&$1);
			}
		;


byte_string	: L_HEXSTRING
		| L_OCTETSTRING
		;

@BEGIN:	PARSE_UTIME
utime		: time '.' L_USEC
			{
			    $$.ut_sec = $1;
			    $$.ut_usec = $3;
			}
		;
@END:	PARSE_UTIME

time		: L_NUMBER
			{
			    if (parse_limit_check("seconds",
						  (u_int) $1,
						  LIMIT_NATURAL)) {
				PARSE_ERROR;
			    };
			    $$ = $1;
			}
		| L_NUMBER ':' L_NUMBER
			{
			    if (parse_limit_check("minutes",
						  (u_int) $1,
						  LIMIT_NATURAL)) {
				PARSE_ERROR;
			    }
			    if (parse_limit_check("seconds",
						  (u_int) $3,
						  LIMIT_SECONDS)) {
				PARSE_ERROR;
			    }
			    $$ = ($1 * 60) + $3;
			}
		| L_NUMBER ':' L_NUMBER ':' L_NUMBER
			{
			    if (parse_limit_check("hours",
						  (u_int) $1,
						  LIMIT_NATURAL)) {
				PARSE_ERROR;
			    }
			    if (parse_limit_check("minutes",
						  (u_int) $3,
						  LIMIT_MINUTES)) {
				PARSE_ERROR;
			    }
			    if (parse_limit_check("seconds",
						  (u_int) $5,
						  LIMIT_SECONDS)) {
				PARSE_ERROR;
			    }
			    $$ = (($1 * 60) + $3) * 60 + $5;
			}
		;

/* Internet ports */
@BEGIN:	PARSE_PORT
port		: L_NUMBER
			{
			    if (parse_limit_check("port",
						  (u_int) $1,
						  LIMIT_PORT)) {
				PARSE_ERROR;
			    }
			    $$ = htons($1);
			}
		| L_KEYWORD
			{
			    const struct servent *sp;

			    if (!(sp = getservbyname($1.ptr, parse_serv_proto))) {
				(void) sprintf(parse_error, "unknown protocol %s/%s",
					$1.ptr, parse_serv_proto);
				PARSE_ERROR;
			    }

			    $$ = sp->s_port;

			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("parse: %s PORT %s (%d)",
				      parse_where(),
				      $1.ptr,
				      ntohs($$)));
			}
		;
@END:	PARSE_PORT

/**/
@BEGIN:	AUTONOMOUS_SYSTEM
/* Autonomous systems */

as_loop_option	: /* Empty */
			{
			    $$ = 1;
			}
@BEGIN:	PROTO_ASPATHS
		| T_LOOPS L_NUMBER
			{
			    if (parse_limit_check("as loop limit",
						  (u_int) $2,
						  LIMIT_AS_LOOPS)) {
				PARSE_ERROR;
			    }
			    $$ = $2;
			}
@END:	PROTO_ASPATHS
		;


as		: L_NUMBER
			{
			    if (parse_limit_check("autonomous system",
						  (u_int) $1,
						  LIMIT_AS)) {
				PARSE_ERROR;
			    }
			    $$ = $1;
			}
		;

@BEGIN:	PARSE_ASLIST
as_list		: as
			{
			    $$ = adv_alloc(ADVFT_AS | ADVF_FIRST, (proto_t) 0);
			    $$->adv_as = $1;
			}
		| as_list as
			{
			    adv_entry *adv = adv_alloc(ADVFT_AS, (proto_t) 0);

			    adv->adv_as = $2;
			    $$ = $1;
			    if (parse_adv_append(&$$, adv)) {
				PARSE_ERROR;
			    }
			}
		;

as_list_option	: /* Empty */
			{
			    $$ = (adv_entry *) 0;
			}
		| T_AS as_list
			{
			    $$ = $2;
			}
		;
@END:	PARSE_ASLIST

@END:	AUTONOMOUS_SYSTEM
/**/
@BEGIN:	PROTO_ASPATHS
/* Tags */

/* Route tags */
tag_as_option
		: /* Empty */
			{
			    PARSE_METRIC_CLEAR(&$$);
			}
		| T_TAG tag_as
			{
			    $$ = $2;
			}
		;

tag_as		: tag
		| T_AS
			{
			    PARSE_METRIC_ALTERNATE(&$$, 0);
			}
		| T_AS number
			{
			    if (parse_limit_check("external-route-tag",
						  (u_int) $2,
						  PATH_OSPF_TAG_USR_LIMIT)) {
				PARSE_ERROR;
			    }
			    PARSE_METRIC_ALTERNATE(&$$, $2);
			}
		;

tag_option	: /* Empty */
			{
			    PARSE_METRIC_CLEAR(&$$);
			}
		| T_TAG tag
			{
			    $$ = $2;
			}
		;

tag	: number
			{
			    if (parse_limit_check("external-route-tag",
						  (u_int) $1,
						  PATH_OSPF_TAG_LIMIT)) {
				PARSE_ERROR;
			    }
			    PARSE_METRIC_SET(&$$, $1);
			}
/* XXX - various tag options */
		;

tag_prop_init
		: proto_exterior
@BEGIN:	PROTO_RIP
		| rip_prop_init 
@END:	PROTO_RIP
@BEGIN:	PROTO_HELLO
		| hello_prop_init 
@END:	PROTO_HELLO
@BEGIN:	PROTO_OSPF
		| ospf_prop_init
		| ospf_ase_prop_init
@END:	PROTO_OSPF
		;

/**/
/* AS paths */

aspath_prop_init
		: proto_exterior
@BEGIN:	PROTO_RIP
		| rip_prop_init 
@END:	PROTO_RIP
@BEGIN:	PROTO_HELLO
		| hello_prop_init 
@END:	PROTO_HELLO
@BEGIN:	PROTO_OSPF
		| ospf_prop_init
		| ospf_ase_prop_init
@END:	PROTO_OSPF
		;

aspath_match	: T_ASPATH
			{
			    aspath_init_regex();
			}
		aspath_regex T_ORIGIN aspath_origin
    			{
			    $$ = aspath_consume_current($3);
			    $$->origin_mask = $4;
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("%s: path %X origins %s",
				      parse_where(),
				      $$,
				      aspath_adv_origins($$->origin_mask)));
			}
    		;

aspath_origin :
			{
			    /* Set all bits on */
			    $$ = (flag_t) -1;
			}
		| T_ANY
			{
			    /* Set all bits on */
			    $$ = (flag_t) -1;
			}
		| aspath_origin_list
			{
			    $$ = $1;
			}
		;

aspath_origin_list
		: aspath_origins
		| aspath_origin_list '|' aspath_origins
			{
			    $$ = $1 | $3;
			}
		;

aspath_origins	: T_IGP
			{
			    $$ = (1 << PATH_ORG_IGP);
			}
		| T_EGP
			{
			    $$ = (1 << PATH_ORG_EGP);
			}
		| T_INCOMPLETE
    			{
			    $$ = (1 << PATH_ORG_XX);
			}
		;
    
aspath_regex	: aspath_sum
			{
			    aspath_simple_regex(&$$, &$1);
			}
		| aspath_regex '|' aspath_sum
			{
			    aspath_merge_regex(&$$, &$1, &$3);
			}
		;

aspath_sum	: aspath_term
			{
			    aspath_copy_regex(&$$, &$1);
			}
		| aspath_sum aspath_term
			{
			    if(!aspath_prepend_regex(&$$, &$1, &$2)) {
				YYERROR;
			    }
			}
		;

aspath_term	: aspath_symbol
			{
			    aspath_copy_regex(&$$, &$1);
			}
		| aspath_symbol '*'
			{
			    aspath_zero_or_more_term(&$$, &$1);
			}
		| aspath_symbol '+'
			{
			    aspath_one_or_more_term(&$$, &$1);
			}
		| aspath_symbol '?'
			{
			    aspath_zero_or_one_term(&$$, &$1);
			}
		| aspath_symbol '{' aspath_range '}'
			{
			    if (!aspath_range_term(&$$, &$1, &$3)) {
				sprintf(parse_error,
					"too many AS path regexp states");
				PARSE_ERROR;
			    }
			}
		;

aspath_symbol	: as
			{
			    if (!aspath_as_transition(&$$, $1)) {
				sprintf(parse_error,
					"too many AS path regexp states");
				PARSE_ERROR;
			    }
			}
		| '.'
			{
			    if (!aspath_any_transition(&$$)) {
				sprintf(parse_error,
					"too many AS path regexp states");
				PARSE_ERROR;
			    }
			}
		| '(' aspath_regex ')'
			{
			    aspath_copy_regex(&$$, &$2);
			}

aspath_range	: number
			{
			    $$.begin = $1;
			    $$.end = 0;
			    if (!$1) {
				sprintf(parse_error, "invalid range start: %d",
					$1);
				PARSE_ERROR;
			    }
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("%s: RANGE: {%d}",
				      parse_where(),
				      $$.begin));
			}
		| number ','
			{
			    $$.begin = $1;
			    $$.end = 1;
			    if (!$1) {
				sprintf(parse_error, "invalid range start: %d",
					$1);
				PARSE_ERROR;
			    }
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("%s: RANGE: {%d,}",
				      parse_where(),
				      $$.begin));
			}
		| number ',' number
			{
			    $$.begin = $1;
			    $$.end = $3;
			    if (!$1) {
				sprintf(parse_error, "invalid range start: %d",
					$1);
				PARSE_ERROR;
			    }
			    if ($3 < $1 || !$3) {
				sprintf(parse_error, "invalid range end: %d",
					$3);
				PARSE_ERROR;
			    }
			    trace_tf(trace_global,
				     TR_PARSE,
				     0,
				     ("%s: RANGE: {%d,%d}",
				      parse_where(),
				      $$.begin,
				      $$.end));
			}
		;
@END:	PROTO_ASPATHS
%%

/*
 *	Log any parsing errors
 */
static void
yyerror(s)
const char *s;
{
    byte *cp;

    tracef("parse: %s ",
	   parse_where());

    switch (yychar) {
    case L_HEXSTRING:
	tracef("%s at '",
	       s);
	for (cp = yylval.hex.ptr; (cp - yylval.hex.ptr) < yylval.hex.len; cp++) {
	    tracef("%02x",
		   *cp);
	}
	tracef("'");
	break;	

    case L_OCTETSTRING:
	tracef("%s at '",
	       s);
	for (cp = yylval.hex.ptr; (cp - yylval.hex.ptr) < yylval.hex.len; cp++) {
	    tracef("%s%u",
		   (cp == yylval.hex.ptr) ? "" : ".",
		   *cp);
	}
	tracef("'");
	break;	

    case L_NUMBER:
	tracef("%s at '%d'",
	       s,
	       yylval.num);
	break;

    case L_EOS:
	tracef("%s at 'end-of-statement'",
	       s);
	break;

    case L_ERROR:
	tracef("%s",
	       parse_error);
	break;

#ifdef	YYEOF
    case YYEOF:
#else	/* YYEOF */
    case 0:
#endif	/* YYEOF */
	tracef("%s at 'end-of-file'",
	       s);
	break;

    default:
	if (!parse_keyword_lookup(yychar)) {
#if	YYDEBUG != 0
#ifdef	YYTRANSLATE
	    tracef("%s at '%s'",
		   s,
		   yytname[YYTRANSLATE(yychar)]);
#else	/* YYTRANSLATE */
	    tracef("%s at '%s'",
		   s,
		   yyname[yychar]);
#endif	/* YYTRANSLATE */
#else	/* YYDEBUG */
	    tracef("%s",
		   s);
#endif	/* YYDEBUG */
	    break;
	}
	tracef("%s at '%s' (%u) length %d",
	       s,
	       yylval.str.ptr,
	       yylval.str.type,
	       yylval.str.len);
	break;

    case L_STRING:
    case L_HNAME:
    case L_KEYWORD:
	tracef("%s at '%s' length %d",
	       s,
	       yylval.str.ptr,
	       yylval.str.len);
	break;

#ifdef	YYEMPTY
    case YYEMPTY:
	tracef("%s",
	       s);
	break;
#endif	/* YYEMPTY */
    }
    trace_log_tf(trace_global,
		 TRC_NL_BEFORE|TRC_NL_AFTER,
		 LOG_ERR,
		 (NULL));
}



/*
 * ------------------------------------------------------------------------
 * 
 * 	GateD, Release 3.5
 * 
 * 	Copyright (c) 1990,1991,1992,1993,1994 by Cornell University
 * 	    All rights reserved.
 * 
 * 	THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY
 * 	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
 * 	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * 	AND FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * 	Royalty-free licenses to redistribute GateD Release
 * 	3 in whole or in part may be obtained by writing to:
 * 
 * 	    GateDaemon Project
 * 	    Information Technologies/Network Resources
 * 	    200 CCC
 * 	    Cornell University
 * 	    Ithaca, NY  14853-2601  USA
 * 
 * 	GateD is based on Kirton's EGP, UC Berkeley's routing
 * 	daemon	 (routed), and DCN's HELLO routing Protocol.
 * 	Development of GateD has been supported in part by the
 * 	National Science Foundation.
 * 
 * 	Please forward bug fixes, enhancements and questions to the
 * 	gated mailing list: gated-people@gated.cornell.edu.
 * 
 * ------------------------------------------------------------------------
 * 
 *       Portions of this software may fall under the following
 *       copyrights:
 * 
 * 	Copyright (c) 1988 Regents of the University of California.
 * 	All rights reserved.
 * 
 * 	Redistribution and use in source and binary forms are
 * 	permitted provided that the above copyright notice and
 * 	this paragraph are duplicated in all such forms and that
 * 	any documentation, advertising materials, and other
 * 	materials related to such distribution and use
 * 	acknowledge that the software was developed by the
 * 	University of California, Berkeley.  The name of the
 * 	University may not be used to endorse or promote
 * 	products derived from this software without specific
 * 	prior written permission.  THIS SOFTWARE IS PROVIDED
 * 	``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
 * 	INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * 	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
