This is bgp_init.c in view mode; [Download] [Up]
/*
* $Header: /disk/d/src/devel/gated/dist/src/RCS/bgp_init.c,v 2.1 92/02/24 14:12:25 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"
#ifndef vax11c
#include <sys/file.h>
#endif /* vax11c */
#include "bgp.h"
#ifdef PROTO_BGP
int doing_bgp = FALSE; /* Is BGP active? */
pref_t bgp_preference = RTPREF_BGP; /* Preference for BGP routes */
u_short bgp_port; /* Well known BGP port */
metric_t bgp_default_metric = bgpMetricInfinity; /* Default metric if no announce clauses specified */
bgpPeer *bgp_peers; /* Linked list of BGP peers */
int bgp_n_peers; /* Number of BGP peers */
bgpPdu *bgp_send_buffer; /* Send buffer */
adv_entry *bgp_accept_list = NULL; /* List of BGP advise entries */
adv_entry *bgp_propagate_list = NULL; /* List of BGP propagate entries */
static timer *bgp_flash_timer = (timer *) 0;
static time_t bgp_next_flash = (time_t) 0;
int notifyLengths[BGPERRCD_MAX + 1] =
{
0,
BGPERRLEN_LINKTYPE,
BGPERRLEN_AUTHCODE,
BGPERRLEN_AUTHFAIL,
BGPERRLEN_UPDATE,
BGPERRLEN_SYNC,
BGPERRLEN_MSGLEN,
BGPERRLEN_MSGTYPE,
BGPERRLEN_VERSION,
BGPERRLEN_OPENAS
};
bits bgpFlags[] =
{
{BGPF_HEADER, "Header"},
{BGPF_DELETE, "Delete"},
{BGPF_WAIT, "Wait"},
{BGPF_GENDEFAULT, "GenDefault"},
{0}
};
bits bgpOptions[] =
{
{BGPO_METRICOUT, "MetricOut"},
{BGPO_ASIN, "AsIn"},
{BGPO_ASOUT, "AsOut"},
{BGPO_NOGENDEFAULT, "NoGenDefault"},
{BGPO_GATEWAY, "Gateway"},
{BGPO_PREFERENCE, "Preference"},
{BGPO_INTERFACE, "Interface"},
{BGPO_LINKTYPE, "LinkType"},
{BGPO_HOLDTIME, "HoldTime"},
{0}
};
bits bgpStates[] =
{
{0, "Invalid"},
{BGPSTATE_IDLE, "Idle"},
{BGPSTATE_ACTIVE, "Active"},
{BGPSTATE_CONNECT, "Connect"},
{BGPSTATE_OPENSENT, "OpenSent"},
{BGPSTATE_OPENCONFIRM, "Confirm"},
{BGPSTATE_ESTABLISHED, "Established"},
{0}
};
bits bgpEvents[] =
{
{0, "Invalid"},
{BGPEVENT_START, "Start"},
{BGPEVENT_OPEN, "Open"},
{BGPEVENT_CLOSED, "Closed"},
{BGPEVENT_OPENFAIL, "OpenFail"},
{BGPEVENT_RECVOPEN, "RecvOpen"},
{BGPEVENT_RECVCONFIRM, "RecvConfirm"},
{BGPEVENT_RECVKEEPALIVE, "RecvKeepAlive"},
{BGPEVENT_RECVUPDATE, "RecvUpdate"},
{BGPEVENT_RECVNOTIFY, "RecvNotify"},
{BGPEVENT_HOLDTIME, "HoldTime"},
{BGPEVENT_KEEPALIVE, "KeepAlive"},
{BGPEVENT_CEASE, "Cease"},
{BGPEVENT_STOP, "Stop"},
{0}
};
bits bgpAsDirs[] =
{
{0, "Invalid"},
{asDirUp, "Up"},
{asDirDown, "Down"},
{asDirHorizontal, "Horizontal"},
{asDirEgp, "Egp"},
{asDirIncomplete, "Incomplete"},
{0}
};
bits bgpOpenType[] =
{
{openLinkInternal, "Internal"},
{openLinkUp, "Up"},
{openLinkDown, "Down"},
{openLinkHorizontal, "Horizontal"},
{0}
};
bits bgpPduType[] =
{
{0, "Invalid"},
{bgpPduOpen, "Open"},
{bgpPduUpdate, "Update"},
{bgpPduNotify, "Notify"},
{bgpPduKeepAlive, "KeepAlive"},
{bgpPduOpenConfirm, "OpenConfirm"},
{0}
};
bits bgpErrors[] =
{
{0, NULL},
{BGPERRCD_LINKTYPE, "link type error in open"},
{BGPERRCD_AUTHCODE, "unknown authentication code"},
{BGPERRCD_AUTHFAIL, "authentication failure"},
{BGPERRCD_UPDATE, "update error"},
{BGPERRCD_SYNC, "connection out of sync"},
{BGPERRCD_MSGLEN, "invalid message length"},
{BGPERRCD_MSGTYPE, "invalid message type"},
{BGPERRCD_VERSION, "invalid version number"},
{BGPERRCD_OPENAS, "invalid AS field in Open"},
{BGPERRCD_CEASE, "BGP neighbor Cease"},
};
bits bgpUpdateErrors[] =
{
{0, NULL},
{BGPUPDERR_ASCOUNT, "Invalid AS count"},
{BGPUPDERR_DIRECTION, "Invalid Direction code"},
{BGPUPDERR_AS, "Invalid AS"},
{BGPUPDERR_ORDER, "Terminal Direction in middle of path"},
{BGPUPDERR_LOOP, "Routing loop detected"},
{BGPUPDERR_GATEWAY, "Invalid Gateway"},
{BGPUPDERR_NETCOUNT, "Invalid Network count"},
{BGPUPDERR_NETWORK, "Invalid Network"}
};
/* We have a socket, create the task */
void
bgp_session_init(bnp, bgp_socket)
bgpPeer *bnp;
int bgp_socket;
{
struct sockaddr_in addr;
int addrlen = socksize(&addr);
if (getpeername(bgp_socket, (struct sockaddr *) & addr, &addrlen) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_session_init: getpeername(%d): %m",
bgp_socket);
} else {
IF_BGPPROTO trace(TR_BGP, 0, "bgp_session_init: peer %s socket %d is connected to %A",
bnp->bgp_name,
bgp_socket,
&addr);
}
bnp->bgp_task->task_recv = bgp_read;
task_set_socket(bnp->bgp_task, bgp_socket);
if (task_set_option(bnp->bgp_task, TASKOPTION_NONBLOCKING, (caddr_t) TRUE) < 0) {
quit(errno);
}
if (task_set_option(bnp->bgp_task, TASKOPTION_RECVBUF, (caddr_t) (32 * 1024)) < 0) {
quit(errno);
}
if (task_set_option(bnp->bgp_task, TASKOPTION_SENDBUF, (caddr_t) (32 * 1024)) < 0) {
quit(errno);
}
if (if_withdst((sockaddr_un *) & bnp->bgp_addr) && task_set_option(bnp->bgp_task, TASKOPTION_DONTROUTE, (caddr_t) TRUE) < 0) {
quit(errno);
}
(void) timer_create(bnp->bgp_task, BGPTIMER_KEEPALIVE, "KeepAlive", 0, (time_t) 0, bgp_event_KeepAlive);
}
/* Close the socket and delete the task */
void
bgp_session_finit(bnp, quick)
bgpPeer *bnp;
int quick;
{
IF_BGPPROTO trace(TR_BGP, 0, "bgp_session_finit: peer %s",
bnp->bgp_name);
if (!quick) {
if (task_set_option(bnp->bgp_task, TASKOPTION_LINGER, (caddr_t) BGP_CLOSE_TIMER) < 0) {
quit(errno);
}
}
if (close(bnp->bgp_task->task_socket) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_session_finit: close: %m");
}
task_reset_socket(bnp->bgp_task);
timer_delete(bnp->bgp_task->task_timer[BGPTIMER_KEEPALIVE]);
}
/*
* Clean up when connect has completed
*/
void
bgp_connect_finit(bnp)
bgpPeer *bnp;
{
task_reset_socket(bnp->bgp_task);
timer_delete(bnp->bgp_task->task_timer[BGPTIMER_CONNECT]);
}
/*
* Connect has completed or failed
*/
void
bgp_connect_complete(tp)
task *tp;
{
int length;
int bgp_socket = tp->task_socket;
struct sockaddr_in addr;
bgpPeer *bnp = (bgpPeer *) tp->task_data;
tracef("bgp_connect_complete: peer %s state %s ",
bnp->bgp_name,
trace_state(bgpStates, bnp->bgp_state));
length = socksize(&addr);
if (getpeername(tp->task_socket, (struct sockaddr *) & addr, &length) < 0) {
trace(TR_EXT, 0, "Connection error: %m");
if (close(bnp->bgp_task->task_socket) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_connect_complete: close(%d): %m",
bnp->bgp_task->task_socket);
quit(errno);
}
bgp_connect_finit(bnp);
bgp_event_OpenFail(bnp);
} else {
trace(TR_BGP, 0, "Connection established with %A",
&addr);
bgp_connect_finit(bnp);
bgp_session_init(bnp, bgp_socket);
bgp_event_Open(bnp);
}
}
void
bgp_connect_start(bnp)
bgpPeer *bnp;
{
int bgp_socket;
struct sockaddr_in addr;
IF_BGPPROTO trace(TR_BGP, 0, "bgp_connect_start: peer %s",
bnp->bgp_name);
if ((bgp_socket = task_get_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
quit(errno);
}
bnp->bgp_task->task_flags |= TASKF_CONNECT;
bnp->bgp_task->task_connect = bgp_connect_complete;
task_set_socket(bnp->bgp_task, bgp_socket);
if (task_set_option(bnp->bgp_task, TASKOPTION_NONBLOCKING, (caddr_t) TRUE) < 0) {
quit(errno);
}
if (task_set_option(bnp->bgp_task, TASKOPTION_REUSEADDR, (caddr_t) TRUE) < 0) {
quit(errno);
}
/* There are problems with the linger_close if you bind the local */
/* address */
addr = bnp->bgp_interface->int_addr.in; /* struct copy */
#ifdef notdef
addr.sin_port = bgp_port;
#else
addr.sin_port = 0; /* leave port wildcarded, should work okay */
#endif /* notdef */
if (bind(bgp_socket, &addr, socksize(&addr)) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_connect_start: bind %A: %m",
&addr);
quit(errno);
}
if (connect(bgp_socket, (struct sockaddr *) & bnp->bgp_addr, socksize(&bnp->bgp_addr)) < 0) {
int log_level = LOG_WARNING;
int trace_level = TR_BGP | TR_TASK;
switch (errno) {
case EINPROGRESS:
log_level = 0;
if (!(trace_flags & TR_PROTOCOL)) {
trace_level = 0;
}
/* Fall Thru */
case ENETDOWN:
case ENETUNREACH:
case EHOSTDOWN:
case EHOSTUNREACH:
case EADDRINUSE:
trace(trace_level, log_level, "bgp_connect_start: connect %A: %m",
&bnp->bgp_addr);
timer_set(bnp->bgp_task->task_timer[BGPTIMER_CONNECT], (time_t) BGP_WAIT_RETRY);
break;
default:
trace(TR_ALL, LOG_ERR, "bgp_connect_start: connect %A: %m",
&bnp->bgp_addr);
quit(errno);
}
} else {
IF_BGPPROTO trace(TR_BGP, 0, "bgp_connect_start: connect %A succeded",
&bnp->bgp_addr);
bgp_connect_complete(bnp->bgp_task);
}
}
/*
* Close the current socket and start a new connect by calling bgp_connect_start()
*/
/*ARGSUSED*/
void
bgp_connect_job(tip, interval)
timer *tip;
time_t interval;
{
task *tp = tip->timer_task;
bgpPeer *bnp = (bgpPeer *) tp->task_data;
IF_BGPPROTO trace(TR_BGP, 0, "bgp_connect_job: %s",
timer_name(tip));
if (close(tp->task_socket) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_connect_job: close(%d): %m",
tp->task_socket);
quit(errno);
}
task_reset_socket(tp);
bgp_connect_start(bnp);
}
/*
* Initialize for connecting to peer.
*/
void
bgp_connect_init(bnp)
bgpPeer *bnp;
{
(void) timer_create(bnp->bgp_task, BGPTIMER_CONNECT, "Connect", 0, (time_t) 0, bgp_connect_job);
bgp_connect_start(bnp);
}
/*ARGSUSED*/
void
bgp_do_flash(tp, interval)
task *tp;
time_t interval;
{
bgpPeer *bnp;
trace(TR_TASK, 0, "bgp_do_flash: Doing flash update for BGP");
BGP_LIST(bnp) {
if (bnp->bgp_state == BGPSTATE_ESTABLISHED) {
bgp_send_update(bnp, TRUE);
}
} BGP_LISTEND;
bgp_flash_timer = (timer *) 0;
bgp_next_flash = (time_t) BGP_FLASH_INTERVAL + time_sec;
trace(TR_TASK, 0, "bgp_do_flash: Flash update done, none before %T", bgp_next_flash);
}
/*
* Check to see if a flash update packet is allowed and send or schedule it
*/
void
bgp_flash(tp)
task *tp;
{
if (time_sec >= bgp_next_flash) {
/* A flash update can be sent now, do it */
bgp_do_flash(tp, (time_t) 0);
} else if (!bgp_flash_timer) {
/* A flash update can't be sent and one is not yet scheduled */
bgp_flash_timer = timer_create(tp, 0, "Flash", TIMERF_DELETE | TIMERF_ABSOLUTE, bgp_next_flash - time_sec, bgp_do_flash);
}
}
/*
* Process an incoming connection
*/
void
bgp_listen_accept(tp)
task *tp;
{
int bgp_socket;
int addrlen;
struct sockaddr_in addr;
bgpPeer *bnp;
addrlen = socksize(&addr);
if ((bgp_socket = accept(tp->task_socket, (struct sockaddr *) & addr, &addrlen)) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_listen_accept: accept(%d): %m", tp->task_socket);
quit(errno);
}
if (addrlen != socksize(&addr)) {
trace(TR_ALL, LOG_ERR, "bgp_listen_accept: incorrect address length, ignoring connection");
(void) close(bgp_socket);
return;
}
if (addr.sin_family != AF_INET) {
trace(TR_ALL, LOG_ERR, "bgp_listen_accept: ignoring non-inet connection request");
(void) close(bgp_socket);
return;
}
BGP_LIST(bnp) {
if (equal_in(bnp->bgp_addr.sin_addr, addr.sin_addr)) {
switch (bnp->bgp_state) {
case BGPSTATE_IDLE:
case BGPSTATE_OPENSENT:
case BGPSTATE_OPENCONFIRM:
case BGPSTATE_ESTABLISHED:
trace(TR_EXT, LOG_NOTICE, "bgp_listen_accept: peer %s state %s rejecting connection",
bnp->bgp_name,
trace_state(bgpStates, bnp->bgp_state));
(void) close(bgp_socket);
break;
case BGPSTATE_CONNECT:
/* Prevent the active connect from succeding */
if (close(bnp->bgp_task->task_socket) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_connect_complete: close(%d): %m",
bnp->bgp_task->task_socket);
quit(errno);
}
bgp_connect_finit(bnp);
case BGPSTATE_ACTIVE:
bgp_session_init(bnp, bgp_socket);
bgp_event_Open(bnp);
}
break;
}
} BGP_LISTEND;
if (!bnp) {
trace(TR_EXT, LOG_NOTICE, "bgp_listen_accept: rejecting connection from unknown peer %A",
&addr);
(void) close(bgp_socket);
}
}
/*
* Cleanup before re-parse
*/
/*ARGSUSED*/
static void
bgp_cleanup(tp)
task *tp;
{
bgp_default_metric = bgpMetricInfinity;
bgp_preference = RTPREF_BGP;
adv_free_list(bgp_accept_list);
bgp_accept_list = (adv_entry *) 0;
adv_free_list(bgp_propagate_list);
bgp_propagate_list = (adv_entry *) 0;
}
/*
* Setup to catch incoming connections
*/
void
bgp_listen_init()
{
int bgp_socket;
static task *bgp_task = (task *) 0;
struct sockaddr_in addr;
int on = 1;
if (doing_bgp && !bgp_task) {
sockclear_in(&addr);
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = bgp_port;
if ((bgp_socket = task_get_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
quit(errno);
}
if (setsockopt(bgp_socket, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(int)) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_listen_init: setsockopt: %m");
quit(errno);
}
if (bind(bgp_socket, (struct sockaddr *) & addr, socksize(&addr)) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_listen_init: bind %A: %m",
&addr);
quit(errno);
}
if (listen(bgp_socket, 5) < 0) {
trace(TR_ALL, LOG_ERR, "bgp_listen_init: listen: %m");
quit(errno);
}
bgp_task = task_alloc("BGP_listen");
bgp_task->task_flags = TASKF_ACCEPT;
sockcopy(&addr, &bgp_task->task_addr);
bgp_task->task_socket = bgp_socket;
bgp_task->task_rtproto = RTPROTO_BGP;
bgp_task->task_accept = bgp_listen_accept;
bgp_task->task_cleanup = bgp_cleanup;
bgp_task->task_flash = bgp_flash; /* Flash updates handled here */
bgp_task->task_dump = bgp_dump;
if (!task_create(bgp_task, 0)) {
quit(EINVAL);
}
} else if (!doing_bgp && bgp_task) {
task_delete(bgp_task);
bgp_task = (task *) 0;
}
}
/*
* Receive from socket
*/
int
bgp_recv(tp)
task *tp;
{
int count, length;
bgpPeer *bnp = (bgpPeer *) tp->task_data;
length = bnp->bgp_length - bnp->bgp_length_accumulated;
errno = 0;
count = recv(tp->task_socket, bnp->bgp_readpointer, length, 0);
if (count > 0) {
bnp->bgp_length_accumulated += count;
bnp->bgp_readpointer += count;
trace(TR_TASK, 0, "bgp_recv: peer %s received %d bytes (%d of %d so far)",
bnp->bgp_name,
count,
bnp->bgp_length_accumulated,
bnp->bgp_length);
} else if (count < 0) {
int log_level = LOG_WARNING;
int trace_level = TR_BGP | TR_TASK;
switch (errno) {
case EWOULDBLOCK:
log_level = 0;
/* Fall Thru */
case ENETDOWN:
case ENETUNREACH:
case EHOSTDOWN:
case EHOSTUNREACH:
count = 0;
break;
default:
trace_level = TR_ALL;
log_level = LOG_ERR;
}
trace(trace_level, log_level, "bgp_recv: peer %s recv: %m",
bnp->bgp_name);
} else {
trace(TR_EXT, LOG_ERR, "bgp_recv: peer %s recv: End of File (Connection Closed)",
bnp->bgp_name);
/* Count is zero - end of file */
count = -1;
}
return (count);
}
/*
* Delete a peer
*/
static void
bgp_delete(bnp)
bgpPeer *bnp;
{
if (bnp == bgp_peers) {
bgp_peers = bnp->bgp_next;
} else {
bgpPeer *bnp2;
BGP_LIST(bnp2) {
if (bnp2->bgp_next == bnp) {
bnp2->bgp_next = bnp->bgp_next;
break;
}
} BGP_LISTEND;
}
bgp_n_peers--;
(void) free((caddr_t) bnp);
}
/*
* Clean up and shut down
*/
static void
bgp_terminate(tp)
task *tp;
{
bgpPeer *bnp = (bgpPeer *) tp->task_data;
bgp_event_Stop(bnp);
timer_delete(tp->task_timer[BGPTIMER_HOLDTIME]);
task_delete(tp);
bgp_delete(bnp);
}
/*
* Cleanup for a peer
*/
static void
bgp_peer_cleanup(tp)
task *tp;
{
bgpPeer *bnp = (bgpPeer *) tp->task_data;
bnp->bgp_flags |= BGPF_DELETE;
adv_cleanup((int *) 0, (int *) 0, (gw_entry *) 0,
&bnp->bgp_accept, &bnp->bgp_propagate,
(adv_entry ***) 0, (adv_entry ***) 0);
}
/*
* Reinit a peer
*/
static void
bgp_peer_reinit(tp)
task *tp;
{
bgpPeer *bnp = (bgpPeer *) tp->task_data;
if (!doing_bgp || (bnp->bgp_flags & BGPF_DELETE)) {
bnp->bgp_flags |= BGPF_DELETE;
bgp_terminate(tp);
} else {
/* Issue a start event for Idle peers */
switch (bnp->bgp_state) {
case BGPSTATE_IDLE:
case BGPSTATE_ACTIVE:
bgp_event_Start(bnp);
break;
case BGPSTATE_CONNECT:
case BGPSTATE_OPENSENT:
case BGPSTATE_OPENCONFIRM:
case BGPSTATE_ESTABLISHED:
break;
}
/* Locate our new policy */
if (bnp->bgp_asin) {
/* If the AS isn't valid now, the correct policy will be located */
/* when the AS becomes valid */
bnp->bgp_accept = control_exterior_locate(bgp_accept_list, bnp->bgp_asin);
bnp->bgp_propagate = control_exterior_locate(bgp_propagate_list, bnp->bgp_asin);
}
}
}
void
bgp_init()
{
bgpPeer *bnp;
if_entry *ifp;
struct servent *sp;
struct sockaddr_in addr;
if (doing_bgp) {
if ((sp = getservbyname("bgp", "tcp")) == NULL) {
trace(TR_ALL, LOG_ERR, "bgp_init: getservbyname(bgp, tcp): %m - using port %d",
IPPROTO_BGP);
bgp_port = htons(IPPROTO_BGP);
} else {
bgp_port = sp->s_port;
}
sockclear_in(&addr);
addr.sin_port = bgp_port;
BGP_LIST(bnp) {
if (!bnp->bgp_task) {
if (!(bnp->bgp_options & BGPO_INTERFACE)) {
if (!(bnp->bgp_options & BGPO_GATEWAY)) {
sockcopy(&bnp->bgp_addr, &addr);
} else {
addr = bnp->bgp_gateway; /* struct copy */
}
ifp = if_withdst((sockaddr_un *) & addr);
if (ifp) {
bnp->bgp_interface = ifp;
} else if (!(bnp->bgp_options & BGPO_GATEWAY)) {
/* If we only have one interface, use it */
ifp = NULL;
if (n_interfaces == 1) {
IF_LIST(ifp) {
if (!(ifp->int_state & IFS_LOOPBACK)) {
bnp->bgp_interface = ifp;
break;
}
} IF_LISTEND(ifp) ;
}
if (!ifp) {
trace(TR_INT, LOG_ERR, "bgp_init: Can't determine interface for peer %s", bnp->bgp_name);
quit(EDESTADDRREQ);
}
} else {
trace(TR_INT, LOG_ERR, "bgp_init: no direct net to gateway %s", bnp->bgp_name);
quit(EDESTADDRREQ);
}
}
/* If AsOut was not specified, default to my_system */
if (!(bnp->bgp_options & BGPO_ASOUT)) {
bnp->bgp_asout = my_system;
}
if (bnp->bgp_options & BGPO_ASIN) {
bnp->bgp_accept = control_exterior_locate(bgp_accept_list, bnp->bgp_asin);
bnp->bgp_propagate = control_exterior_locate(bgp_propagate_list, bnp->bgp_asin);
}
/* If HoldTime is not specified, assume default */
if (!(bnp->bgp_options & BGPO_HOLDTIME)) {
bnp->bgp_holdtime_out = BGP_KEEP_ALIVE;
}
/* If link type is not specifed, Horizontal is assumed if */
/* the incoming and outgoing AS are different. If they */
/* are the same, Internal is the default. */
if (!(bnp->bgp_options & BGPO_LINKTYPE)) {
if ((bnp->bgp_options & BGPO_ASIN) && (bnp->bgp_asin == bnp->bgp_asout)) {
bnp->bgp_linktype = openLinkInternal;
} else {
bnp->bgp_linktype = openLinkHorizontal;
}
trace(TR_BGP, LOG_INFO, "bgp_init: peer %s - link type not specified, assuming %s",
bnp->bgp_name,
trace_state(bgpOpenType, bnp->bgp_linktype));
}
if (!(bnp->bgp_options & BGPO_PREFERENCE)) {
bnp->bgp_preference = bgp_preference;
}
/* If the link type is internal, the protocol is IBGP and */
/* the default preference is different. The protocol is */
/* not set here though, it is set when the task is */
/* allocated. */
if (bnp->bgp_linktype == openLinkInternal) {
if (!(bnp->bgp_options & BGPO_PREFERENCE)) {
bnp->bgp_preference = RTPREF_IBGP;
}
}
/* Initially in the Idle state */
bnp->bgp_state = BGPSTATE_IDLE;
/* Create the abort timer task */
bnp->bgp_task = task_alloc("BGP");
bnp->bgp_addr.sin_port = bgp_port;
bnp->bgp_task->task_addr.in = bnp->bgp_addr; /* struct copy */
bnp->bgp_task->task_rtproto = RTPROTO_BGP;
bnp->bgp_task->task_terminate = bgp_terminate;
bnp->bgp_task->task_cleanup = bgp_peer_cleanup;
bnp->bgp_task->task_reinit = bgp_peer_reinit;
bnp->bgp_task->task_data = (caddr_t) bnp;
if (!task_create(bnp->bgp_task, 0)) {
quit(EINVAL);
}
/* The hold timer is used to start a connect after a few seconds */
(void) timer_create(bnp->bgp_task,
BGPTIMER_HOLDTIME,
"Holdtime",
TIMERF_ABSOLUTE,
(time_t) BGP_IDLE_INIT,
bgp_event_Holdtime);
}
} BGP_LISTEND;
if (!test_flag) {
/* Listen for incoming connections */
bgp_listen_init();
if ((bgp_send_buffer = (bgpPdu *) malloc(BGPMAXPACKETSIZE)) == NULL) {
trace(TR_ALL, LOG_ERR, "bgp_init: malloc send buffer: %m");
}
}
} else {
/* BGP is not running, but it may have been. Delete all peers that do not have tasks */
BGP_LIST(bnp) {
if (!bnp->bgp_task) {
bgp_delete(bnp);
}
} BGP_LISTEND;
bgp_cleanup((task *) 0);
bgp_listen_init();
}
}
#endif /* PROTO_BGP */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.