This is parse.c in view mode; [Download] [Up]
/*
* $Header: /disk/d/src/devel/gated/dist/src/RCS/parse.c,v 2.1 92/02/24 14:12:47 jch Exp $
*/
/*%Copyright%*/
/************************************************************************
* *
* GateD, Release 2 *
* *
* Copyright (c) 1990,1991,1992 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 *
* 2 in whole or in part may be obtained by writing to: *
* *
* GateDaemon Project *
* Information Technologies/Network Resources *
* 143 Caldwell Hall *
* Cornell University *
* Ithaca, NY 14853-2602 *
* *
* GateD is based on Kirton's EGP, UC Berkeley's routing *
* daemon (routed), and DCN's HELLO routing Protocol. *
* Development of Release 2 has been supported by the *
* National Science Foundation. *
* *
* Please forward bug fixes, enhancements and questions to the *
* gated mailing list: gated-people@gated.cornell.edu. *
* *
* Authors: *
* *
* Jeffrey C Honig <jch@gated.cornell.edu> *
* Scott W Brim <swb@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. *
* *
************************************************************************/
#include "include.h"
#ifdef SYSV
#include <dirent.h>
#endif /* SYSV */
#include "parse.h"
#include "parser.h"
#include "rip.h"
#include "hello.h"
#include "egp.h"
#include "bgp.h"
#include "snmp.h"
static int n_keywords;
/*
* Table of keywords recognized. This table is sorted at runtime
* to facilitate binary searching.
*/
static bits keywords[] =
{
{T_INTERFACE, "interface"},
{T_INTERFACE, "intf"},
{T_DIRECT, "direct"},
{T_PROTO, "protocol"},
{T_PROTO, "proto"},
{T_METRIC, "metric"},
{T_LEX, "lex"},
{T_PARSE, "yacc"},
{T_PARSE, "parse"},
{T_CONFIG, "config"},
{T_DEFAULT, "default"},
{T_INCLUDE, "include"},
{T_DIRECTORY, "directory"},
#if YYDEBUG != 0
{T_YYDEBUG, "yydebug"},
{T_YYSTATE, "yystate"},
{T_YYQUIT, "yyquit"},
#endif /* YYDEBUG */
{T_ON, "on"},
{T_ON, "yes"},
{T_OFF, "off"},
{T_OFF, "no"},
{T_QUIET, "quiet"},
{T_POINTOPOINT, "pointopoint"},
{T_POINTOPOINT, "pointtopoint"},
{T_POINTOPOINT, "p2p"},
{T_SUPPLIER, "supplier"},
{T_GATEWAY, "gateway"},
{T_GATEWAY, "gw"},
{T_PREFERENCE, "preference"},
{T_PREFERENCE, "pref"},
{T_DEFAULTMETRIC, "defaultmetric"},
#if defined(PROTO_EGP) || defined(PROTO_BGP)
{T_NEIGHBOR, "neighbor"},
{T_NEIGHBOR, "peer"},
{T_ASIN, "asin"},
{T_ASOUT, "asout"},
{T_METRICOUT, "metricout"},
{T_VERSION, "version"},
{T_GENDEFAULT, "gendefault"},
{T_NOGENDEFAULT, "nogendefault"},
{T_DEFAULTIN, "acceptdefault"},
{T_DEFAULTOUT, "propagatedefault"},
#endif /* defined(PROTO_EGP) || defined(PROTO_BGP) */
#ifdef PROTO_EGP
{T_EGP, "egp"},
{T_GROUP, "group"},
{T_MAXUP, "maxup"},
{T_SOURCENET, "sourcenet"},
{T_P1, "p1"},
{T_P1, "minhello"},
{T_P2, "p2"},
{T_P2, "minpoll"},
{T_PKTSIZE, "packetsize"},
{T_PKTSIZE, "packet-size"},
#endif /* PROTO_EGP */
#ifdef PROTO_BGP
{T_BGP, "bgp"},
{T_LINKTYPE, "linktype"},
{T_INTERNAL, "internal"},
{T_HORIZONTAL, "horizontal"},
{T_HOLDTIME, "holdtime"},
#endif /* PROTO_BGP */
#if defined(PROTO_RIP) || defined(PROTO_HELLO)
{T_TRUSTEDGATEWAYS, "trustedgateways"},
{T_SOURCEGATEWAYS, "sourcegateways"},
#endif /* defined(PROTO_RIP) || defined(PROTO_HELLO) */
#ifdef PROTO_RIP
{T_RIP, "rip"},
{T_NORIPOUT, "noripout"},
{T_NORIPIN, "noripin"},
#endif /* PROTO_RIP */
#ifdef PROTO_HELLO
{T_HELLO, "hello"},
{T_NOHELLOOUT, "nohelloout"},
{T_NOHELLOIN, "nohelloin"},
#endif /* PROTO_HELLO */
#ifdef PROTO_ICMP
{T_ICMP, "icmp"},
{T_NOICMPIN, "noicmpin"},
#endif /* PROTO_ICMP */
#if defined(PROTO_ICMP) || defined(RTM_ADD)
{T_REDIRECT, "redirect"},
{T_REDIRECT, "redirects"},
#endif /* defined(PROTO_ICMP) || defined(RTM_ADD) */
#ifdef AGENT_SNMP
{T_SNMP, "snmp"},
#endif /* AGENT_SNMP */
{T_PASSIVE, "passive"},
{T_STATIC, "static"},
{T_ANNOUNCE, "announce"},
{T_NOANNOUNCE, "noannounce"},
{T_LISTEN, "listen"},
{T_NOLISTEN, "nolisten"},
{T_MARTIANS, "martians"},
{T_AS, "as"},
{T_AS, "autonomoussystem"},
{T_AS, "autonomous-system"},
{T_PROPAGATE, "propagate"},
{T_ACCEPT, "accept"},
{T_RESTRICT, "restrict"},
{T_NORESTRICT, "norestrict"},
{T_MASK, "mask"},
{T_OPTIONS, "options"},
{T_NOINSTALL, "noinstall"},
{T_TRACEOPTIONS, "traceoptions"},
{T_TRACEFILE, "tracefile"},
{T_REPLACE, "replace"},
{T_ALL, "all"},
{T_NONE, "none"},
{T_GENERAL, "general"},
{T_EXTERNAL, "external"},
{T_ROUTE, "route"},
{T_UPDATE, "update"},
{T_KERNEL, "kernel"},
{T_TASK, "task"},
{T_TIMER, "timer"},
{T_NOSTAMP, "nostamp"},
{T_MARK, "mark"},
{0, NULL}
};
/*
* A string of alpha characters which is either a keyword or a host/network name.
* First do a binary search (Knuth 6.2.1) to lookup up a keyword, if it is not found
* assume it is a host/network name. The proper thing to do is a REJECT, but flex
* won't optimize if we use a REJECT.
*/
int
parse_keyword(yytext)
char *yytext;
{
int c;
bits *i, *l, *u, *p = (bits *) 0;
l = keywords;
u = &keywords[n_keywords - 1];
do {
i = (u - l) / 2 + l;
c = strcasecmp(yytext, i->t_name);
if (!c) {
p = i;
break;
} else if (c < 0) {
u = i - 1;
} else {
l = i + 1;
}
} while (u >= l);
return (p ? p->t_bits : UNKNOWN);
}
/*
* Look up a token name given it's ID in the keyword table. There is no way to select
* between multiple keywords mapping to the same token once the table is sorted.
*/
const char *
parse_keyword_lookup(token)
int token;
{
bits *p;
static char invalid_string[2];
static bits special_keywords[] =
{
{EOS, "end-of-statement"},
{UNKNOWN, "unknown-keyword"},
{0, NULL}
};
if (token > 0 && token < 257 /* XXX - ASCII dependency here*/ ) {
*invalid_string = token;
return (invalid_string);
}
for (p = keywords; p->t_name; p++) {
if (token == p->t_bits) {
return (p->t_name);
}
}
for (p = special_keywords; p->t_name; p++) {
if (token == p->t_bits) {
return (p->t_name);
}
}
return ((char *) 0);
}
/*
* A comparison routine used by the sorting routine that follows
*/
static int
parse_keyword_sort_compare(p1, p2)
bits *p1, *p2;
{
return (strcasecmp(p1->t_name, p2->t_name));
}
/*
* Quicksort the table of keywords to insure that they are in order, easier
* than trying to keep the source sorted and less prone to mistakes.
*
* The sort is only done the first time we are called, i.e. when n_keyword is
* zero.
*/
static void
parse_keyword_sort()
{
bits *p;
if (!n_keywords) {
/* Calculate size of table */
for (p = keywords; p->t_name; p++, n_keywords++) ;
qsort((caddr_t) keywords, n_keywords, sizeof(bits), parse_keyword_sort_compare);
}
}
/*
* Front end for yyparse(). Exit if any errors
*/
int
parse_parse(file)
const char *file;
{
int errors;
extern int yynerrs;
static int first_parse = TRUE;
if (first_parse) {
parse_keyword_sort(); /* Sort the keyword table */
}
parse_directory = parse_strdup(task_path_name);
sethostent(1);
setnetent(1);
errors = parse_open(parse_strdup(file));
if (!errors) {
protos_seen = (proto_t) 0;
parse_state = PS_DEFINE;
errors = yyparse();
}
errors += yynerrs;
endhostent();
endnetent();
if (errors) {
trace(TR_ALL, 0, NULL);
trace(TR_ALL, LOG_ERR, "parse_parse: %d parse error%s", errors, errors > 1 ? "s" : "");
trace(TR_ALL, 0, NULL);
}
if (parse_directory) {
(void) free(parse_directory);
parse_directory = (char *) 0;
}
first_parse = FALSE;
return (errors);
}
/*
* Duplicate a string and return pointer
*/
char *
parse_strdup(s)
char *s;
{
char *cp;
cp = (char *) malloc((u_int) (strlen(s) + 1));
if (!cp) {
trace(TR_ALL, LOG_ERR, "parse_strdup: %s malloc: %m",
parse_where());
quit(errno);
}
(void) strcpy(cp, s);
return (cp);
}
/*
* Format a message indicating the current line number and return
* a pointer to it.
*/
char *
parse_where()
{
static char where[BUFSIZ];
if (parse_filename) {
(void) sprintf(where, "%s:%d",
parse_filename,
yylineno);
} else {
(void) sprintf(where, "%d",
yylineno);
}
return (where);
}
/*
* Limit check a number
*/
int
parse_limit_check(type, value, lower, upper)
const char *type;
int value;
int lower;
int upper;
{
if ((value < lower) || ((upper != -1) && (value > upper))) {
(void) sprintf(parse_error, "invalid %s value at '%d'",
type,
value);
return (1);
}
trace(TR_PARSE, 0, "parse: %s %s: %d",
parse_where(),
type,
value);
return (0);
}
/* Translate a u_long IP address into a sockaddr_in */
void
parse_addr_long(sockaddr, addr)
sockaddr_un *sockaddr;
u_long addr;
{
sockclear_in(sockaddr);
sockaddr->in.sin_addr.s_addr = addr;
trace(TR_PARSE, 0, "parse: %s IP_ADDR: %A",
parse_where(),
sockaddr);
}
/*
* Look up a string as a host or network name, returning it's IP address
* in normalized network byte order. Also recognizes a network name of
* "default", translating to network 0.
*/
int
parse_addr_hname(addr, hname, host_ok, net_ok)
sockaddr_un *addr;
char *hname;
int host_ok, net_ok;
{
u_long network;
struct netent *netent;
struct hostent *hostent;
int net_unknown = TRUE;
const char *errmsg = 0;
#ifdef HOST_NOT_FOUND
extern int h_errno;
extern int h_nerr;
extern char *h_errlist[];
h_errno = HOST_NOT_FOUND;
#endif /* HOST_NOT_FOUND */
if (net_ok) {
netent = getnetbyname(hname);
if (netent) {
if (netent->n_addrtype != AF_INET) {
/* XXX - Should we pretend it does not exist if it is not an INET name? */
(void) sprintf(parse_error, "network not INET at '%s'",
hname);
return (1);
}
network = netent->n_net;
if (network) {
while (!(network & 0xff000000)) {
network <<= 8;
}
}
parse_addr_long(addr, htonl(network));
return (0);
#ifdef HOST_NOT_FOUND
} else {
errmsg = "Unknown network";
net_unknown = TRUE;
#endif /* HOST_NOT_FOUND */
}
}
if (host_ok) {
hostent = gethostbyname(hname);
if (hostent) {
if (hostent->h_addrtype != AF_INET) {
/* XXX - Should we pretend it does not exist if it is not an INET name? */
(void) sprintf(parse_error, "host not INET at '%s'",
hname);
return (1);
}
#ifdef h_addr
if (hostent->h_addr_list[1]) {
/* XXX - For a gateway we could use just the address on our network if there was only one */
(void) sprintf(parse_error, "host has multiple addresses at '%s'",
hname);
return (1);
}
#endif /* h_addr */
memcpy((caddr_t) & network, hostent->h_addr, sizeof(network));
parse_addr_long(addr, network);
return (0);
} else {
#ifdef HOST_NOT_FOUND
if ((!h_errno || (h_errno == HOST_NOT_FOUND)) && net_unknown) {
errmsg = "Unknown host/network";
} else if (h_errno && (h_errno < h_nerr)) {
errmsg = h_errlist[h_errno];
} else {
errmsg = "Unknown host";
}
#else /* HOST_NOT_FOUND */
if (net_unknown) {
errmsg = "Unknown host/network";
} else {
errmsg = "Unknown host";
}
#endif /* HOST_NOT_FOUND */
}
}
(void) sprintf(parse_error, "error resolving '%s': %s",
hname,
errmsg);
return (1);
}
/*
* Append an advlist to another advlist
*/
adv_entry *
parse_adv_append(old, new, free)
adv_entry *old, *new;
int free;
{
adv_entry *alo, *aln, *last = NULL;
/* Add this network to the end of the list */
if (old) {
for (alo = old; alo; alo = alo->adv_next) {
if (!alo->adv_next) {
last = alo;
}
/* Scan list for duplicates */
for (aln = new; aln; aln = aln->adv_next) {
if ((aln->adv_flag & ADVF_TYPE) != (alo->adv_flag & ADVF_TYPE)) {
continue;
}
switch (aln->adv_flag & ADVF_TYPE) {
case ADVF_TANY:
break;
case ADVF_TGW:
if (aln->adv_gwp == alo->adv_gwp) {
(void) sprintf(parse_error, "duplicate gateway in list at '%A'",
&aln->adv_gwp->gw_addr);
return ((adv_entry *) 0);
}
break;
case ADVF_TINTF:
if (aln->adv_ifp == alo->adv_ifp) {
(void) sprintf(parse_error, "duplicate interface in list at '%A'",
(aln->adv_ifp->int_state & IFS_POINTOPOINT) ?
&aln->adv_ifp->int_dstaddr :
&aln->adv_ifp->int_addr);
return ((adv_entry *) 0);
}
break;
case ADVF_TAS:
if (aln->adv_as == alo->adv_as) {
(void) sprintf(parse_error, "duplicate autonomous-system in list at '%u'",
aln->adv_as);
return ((adv_entry *) 0);
}
break;
case ADVF_TDM:
/* XXX - make sure same address family */
if (equal(&aln->adv_dm.dm_dest, &alo->adv_dm.dm_dest) &&
equal(&aln->adv_dm.dm_mask, &alo->adv_dm.dm_mask)) {
(void) sprintf(parse_error, "duplicate dest and mask in list at '%A mask %A'",
&aln->adv_dm.dm_dest,
&aln->adv_dm.dm_mask);
return ((adv_entry *) 0);
}
break;
}
}
}
last->adv_next = new;
} else {
old = new;
}
if (new) {
/* XXX - bump the refcount, then free it? */
for (aln = new; aln; aln = aln->adv_next) {
aln->adv_refcount++;
}
if (free) {
adv_free_list(new);
}
}
return (old);
}
/*
* Set a flag in the gw structure for each element in a list
*/
int
parse_gw_flag(list, proto, flag)
adv_entry *list;
proto_t proto;
flag_t flag;
{
int n = 0;
adv_entry *adv;
for (adv = list; adv; adv = adv->adv_next) {
adv->adv_gwp->gw_flags |= flag;
adv->adv_gwp->gw_proto = proto;
n++;
}
return (n);
}
/*
* Display an adv entry
*/
void
parse_adv_entry(list)
adv_entry *list;
{
int first = TRUE;
adv_entry *adv;
if (list) {
if (list->adv_proto) {
tracef("proto %s ",
gd_lower(trace_bits(rt_proto_bits, list->adv_proto)));
}
adv = list;
do {
switch (adv->adv_flag & ADVF_TYPE) {
case ADVF_TDM:
/* XXX - should not happen */
case ADVF_TANY:
break;
case ADVF_TGW:
tracef("%s%A ",
first ? "gateway " : "",
&adv->adv_gwp->gw_addr);
break;
case ADVF_TINTF:
tracef("%s%A(%s) ",
first ? "interface " : "",
(adv->adv_ifp->int_state & IFS_POINTOPOINT) ?
&adv->adv_ifp->int_dstaddr :
&adv->adv_ifp->int_addr,
adv->adv_ifp->int_name);
break;
case ADVF_TAS:
tracef("%s%d ",
first ? "as " : "",
adv->adv_as);
break;
}
first = FALSE;
} while ((adv = adv->adv_next) && !(adv->adv_flag & ADVF_FIRST));
switch (list->adv_flag & ADVF_OTYPE) {
case ADVF_OTNONE:
break;
case ADVF_OTMETRIC:
tracef("metric %d ", list->adv_metric);
break;
case ADVF_OTPREFERENCE:
tracef("preference %d ", list->adv_preference);
break;
}
}
}
/*
* Display a dest_mask list
*/
void
parse_adv_destmask(dest, name1, name2)
adv_entry *dest;
const char *name1, *name2;
{
adv_entry *adv;
if (dest) {
ADV_LIST(dest, adv) {
tracef("parse: %s%s%s%.*s %A mask %A",
parse_where(),
name1,
(adv->adv_flag & ADVF_NO) ? "no" : "",
name2 ? strlen(name2) : 0,
name2,
&adv->adv_dm.dm_dest,
&adv->adv_dm.dm_mask);
switch (adv->adv_flag & ADVF_OTYPE) {
case ADVF_OTNONE:
break;
case ADVF_OTMETRIC:
tracef(" metric %d", adv->adv_metric);
break;
case ADVF_OTPREFERENCE:
tracef(" preference %d", adv->adv_preference);
break;
}
trace(TR_CONFIG, 0, " ;");
} ADV_LISTEND;
}
}
/*
* Append to an existing list
*/
void
parse_adv_list(name1, name2, list, dest)
const char *name1, *name2;
adv_entry *list, *dest;
{
if (trace_flags & TR_CONFIG) {
tracef("parse: %s\t%s ",
parse_where(),
name1);
parse_adv_entry(list);
trace(TR_CONFIG, 0, "{");
parse_adv_destmask(dest, "\t\t", name2);
trace(TR_CONFIG, 0, "parse: %s\t} ;",
parse_where());
}
}
/*
* Display a propagate clause
*/
void
parse_adv_prop_list(list)
adv_entry *list;
{
adv_entry *adv;
if (list) {
if (trace_flags & TR_CONFIG) {
tracef("parse: %s\tpropagate ",
parse_where());
parse_adv_entry(list);
trace(TR_CONFIG, 0, " {");
adv = list->adv_list;
if (adv) {
do {
tracef("parse: %s\t\t",
parse_where());
parse_adv_entry(adv);
if (adv->adv_list) {
trace(TR_CONFIG, 0, "{");
parse_adv_destmask(adv->adv_list, "\t\t\t", "announce");
tracef("parse: %s\t\t}",
parse_where());
}
trace(TR_CONFIG, 0, " ;");
do {
adv = adv->adv_next;
} while (adv && !(adv->adv_flag & ADVF_FIRST));
} while (adv);
}
trace(TR_CONFIG, 0, "parse: %s\t} ;",
parse_where());
}
}
}
/*
* Set interface struct with parsed values
*/
static void
parse_interface_set(ifp)
if_entry *ifp;
{
ifp->int_state |= parse_flags;
if (parse_metric > 0) {
ifp->int_metric = parse_metric;
}
if (parse_preference) {
ifp->int_preference = parse_preference;
}
if_display("parse", ifp);
}
/* Set interface flags on specified interface list or all interfaces */
void
parse_interface(list)
adv_entry *list;
{
if_entry *ifp;
adv_entry *adv;
if (list) {
for (adv = list; adv; adv = adv->adv_next) {;
parse_interface_set(adv->adv_ifp);
}
adv_free_list(list);
} else {
IF_LIST(ifp) {
parse_interface_set(ifp);
} IF_LISTEND(ifp) ;
}
}
/*
* Switch to a new state if it is a valid progression from
* the current state
*/
int
parse_new_state(state)
int state;
{
static const char *states[] =
{
"define",
"protocol",
"route",
"control"
};
if (state < parse_state) {
(void) sprintf(parse_error, "statement out of order");
return (1);
} else if (state > parse_state) {
parse_state = state;
trace(TR_PARSE, 0, "parse_new_state: %s %s",
parse_where(),
states[parse_state]);
}
return (0);
}
int
parse_metric_check(proto, metric)
proto_t proto;
int metric;
{
const char *string;
int limit_low, limit_high;
switch (proto) {
#ifdef PROTO_RIP
case RTPROTO_RIP:
string = "RIP metric";
limit_low = LIMIT_RIP_LOW;
limit_high = LIMIT_RIP_HIGH;
break;
#endif /* PROTO_RIP */
#ifdef PROTO_HELLO
case RTPROTO_HELLO:
string = "HELLO metric";
limit_low = LIMIT_HELLO_LOW;
limit_high = LIMIT_HELLO_HIGH;
break;
#endif /* PROTO_HELLO */
#ifdef PROTO_EGP
case RTPROTO_EGP:
string = "EGP metric";
limit_low = LIMIT_EGP_LOW;
limit_high = LIMIT_EGP_HIGH;
break;
#endif /* PROTO_EGP */
#ifdef PROTO_BGP
case RTPROTO_BGP:
string = "BGP metric";
limit_low = LIMIT_BGP_LOW;
limit_high = LIMIT_BGP_HIGH;
break;
#endif /* PROTO_BGP */
case RTPROTO_DIRECT:
string = "interface metric";
limit_low = LIMIT_INTERFACE_LOW;
limit_high = LIMIT_INTERFACE_HIGH;
break;
default:
(void) sprintf(parse_error, "parse_metric_check: invalid protocol %x",
proto);
return (1);
}
return (parse_limit_check(string, metric, limit_low, limit_high));
}
/*
* Set metric for each element in list that does not have one
*/
adv_entry *
parse_adv_propagate(list, proto, metric, advlist)
adv_entry *list;
proto_t proto;
metric_t metric;
adv_entry *advlist;
{
adv_entry *adv;
for (adv = list; adv; adv = adv->adv_next) {
adv->adv_proto = proto;
adv->adv_list = advlist;
if (metric >= 0) {
adv->adv_flag |= ADVF_OTMETRIC;
adv->adv_metric = metric;
}
}
return (list);
}
/*
* Set preference for each elmit in list that does not have one
*/
void
parse_adv_preference(list, proto, preference)
adv_entry *list;
proto_t proto;
pref_t preference;
{
for (; list; list = list->adv_next) {
if ((list->adv_flag & ADVF_OTYPE) == ADVF_OTNONE) {
list->adv_proto = proto;
list->adv_flag |= ADVF_OTPREFERENCE;
list->adv_preference = preference;
}
}
}
/*
* Return a pointer to a duplicate of this adv_entry
*/
adv_entry *
parse_adv_dup(old)
adv_entry *old;
{
adv_entry *new = NULL, *adv, *root;
root = NULL;
for (; old; old = old->adv_next) {
adv = adv_alloc(old->adv_flag, old->adv_proto);
memcpy((caddr_t) adv, (caddr_t) old, sizeof(*adv));
if (!root) {
root = adv;
} else {
new->adv_next = adv;
}
if (adv->adv_list) {
adv->adv_list->adv_refcount++;
}
new = adv;
}
return (root);
}
/*
* If the pointed to table of adv lists for interfaces does not
* exist, create it.
*/
adv_entry **
parse_adv_interface(list)
adv_entry ***list;
{
if (!*list) {
*list = (adv_entry **) calloc((u_int) (int_index_max + 1), sizeof(adv_entry));
if (!*list) {
trace(TR_ALL, LOG_ERR, "parse_adv_interface: calloc %m");
quit(errno);
}
}
return (*list);
}
/*
* Lookup the entry in the list for the exterior protocol and append this list to it.
*/
int
parse_adv_ext(advlist, adv)
adv_entry **advlist;
adv_entry *adv;
{
adv_entry *list;
ADV_LIST(*advlist, list) {
if (adv->adv_as == list->adv_as) {
break;
}
} ADV_LISTEND;
if (!list) {
list = adv_alloc(ADVF_TAS, adv->adv_proto);
list->adv_as = adv->adv_as;
*advlist = parse_adv_append(*advlist, list, TRUE);
if (!*advlist) {
return (0);
}
}
list->adv_list = parse_adv_append(list->adv_list, adv, TRUE);
if (!list->adv_list) {
return (0);
}
return (1);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.