X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/43d0275f6d62a5895864526bd590a3ead097bc7f..8e5be4e9ec35061c6bfd4a0fea78d63f386d4705:/bgp.c?ds=inline

diff --git a/bgp.c b/bgp.c
index 4404484..9f64d39 100644
--- a/bgp.c
+++ b/bgp.c
@@ -10,7 +10,7 @@
  *   nor RFC2385 (which requires a kernel patch on 2.4 kernels).
  */
 
-char const *cvs_id_bgp = "$Id: bgp.c,v 1.3 2004/08/13 00:02:50 fred_nerk Exp $";
+char const *cvs_id_bgp = "$Id: bgp.c,v 1.9 2004/12/16 08:49:52 bodea Exp $";
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -31,11 +31,10 @@ static void bgp_clear(struct bgp_peer *peer);
 static void bgp_set_retry(struct bgp_peer *peer);
 static void bgp_cidr(in_addr_t ip, in_addr_t mask, struct bgp_ip_prefix *pfx);
 static struct bgp_route_list *bgp_insert_route(struct bgp_route_list *head,
-	struct bgp_route_list *new);
+    struct bgp_route_list *new);
 
 static void bgp_free_routes(struct bgp_route_list *routes);
-static char const *bgp_state_str(enum bgp_state state);
-static char const *bgp_msg_type_str(u8 type);
+static char const *bgp_msg_type_str(uint8_t type);
 static int bgp_connect(struct bgp_peer *peer);
 static int bgp_handle_connect(struct bgp_peer *peer);
 static int bgp_write(struct bgp_peer *peer);
@@ -44,310 +43,330 @@ static int bgp_handle_input(struct bgp_peer *peer);
 static int bgp_send_open(struct bgp_peer *peer);
 static int bgp_send_keepalive(struct bgp_peer *peer);
 static int bgp_send_update(struct bgp_peer *peer);
-static int bgp_send_notification(struct bgp_peer *peer, u8 code, u8 subcode);
+static int bgp_send_notification(struct bgp_peer *peer, uint8_t code,
+    uint8_t subcode);
 
-static u16 our_as;
+static uint16_t our_as;
+static struct bgp_route_list *bgp_routes = 0;
+
+int bgp_configured = 0;
+struct bgp_peer *bgp_peers = 0;
 
 /* prepare peer structure, globals */
 int bgp_setup(int as)
 {
-	int i;
-	struct bgp_peer *peer;
+    int i;
+    struct bgp_peer *peer;
 
-	for (i = 0; i < BGP_NUM_PEERS; i++)
-	{
-		peer = &bgp_peers[i];
-		memset(peer, 0, sizeof(*peer));
+    for (i = 0; i < BGP_NUM_PEERS; i++)
+    {
+	peer = &bgp_peers[i];
+	memset(peer, 0, sizeof(*peer));
 
-		peer->addr = INADDR_NONE;
-		peer->sock = -1;
-		peer->state = peer->next_state = Disabled;
+	peer->addr = INADDR_NONE;
+	peer->sock = -1;
+	peer->state = peer->next_state = Disabled;
 
-		if (!((peer->outbuf = malloc(sizeof(*peer->outbuf))) && (peer->inbuf = malloc(sizeof(*peer->inbuf)))))
-		{
-			log(0, 0, 0, 0, "Can't allocate buffers for bgp peer (%s)\n",
-				strerror(errno));
+	if (!((peer->outbuf = malloc(sizeof(*peer->outbuf)))
+	    && (peer->inbuf = malloc(sizeof(*peer->inbuf)))))
+	{
+	    LOG(0, 0, 0, "Can't allocate buffers for bgp peer (%s)\n",
+		strerror(errno));
 
-			return 0;
-		}
+	    return 0;
 	}
+    }
 
-	if (as < 1)
-			as = 0;
+    if (as < 1)
+    	as = 0;
 
-	if ((our_as = as))
-			return 0;
+    if ((our_as = as))
+    	return 0;
 
-	bgp_routes = 0;
-	bgp_configured = 0; /* set by bgp_start */
+    bgp_routes = 0;
+    bgp_configured = 0; /* set by bgp_start */
 
-	return 1;
+    return 1;
 }
 
 /* start connection with a peer */
-int bgp_start(struct bgp_peer *peer, char *name, int as, int enable)
+int bgp_start(struct bgp_peer *peer, char *name, int as, int keepalive,
+    int hold, int enable)
 {
-	struct hostent *h;
-	int ibgp;
-	int i;
-	struct bgp_path_attr a;
-	char path_attrs[64];
-	char *p = path_attrs;
-	in_addr_t ip;
-	u32 metric = htonl(BGP_METRIC);
-	u32 no_export = htonl(BGP_COMMUNITY_NO_EXPORT);
-
-	if (!our_as)
-		return 0;
-
-	if (peer->state != Disabled)
-		bgp_halt(peer);
-
-	snprintf(peer->name, sizeof(peer->name), "%s", name);
-
-	if (!(h = gethostbyname(name)) || h->h_addrtype != AF_INET)
-	{
-		log(0, 0, 0, 0, "Can't get address for BGP peer %s (%s)\n", name, h ? "no address" : hstrerror(h_errno));
-
-		return 0;
-	}
-
-	memcpy(&peer->addr, h->h_addr, sizeof(peer->addr));
-	peer->as = as > 0 ? as : our_as;
-	ibgp = peer->as == our_as;
-
-	/* clear buffers, go to Idle state */
-	peer->next_state = Idle;
-	bgp_clear(peer);
-
-	/* set initial routing state */
-	peer->routing = enable;
-
-	/* all our routes use the same attributes, so prepare it in advance */
-	if (peer->path_attrs)
-			free(peer->path_attrs);
-
-	peer->path_attr_len = 0;
-
-	/* ORIGIN */
-	a.flags = BGP_PATH_ATTR_FLAG_TRANS;
-	a.code = BGP_PATH_ATTR_CODE_ORIGIN;
-	a.data.s.len = 1;
-	a.data.s.value[0] = BGP_PATH_ATTR_CODE_ORIGIN_IGP;
-
-#define ADD_ATTRIBUTE()				do { \
-	i = BGP_PATH_ATTR_SIZE(a);		\
-	memcpy(p, &a, i); 				\
-	p += i; 						\
-	peer->path_attr_len += i;		} while (0)
-
-	ADD_ATTRIBUTE();
-
-	/* AS_PATH */
-	a.flags = BGP_PATH_ATTR_FLAG_TRANS;
-	a.code = BGP_PATH_ATTR_CODE_AS_PATH;
-	if (ibgp)
-	{
-		/* empty path */
-		a.data.s.len = 0;
-	}
-	else
-	{
-		/* just our AS */
-		struct {
-			u8 type;
-			u8 len;
-			u16 value;
-		} as_path = {
-			BGP_PATH_ATTR_CODE_AS_PATH_AS_SEQUENCE,
-			1,
-			htons(our_as),
-		};
-
-		a.data.s.len = sizeof(as_path);
-		memcpy(&a.data.s.value, &as_path, sizeof(as_path));
-	}
-
-	ADD_ATTRIBUTE();
-
-	/* NEXT_HOP */
+    struct hostent *h;
+    int ibgp;
+    int i;
+    struct bgp_path_attr a;
+    char path_attrs[64];
+    char *p = path_attrs;
+    in_addr_t ip;
+    uint32_t metric = htonl(BGP_METRIC);
+    uint32_t no_export = htonl(BGP_COMMUNITY_NO_EXPORT);
+
+    if (!our_as)
+	return 0;
+
+    if (peer->state != Disabled)
+	bgp_halt(peer);
+
+    snprintf(peer->name, sizeof(peer->name), "%s", name);
+
+    if (!(h = gethostbyname(name)) || h->h_addrtype != AF_INET)
+    {
+	LOG(0, 0, 0, "Can't get address for BGP peer %s (%s)\n",
+	    name, h ? "no address" : hstrerror(h_errno));
+
+	return 0;
+    }
+
+    memcpy(&peer->addr, h->h_addr, sizeof(peer->addr));
+    peer->as = as > 0 ? as : our_as;
+    ibgp = peer->as == our_as;
+
+    /* set initial timer values */
+    peer->init_keepalive = keepalive == -1 ? BGP_KEEPALIVE_TIME : keepalive;
+    peer->init_hold = hold == -1 ? BGP_HOLD_TIME : hold;
+
+    if (peer->init_hold < 3)
+    	peer->init_hold = 3;
+
+    if (peer->init_keepalive * 3 > peer->init_hold)
+    	peer->init_keepalive = peer->init_hold / 3;
+
+    /* clear buffers, go to Idle state */
+    peer->next_state = Idle;
+    bgp_clear(peer);
+
+    /* set initial routing state */
+    peer->routing = enable;
+
+    /* all our routes use the same attributes, so prepare it in advance */
+    if (peer->path_attrs)
+    	free(peer->path_attrs);
+
+    peer->path_attr_len = 0;
+
+    /* ORIGIN */
+    a.flags = BGP_PATH_ATTR_FLAG_TRANS;
+    a.code = BGP_PATH_ATTR_CODE_ORIGIN;
+    a.data.s.len = 1;
+    a.data.s.value[0] = BGP_PATH_ATTR_CODE_ORIGIN_IGP;
+
+#define ADD_ATTRIBUTE()		do { \
+    i = BGP_PATH_ATTR_SIZE(a);	\
+    memcpy(p, &a, i); 		\
+    p += i; 			\
+    peer->path_attr_len += i;	} while (0)
+
+    ADD_ATTRIBUTE();
+
+    /* AS_PATH */
+    a.flags = BGP_PATH_ATTR_FLAG_TRANS;
+    a.code = BGP_PATH_ATTR_CODE_AS_PATH;
+    if (ibgp)
+    {
+	/* empty path */
+	a.data.s.len = 0;
+    }
+    else
+    {
+	/* just our AS */
+	struct {
+	    uint8_t type;
+	    uint8_t len;
+	    uint16_t value;
+	} as_path = {
+	    BGP_PATH_ATTR_CODE_AS_PATH_AS_SEQUENCE,
+	    1,
+	    htons(our_as),
+	};
+
+	a.data.s.len = sizeof(as_path);
+	memcpy(&a.data.s.value, &as_path, sizeof(as_path));
+    }
+
+    ADD_ATTRIBUTE();
+
+    /* NEXT_HOP */
+    a.flags = BGP_PATH_ATTR_FLAG_TRANS;
+    a.code = BGP_PATH_ATTR_CODE_NEXT_HOP;
+    ip = my_address; /* we're it */
+    a.data.s.len = sizeof(ip);
+    memcpy(a.data.s.value, &ip, sizeof(ip));
+
+    ADD_ATTRIBUTE();
+
+    /* MULTI_EXIT_DISC */
+    a.flags = BGP_PATH_ATTR_FLAG_OPTIONAL;
+    a.code = BGP_PATH_ATTR_CODE_MULTI_EXIT_DISC;
+    a.data.s.len = sizeof(metric);
+    memcpy(a.data.s.value, &metric, sizeof(metric));
+
+    ADD_ATTRIBUTE();
+
+    if (ibgp)
+    {
+	uint32_t local_pref = htonl(BGP_LOCAL_PREF);
+
+	/* LOCAL_PREF */
 	a.flags = BGP_PATH_ATTR_FLAG_TRANS;
-	a.code = BGP_PATH_ATTR_CODE_NEXT_HOP;
-	ip = my_address; /* we're it */
-	a.data.s.len = sizeof(ip);
-	memcpy(a.data.s.value, &ip, sizeof(ip));
+	a.code = BGP_PATH_ATTR_CODE_LOCAL_PREF;
+	a.data.s.len = sizeof(local_pref);
+	memcpy(a.data.s.value, &local_pref, sizeof(local_pref));
 
 	ADD_ATTRIBUTE();
+    }
 
-	/* MULTI_EXIT_DISC */
-	a.flags = BGP_PATH_ATTR_FLAG_OPTIONAL;
-	a.code = BGP_PATH_ATTR_CODE_MULTI_EXIT_DISC;
-	a.data.s.len = sizeof(metric);
-	memcpy(a.data.s.value, &metric, sizeof(metric));
-
-	ADD_ATTRIBUTE();
-
-	if (ibgp)
-	{
-		u32 local_pref = htonl(BGP_LOCAL_PREF);
-
-		/* LOCAL_PREF */
-		a.flags = BGP_PATH_ATTR_FLAG_TRANS;
-		a.code = BGP_PATH_ATTR_CODE_LOCAL_PREF;
-		a.data.s.len = sizeof(local_pref);
-		memcpy(a.data.s.value, &local_pref, sizeof(local_pref));
-
-		ADD_ATTRIBUTE();
-	}
-
-	/* COMMUNITIES */
-	a.flags = BGP_PATH_ATTR_FLAG_OPTIONAL | BGP_PATH_ATTR_FLAG_TRANS;
-	a.code = BGP_PATH_ATTR_CODE_COMMUNITIES;
-	a.data.s.len = sizeof(no_export);
-	memcpy(a.data.s.value, &no_export, sizeof(no_export));
+    /* COMMUNITIES */
+    a.flags = BGP_PATH_ATTR_FLAG_OPTIONAL | BGP_PATH_ATTR_FLAG_TRANS;
+    a.code = BGP_PATH_ATTR_CODE_COMMUNITIES;
+    a.data.s.len = sizeof(no_export);
+    memcpy(a.data.s.value, &no_export, sizeof(no_export));
 
-	ADD_ATTRIBUTE();
+    ADD_ATTRIBUTE();
 
-	if (!(peer->path_attrs = malloc(peer->path_attr_len)))
-	{
-		log(0, 0, 0, 0, "Can't allocate path_attrs for %s (%s)\n",
-			name, strerror(errno));
+    if (!(peer->path_attrs = malloc(peer->path_attr_len)))
+    {
+	LOG(0, 0, 0, "Can't allocate path_attrs for %s (%s)\n",
+	    name, strerror(errno));
 
-		return 0;
-	}
+	return 0;
+    }
 
-	memcpy(peer->path_attrs, path_attrs, peer->path_attr_len);
+    memcpy(peer->path_attrs, path_attrs, peer->path_attr_len);
 
-	log(4, 0, 0, 0, "Initiating BGP connection to %s (routing %s)\n",
-		name, enable ? "enabled" : "suspended");
+    LOG(4, 0, 0, "Initiating BGP connection to %s (routing %s)\n",
+	name, enable ? "enabled" : "suspended");
 
-	/* we have at least one peer configured */
-	bgp_configured = 1;
+    /* we have at least one peer configured */
+    bgp_configured = 1;
 
-	/* connect */
-	return bgp_connect(peer);
+    /* connect */
+    return bgp_connect(peer);
 }
 
 /* clear counters, timers, routes and buffers; close socket; move to
    next_state, which may be Disabled or Idle */
 static void bgp_clear(struct bgp_peer *peer)
 {
-	if (peer->sock != -1)
-	{
-			close(peer->sock);
-		peer->sock = -1;
-	}
+    if (peer->sock != -1)
+    {
+    	close(peer->sock);
+	peer->sock = -1;
+    }
 
-	peer->keepalive_time = 0;
-	peer->hold = 0;
-	peer->expire_time = 0;
+    peer->keepalive_time = 0;
+    peer->expire_time = 0;
 
-	bgp_free_routes(peer->routes);
-	peer->routes = 0;
+    peer->keepalive = peer->init_keepalive;
+    peer->hold = peer->init_hold;
 
-	peer->outbuf->packet.header.len = 0;
-	peer->outbuf->done = 0;
-	peer->inbuf->packet.header.len = 0;
-	peer->inbuf->done = 0;
+    bgp_free_routes(peer->routes);
+    peer->routes = 0;
 
-	peer->cli_flag = 0;
+    peer->outbuf->packet.header.len = 0;
+    peer->outbuf->done = 0;
+    peer->inbuf->packet.header.len = 0;
+    peer->inbuf->done = 0;
 
-	if (peer->state != peer->next_state)
-	{
-		peer->state = peer->next_state;
-		peer->state_time = time_now;
+    peer->cli_flag = 0;
 
-		log(4, 0, 0, 0, "BGP peer %s: state %s\n", peer->name,
-			bgp_state_str(peer->next_state));
-	}
+    if (peer->state != peer->next_state)
+    {
+	peer->state = peer->next_state;
+	peer->state_time = time_now;
+
+	LOG(4, 0, 0, "BGP peer %s: state %s\n", peer->name,
+	    bgp_state_str(peer->next_state));
+    }
 }
 
 /* initiate a clean shutdown */
 void bgp_stop(struct bgp_peer *peer)
 {
-	log(4, 0, 0, 0, "Terminating BGP connection to %s\n", peer->name);
-	bgp_send_notification(peer, BGP_ERR_CEASE, 0);
+    LOG(4, 0, 0, "Terminating BGP connection to %s\n", peer->name);
+    bgp_send_notification(peer, BGP_ERR_CEASE, 0);
 }
 
 /* drop connection (if any) and set state to Disabled */
 void bgp_halt(struct bgp_peer *peer)
 {
-	log(4, 0, 0, 0, "Aborting BGP connection to %s\n", peer->name);
-	peer->next_state = Disabled;
-	bgp_clear(peer);
+    LOG(4, 0, 0, "Aborting BGP connection to %s\n", peer->name);
+    peer->next_state = Disabled;
+    bgp_clear(peer);
 }
 
 /* drop connection (if any) and set to Idle for connection retry */
 int bgp_restart(struct bgp_peer *peer)
 {
-	peer->next_state = Idle;
-	bgp_clear(peer);
+    peer->next_state = Idle;
+    bgp_clear(peer);
 
-	/* restart now */
-	peer->retry_time = time_now;
-	peer->retry_count = 0;
+    /* restart now */
+    peer->retry_time = time_now;
+    peer->retry_count = 0;
 
-	/* connect */
-	return bgp_connect(peer);
+    /* connect */
+    return bgp_connect(peer);
 }
 
 static void bgp_set_retry(struct bgp_peer *peer)
 {
-	if (peer->retry_count++ < BGP_MAX_RETRY)
-	{
-		peer->retry_time = time_now + (BGP_RETRY_BACKOFF * peer->retry_count);
-		peer->next_state = Idle;
-		bgp_clear(peer);
-	}
-	else
-			bgp_halt(peer); /* give up */
+    if (peer->retry_count++ < BGP_MAX_RETRY)
+    {
+	peer->retry_time = time_now + (BGP_RETRY_BACKOFF * peer->retry_count);
+	peer->next_state = Idle;
+	bgp_clear(peer);
+    }
+    else
+    	bgp_halt(peer); /* give up */
 }
 
 /* convert ip/mask to CIDR notation */
 static void bgp_cidr(in_addr_t ip, in_addr_t mask, struct bgp_ip_prefix *pfx)
 {
-	int i;
-	u32 b;
+    int i;
+    uint32_t b;
 
-	/* convert to prefix notation */
-	pfx->len = 32;
-	pfx->prefix = ip;
+    /* convert to prefix notation */
+    pfx->len = 32;
+    pfx->prefix = ip;
 
-	if (!mask) /* bogus */
-		mask = 0xffffffff;
+    if (!mask) /* bogus */
+	mask = 0xffffffff;
 
-	for (i = 0; i < 32 && ((b = ntohl(1 << i)), !(mask & b)); i++)
-	{
-		pfx->len--;
-		pfx->prefix &= ~b;
-	}
+    for (i = 0; i < 32 && ((b = ntohl(1 << i)), !(mask & b)); i++)
+    {
+	pfx->len--;
+	pfx->prefix &= ~b;
+    }
 }
 
 /* insert route into list; sorted */
 static struct bgp_route_list *bgp_insert_route(struct bgp_route_list *head,
-	struct bgp_route_list *new)
+    struct bgp_route_list *new)
 {
-	struct bgp_route_list *p = head;
-	struct bgp_route_list *e = 0;
-
-	while (p && memcmp(&p->dest, &new->dest, sizeof(p->dest)) < 0)
-	{
-		e = p;
-		p = p->next;
-	}
-
-	if (e)
-	{
-		new->next = e->next;
-		e->next = new;
-	}
-	else
-	{
-		new->next = head;
-		head = new;
-	}
-
-	return head;
+    struct bgp_route_list *p = head;
+    struct bgp_route_list *e = 0;
+
+    while (p && memcmp(&p->dest, &new->dest, sizeof(p->dest)) < 0)
+    {
+	e = p;
+	p = p->next;
+    }
+
+    if (e)
+    {
+	new->next = e->next;
+	e->next = new;
+    }
+    else
+    {
+	new->next = head;
+	head = new;
+    }
+
+    return head;
 }
 
 /* add route to list for peers */
@@ -359,971 +378,826 @@ static struct bgp_route_list *bgp_insert_route(struct bgp_route_list *head,
  */
 int bgp_add_route(in_addr_t ip, in_addr_t mask)
 {
-	struct bgp_route_list *r = bgp_routes;
-	struct bgp_route_list add;
-	int i;
+    struct bgp_route_list *r = bgp_routes;
+    struct bgp_route_list add;
+    int i;
 
-	bgp_cidr(ip, mask, &add.dest);
-	add.next = 0;
+    bgp_cidr(ip, mask, &add.dest);
+    add.next = 0;
 
-	/* check for duplicate */
-	while (r)
-	{
-		i = memcmp(&r->dest, &add.dest, sizeof(r->dest));
-		if (!i)
-			return 1; /* already covered */
+    /* check for duplicate */
+    while (r)
+    {
+	i = memcmp(&r->dest, &add.dest, sizeof(r->dest));
+	if (!i)
+	    return 1; /* already covered */
 
-		if (i > 0)
-			break;
+	if (i > 0)
+	    break;
 
-		r = r->next;
-	}
+	r = r->next;
+    }
 
-	/* insert into route list; sorted */
-	if (!(r = malloc(sizeof(*r))))
-	{
-		log(0, 0, 0, 0, "Can't allocate route for %s/%d (%s)\n",
-			inet_toa(add.dest.prefix), add.dest.len, strerror(errno));
+    /* insert into route list; sorted */
+    if (!(r = malloc(sizeof(*r))))
+    {
+	LOG(0, 0, 0, "Can't allocate route for %s/%d (%s)\n",
+	    fmtaddr(add.dest.prefix, 0), add.dest.len, strerror(errno));
 
-		return 0;
-	}
+	return 0;
+    }
 
-	memcpy(r, &add, sizeof(*r));
-	bgp_routes = bgp_insert_route(bgp_routes, r);
+    memcpy(r, &add, sizeof(*r));
+    bgp_routes = bgp_insert_route(bgp_routes, r);
 
-	/* flag established peers for update */
-	for (i = 0; i < BGP_NUM_PEERS; i++)
-		if (bgp_peers[i].state == Established)
-			bgp_peers[i].update_routes = 1;
+    /* flag established peers for update */
+    for (i = 0; i < BGP_NUM_PEERS; i++)
+	if (bgp_peers[i].state == Established)
+	    bgp_peers[i].update_routes = 1;
 
-	log(4, 0, 0, 0, "Registered BGP route %s/%d\n", inet_toa(add.dest.prefix),
-		add.dest.len);
+    LOG(4, 0, 0, "Registered BGP route %s/%d\n",
+	fmtaddr(add.dest.prefix, 0), add.dest.len);
 
-	return 1;
+    return 1;
 }
 
 /* remove route from list for peers */
 int bgp_del_route(in_addr_t ip, in_addr_t mask)
 {
-	struct bgp_route_list *r = bgp_routes;
-	struct bgp_route_list *e = 0;
-	struct bgp_route_list del;
-	int i;
-
-	bgp_cidr(ip, mask, &del.dest);
-	del.next = 0;
-
-	/* find entry in routes list and remove */
-	while (r)
+    struct bgp_route_list *r = bgp_routes;
+    struct bgp_route_list *e = 0;
+    struct bgp_route_list del;
+    int i;
+
+    bgp_cidr(ip, mask, &del.dest);
+    del.next = 0;
+
+    /* find entry in routes list and remove */
+    while (r)
+    {
+	i = memcmp(&r->dest, &del.dest, sizeof(r->dest));
+	if (!i)
 	{
-		i = memcmp(&r->dest, &del.dest, sizeof(r->dest));
-		if (!i)
-		{
-			if (e)
-				e->next = r->next;
-			else
-				bgp_routes = r->next;
+	    if (e)
+		e->next = r->next;
+	    else
+	    	bgp_routes = r->next;
 
-			free(r);
-			break;
-		}
+	    free(r);
+	    break;
+	}
 
-		e = r;
+	e = r;
 
-		if (i > 0)
-			r = 0; /* stop */
-		else
-			r = r->next;
-	}
+	if (i > 0)
+	    r = 0; /* stop */
+	else
+	    r = r->next;
+    }
 
-	/* not found */
-	if (!r)
-		return 1;
+    /* not found */
+    if (!r)
+	return 1;
 
-	/* flag established peers for update */
-	for (i = 0; i < BGP_NUM_PEERS; i++)
-		if (bgp_peers[i].state == Established)
-			bgp_peers[i].update_routes = 1;
+    /* flag established peers for update */
+    for (i = 0; i < BGP_NUM_PEERS; i++)
+	if (bgp_peers[i].state == Established)
+	    bgp_peers[i].update_routes = 1;
 
-	log(4, 0, 0, 0, "Removed BGP route %s/%d\n", inet_toa(del.dest.prefix),
-		del.dest.len);
+    LOG(4, 0, 0, "Removed BGP route %s/%d\n",
+	fmtaddr(del.dest.prefix, 0), del.dest.len);
 
-	return 1;
+    return 1;
 }
 
 /* enable or disable routing */
 void bgp_enable_routing(int enable)
 {
-	int i;
+    int i;
 
-	for (i = 0; i < BGP_NUM_PEERS; i++)
-	{
-		bgp_peers[i].routing = enable;
+    for (i = 0; i < BGP_NUM_PEERS; i++)
+    {
+	bgp_peers[i].routing = enable;
 
-		/* flag established peers for update */
-		if (bgp_peers[i].state == Established)
-			bgp_peers[i].update_routes = 1;
-	}
+	/* flag established peers for update */
+	if (bgp_peers[i].state == Established)
+	    bgp_peers[i].update_routes = 1;
+    }
 
-	log(4, 0, 0, 0, "%s BGP routing\n", enable ? "Enabled" : "Suspended");
+    LOG(4, 0, 0, "%s BGP routing\n", enable ? "Enabled" : "Suspended");
 }
 
 /* return a bitmask indicating if the socket should be added to the
    read set (1) and or write set (2) for select */
 int bgp_select_state(struct bgp_peer *peer)
 {
-	int flags = 0;
+    int flags = 0;
 
-	if (!bgp_configured)
-			return 0;
+    if (!bgp_configured)
+    	return 0;
 
-	if (peer->state == Disabled || peer->state == Idle)
-			return 0;
+    if (peer->state == Disabled || peer->state == Idle)
+    	return 0;
 
-	if (peer->inbuf->done < BGP_MAX_PACKET_SIZE)
-		flags |= 1;
+    if (peer->inbuf->done < BGP_MAX_PACKET_SIZE)
+	flags |= 1;
 
-	if (peer->state == Connect ||				/* connection in progress */
-		peer->update_routes ||						/* routing updates */
-		peer->outbuf->packet.header.len)		/* pending output */
-			flags |= 2;
+    if (peer->state == Connect ||		/* connection in progress */
+	peer->update_routes ||			/* routing updates */
+	peer->outbuf->packet.header.len)	/* pending output */
+    	flags |= 2;
 
-	return flags;
+    return flags;
 }
 
 /* process bgp peer */
 int bgp_process(struct bgp_peer *peer, int readable, int writable)
 {
-	if (!bgp_configured)
-			return 0;
-
-	if (*peer->name && peer->cli_flag == BGP_CLI_RESTART)
-		return bgp_restart(peer);
-
-	if (peer->state == Disabled)
-			return 1;
-
-	if (peer->cli_flag)
-	{
-		switch (peer->cli_flag)
-		{
-			case BGP_CLI_SUSPEND:
-				if (peer->routing)
-				{
-					peer->routing = 0;
-					if (peer->state == Established)
-						peer->update_routes = 1;
-				}
-
-				break;
-
-			case BGP_CLI_ENABLE:
-				if (!peer->routing)
-				{
-					peer->routing = 1;
-					if (peer->state == Established)
-						peer->update_routes = 1;
-				}
-
-				break;
-		}
-
-		peer->cli_flag = 0;
-	}
+    if (!bgp_configured)
+    	return 0;
 
-	/* handle empty/fill of buffers */
-	if (writable)
-	{
-		int r = 1;
-		if (peer->state == Connect)
-			r = bgp_handle_connect(peer);
-		else if (peer->outbuf->packet.header.len)
-			r = bgp_write(peer);
-
-		if (!r)
-			return 0;
-	}
+    if (*peer->name && peer->cli_flag == BGP_CLI_RESTART)
+	return bgp_restart(peer);
 
-	if (readable)
-	{
-		if (!bgp_read(peer))
-			return 0;
-	}
+    if (peer->state == Disabled)
+    	return 1;
 
-	/* process input buffer contents */
-	while (peer->inbuf->done >= sizeof(peer->inbuf->packet.header)
-		&& !peer->outbuf->packet.header.len) /* may need to queue a response */
+    if (peer->cli_flag)
+    {
+	switch (peer->cli_flag)
 	{
-		if (bgp_handle_input(peer) < 0)
-			return 0;
+	case BGP_CLI_SUSPEND:
+	    if (peer->routing)
+	    {
+		peer->routing = 0;
+		if (peer->state == Established)
+		    peer->update_routes = 1;
+	    }
+
+	    break;
+
+	case BGP_CLI_ENABLE:
+	    if (!peer->routing)
+	    {
+		peer->routing = 1;
+		if (peer->state == Established)
+		    peer->update_routes = 1;
+	    }
+
+	    break;
 	}
 
-	/* process pending updates */
-	if (peer->update_routes
-		&& !peer->outbuf->packet.header.len) /* ditto */
-	{
-		if (!bgp_send_update(peer))
-			return 0;
-	}
-
-	/* process timers */
-	if (peer->state == Established)
-	{
-		if (time_now > peer->expire_time)
-		{
-			log(1, 0, 0, 0, "No message from BGP peer %s in %ds\n",
-				peer->name, peer->hold);
+	peer->cli_flag = 0;
+    }
 
-			bgp_send_notification(peer, BGP_ERR_HOLD_TIMER_EXP, 0);
-			return 0;
-		}
+    /* handle empty/fill of buffers */
+    if (writable)
+    {
+	int r = 1;
+	if (peer->state == Connect)
+	    r = bgp_handle_connect(peer);
+	else if (peer->outbuf->packet.header.len)
+	    r = bgp_write(peer);
 
-		if (time_now > peer->keepalive_time && !peer->outbuf->packet.header.len)
-			bgp_send_keepalive(peer);
-	}
-	else if (peer->state == Idle)
-	{
-		if (time_now > peer->retry_time)
-			return bgp_connect(peer);
-	}
-	else if (time_now > peer->state_time + BGP_KEEPALIVE_TIME)
+	if (!r)
+	    return 0;
+    }
+
+    if (readable)
+    {
+	if (!bgp_read(peer))
+	    return 0;
+    }
+
+    /* process input buffer contents */
+    while (peer->inbuf->done >= sizeof(peer->inbuf->packet.header)
+	&& !peer->outbuf->packet.header.len) /* may need to queue a response */
+    {
+	if (bgp_handle_input(peer) < 0)
+	    return 0;
+    }
+
+    /* process pending updates */
+    if (peer->update_routes
+	&& !peer->outbuf->packet.header.len) /* ditto */
+    {
+	if (!bgp_send_update(peer))
+	    return 0;
+    }
+
+    /* process timers */
+    if (peer->state == Established)
+    {
+	if (time_now > peer->expire_time)
 	{
-		log(1, 0, 0, 0, "%s timer expired for BGP peer %s\n",
-			bgp_state_str(peer->state), peer->name);
+	    LOG(1, 0, 0, "No message from BGP peer %s in %ds\n",
+		peer->name, peer->hold);
 
-		return bgp_restart(peer);
+	    bgp_send_notification(peer, BGP_ERR_HOLD_TIMER_EXP, 0);
+	    return 0;
 	}
 
-	return 1;
+	if (time_now > peer->keepalive_time && !peer->outbuf->packet.header.len)
+	    bgp_send_keepalive(peer);
+    }
+    else if (peer->state == Idle)
+    {
+	if (time_now > peer->retry_time)
+	    return bgp_connect(peer);
+    }
+    else if (time_now > peer->state_time + BGP_STATE_TIME)
+    {
+	LOG(1, 0, 0, "%s timer expired for BGP peer %s\n",
+	    bgp_state_str(peer->state), peer->name);
+
+	return bgp_restart(peer);
+    }
+
+    return 1;
 }
 
 static void bgp_free_routes(struct bgp_route_list *routes)
 {
-	struct bgp_route_list *tmp;
+    struct bgp_route_list *tmp;
 
-	while ((tmp = routes))
-	{
-		routes = tmp->next;
-		free(tmp);
-	}
+    while ((tmp = routes))
+    {
+	routes = tmp->next;
+	free(tmp);
+    }
 }
 
-static char const *bgp_state_str(enum bgp_state state)
+char const *bgp_state_str(enum bgp_state state)
 {
-	switch (state)
-	{
-	case Disabled:		return "Disabled";
-	case Idle:				return "Idle";
-	case Connect:		return "Connect";
-	case Active:		return "Active";
-	case OpenSent:		return "OpenSent";
-	case OpenConfirm:		return "OpenConfirm";
-	case Established:		return "Established";
-	}
-
-	return "?";
+    switch (state)
+    {
+    case Disabled:	return "Disabled";
+    case Idle:		return "Idle";
+    case Connect:	return "Connect";
+    case Active:	return "Active";
+    case OpenSent:	return "OpenSent";
+    case OpenConfirm:	return "OpenConfirm";
+    case Established:	return "Established";
+    }
+
+    return "?";
 }
 
-static char const *bgp_msg_type_str(u8 type)
+static char const *bgp_msg_type_str(uint8_t type)
 {
-	switch (type)
-	{
-	case BGP_MSG_OPEN:				return "OPEN";
-	case BGP_MSG_UPDATE:		return "UPDATE";
-	case BGP_MSG_NOTIFICATION:		return "NOTIFICATION";
-	case BGP_MSG_KEEPALIVE:		return "KEEPALIVE";
-	}
-
-	return "?";
+    switch (type)
+    {
+    case BGP_MSG_OPEN:		return "OPEN";
+    case BGP_MSG_UPDATE:	return "UPDATE";
+    case BGP_MSG_NOTIFICATION:	return "NOTIFICATION";
+    case BGP_MSG_KEEPALIVE:	return "KEEPALIVE";
+    }
+
+    return "?";
 }
 
 /* attempt to connect to peer */
 static int bgp_connect(struct bgp_peer *peer)
 {
-	static int bgp_port = 0;
-	struct sockaddr_in addr;
+    static int bgp_port = 0;
+    struct sockaddr_in addr;
 
-	if (!bgp_port)
+    if (!bgp_port)
+    {
+	struct servent *serv;
+	if (!(serv = getservbyname("bgp", "tcp")))
 	{
-		struct servent *serv;
-		if (!(serv = getservbyname("bgp", "tcp")))
-		{
-			log(0, 0, 0, 0, "Can't get bgp service (%s)\n", strerror(errno));
-			return 0;
-		}
-
-		bgp_port = serv->s_port;
+	    LOG(0, 0, 0, "Can't get bgp service (%s)\n", strerror(errno));
+	    return 0;
 	}
 
-	if ((peer->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
-	{
-		log(0, 0, 0, 0, "Can't create a socket for BGP peer %s (%s)\n",
-			peer->name, strerror(errno));
+	bgp_port = serv->s_port;
+    }
 
-		peer->state = peer->next_state = Disabled;
-		return 0;
-	}
+    if ((peer->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+    {
+	LOG(0, 0, 0, "Can't create a socket for BGP peer %s (%s)\n",
+	    peer->name, strerror(errno));
 
-	/* set to non-blocking */
-	fcntl(peer->sock, F_SETFL, fcntl(peer->sock, F_GETFL, 0) | O_NONBLOCK);
+	peer->state = peer->next_state = Disabled;
+	return 0;
+    }
 
-	/* try connect */
-	memset(&addr, 0, sizeof(addr));
-	addr.sin_family = AF_INET;
-	addr.sin_port = bgp_port;
-	addr.sin_addr.s_addr = peer->addr;
+    /* set to non-blocking */
+    fcntl(peer->sock, F_SETFL, fcntl(peer->sock, F_GETFL, 0) | O_NONBLOCK);
 
-	while (connect(peer->sock, (struct sockaddr *) &addr, sizeof(addr)) == -1)
-	{
-		if (errno == EINTR) /* SIGALARM handler */
-			continue;
+    /* try connect */
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = bgp_port;
+    addr.sin_addr.s_addr = peer->addr;
 
-		if (errno != EINPROGRESS)
-		{
-			log(1, 0, 0, 0, "Can't connect to BGP peer %s (%s)\n",
-				inet_ntoa(addr.sin_addr), strerror(errno));
-
-			bgp_set_retry(peer);
-			return 0;
-		}
+    while (connect(peer->sock, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+    {
+	if (errno == EINTR) /* SIGALARM handler */
+	    continue;
 
-		peer->state = Connect;
-		peer->state_time = time_now;
+	if (errno != EINPROGRESS)
+	{
+	    LOG(1, 0, 0, "Can't connect to BGP peer %s (%s)\n",
+		inet_ntoa(addr.sin_addr), strerror(errno));
 
-		log(4, 0, 0, 0, "BGP peer %s: state Connect\n", peer->name);
-		return 1;
+	    bgp_set_retry(peer);
+	    return 0;
 	}
 
-	peer->state = Active;
+	peer->state = Connect;
 	peer->state_time = time_now;
-	peer->retry_time = peer->retry_count = 0;
 
-	log(4, 0, 0, 0, "BGP peer %s: state Active\n", inet_ntoa(addr.sin_addr));
+	LOG(4, 0, 0, "BGP peer %s: state Connect\n", peer->name);
+	return 1;
+    }
+
+    peer->state = Active;
+    peer->state_time = time_now;
+    peer->retry_time = peer->retry_count = 0;
 
-	return bgp_send_open(peer);
+    LOG(4, 0, 0, "BGP peer %s: state Active\n", inet_ntoa(addr.sin_addr));
+
+    return bgp_send_open(peer);
 }
 
 /* complete partial connection (state = Connect) */
 static int bgp_handle_connect(struct bgp_peer *peer)
 {
-	int err = 0;
-	int len = sizeof(int);
-	getsockopt(peer->sock, SOL_SOCKET, SO_ERROR, &err, &len);
-	if (err)
-	{
-		log(1, 0, 0, 0, "Can't connect to BGP peer %s (%s)\n", peer->name,
-			strerror(err));
+    int err = 0;
+    int len = sizeof(int);
+    getsockopt(peer->sock, SOL_SOCKET, SO_ERROR, &err, &len);
+    if (err)
+    {
+	LOG(1, 0, 0, "Can't connect to BGP peer %s (%s)\n", peer->name,
+	    strerror(err));
 
-		bgp_set_retry(peer);
-		return 0;
-	}
+	bgp_set_retry(peer);
+	return 0;
+    }
 
-	peer->state = Active;
-	peer->state_time = time_now;
+    peer->state = Active;
+    peer->state_time = time_now;
 
-	log(4, 0, 0, 0, "BGP peer %s: state Active\n", peer->name);
+    LOG(4, 0, 0, "BGP peer %s: state Active\n", peer->name);
 
-	return bgp_send_open(peer);
+    return bgp_send_open(peer);
 }
 
 /* initiate a write */
 static int bgp_write(struct bgp_peer *peer)
 {
-	int len = htons(peer->outbuf->packet.header.len);
-	int r;
+    int len = htons(peer->outbuf->packet.header.len);
+    int r;
 
-	while ((r = write(peer->sock, &peer->outbuf->packet + peer->outbuf->done,
-		len - peer->outbuf->done)) == -1)
-	{
-		if (errno == EINTR)
-			continue;
+    while ((r = write(peer->sock, &peer->outbuf->packet + peer->outbuf->done,
+	len - peer->outbuf->done)) == -1)
+    {
+	if (errno == EINTR)
+	    continue;
 
-		if (errno == EAGAIN)
-			return 1;
+	if (errno == EAGAIN)
+	    return 1;
 
-		if (errno == EPIPE)
-			log(1, 0, 0, 0, "Connection to BGP peer %s closed\n", peer->name);
-		else
-			log(1, 0, 0, 0, "Can't write to BGP peer %s (%s)\n", peer->name,
-				strerror(errno));
+	if (errno == EPIPE)
+	    LOG(1, 0, 0, "Connection to BGP peer %s closed\n", peer->name);
+	else
+	    LOG(1, 0, 0, "Can't write to BGP peer %s (%s)\n", peer->name,
+		strerror(errno));
 
-		bgp_set_retry(peer);
-		return 0;
-	}
+	bgp_set_retry(peer);
+	return 0;
+    }
 
-	if (r < len)
-	{
-		peer->outbuf->done += r;
-		return 1;
-	}
+    if (r < len)
+    {
+	peer->outbuf->done += r;
+	return 1;
+    }
 
-	log(4, 0, 0, 0, "Sent %s to BGP peer %s\n",
-		bgp_msg_type_str(peer->outbuf->packet.header.type), peer->name);
+    LOG(4, 0, 0, "Sent %s to BGP peer %s\n",
+	bgp_msg_type_str(peer->outbuf->packet.header.type), peer->name);
 
-	peer->outbuf->packet.header.len = 0;
-	peer->outbuf->done = 0;
+    peer->outbuf->packet.header.len = 0;
+    peer->outbuf->done = 0;
 
-	if (peer->state == Established)
-		peer->keepalive_time = time_now + BGP_KEEPALIVE_TIME;
+    if (peer->state == Established)
+	peer->keepalive_time = time_now + peer->keepalive;
 
-	if (peer->state != peer->next_state)
+    if (peer->state != peer->next_state)
+    {
+	if (peer->next_state == Disabled || peer->next_state == Idle)
 	{
-		if (peer->next_state == Disabled || peer->next_state == Idle)
-		{
-			bgp_clear(peer);
-			return 0;
-		}
+	    bgp_clear(peer);
+	    return 0;
+	}
 
-		peer->state = peer->next_state;
-		peer->state_time = time_now;
+	peer->state = peer->next_state;
+	peer->state_time = time_now;
 
-		log(4, 0, 0, 0, "BGP peer %s: state %s\n", peer->name,
-			bgp_state_str(peer->state));
-	}
+	LOG(4, 0, 0, "BGP peer %s: state %s\n", peer->name,
+	    bgp_state_str(peer->state));
+    }
 
-	return 1;
+    return 1;
 }
 
 /* initiate a read */
 static int bgp_read(struct bgp_peer *peer)
 {
-	int r;
+    int r;
 
-	while ((r = read(peer->sock, &peer->inbuf->packet + peer->inbuf->done,
-		BGP_MAX_PACKET_SIZE - peer->inbuf->done)) < 1)
+    while ((r = read(peer->sock, &peer->inbuf->packet + peer->inbuf->done,
+	BGP_MAX_PACKET_SIZE - peer->inbuf->done)) < 1)
+    {
+	if (!r)
 	{
-		if (!r)
-		{
-			log(1, 0, 0, 0, "Connection to BGP peer %s closed\n", peer->name);
-		}
-		else
-		{
-			if (errno == EINTR)
-				continue;
-
-			if (errno == EAGAIN)
-				return 1;
+	    LOG(1, 0, 0, "Connection to BGP peer %s closed\n", peer->name);
+	}
+	else
+	{
+	    if (errno == EINTR)
+		continue;
 
-			log(1, 0, 0, 0, "Can't read from BGP peer %s (%s)\n", peer->name,
-				strerror(errno));
-		}
+	    if (errno == EAGAIN)
+		return 1;
 
-		bgp_set_retry(peer);
-		return 0;
+	    LOG(1, 0, 0, "Can't read from BGP peer %s (%s)\n", peer->name,
+		strerror(errno));
 	}
 
-	peer->inbuf->done += r;
-	return 1;
+	bgp_set_retry(peer);
+	return 0;
+    }
+
+    peer->inbuf->done += r;
+    return 1;
 }
 
 /* process buffered packets */
 static int bgp_handle_input(struct bgp_peer *peer)
 {
-	struct bgp_packet *p = &peer->inbuf->packet;
-	int len = ntohs(p->header.len);
+    struct bgp_packet *p = &peer->inbuf->packet;
+    int len = ntohs(p->header.len);
 
-	if (len > BGP_MAX_PACKET_SIZE)
-	{
-		log(1, 0, 0, 0, "Bad header length from BGP %s\n", peer->name);
-		bgp_send_notification(peer, BGP_ERR_HEADER, BGP_ERR_HDR_BAD_LEN);
-		return 0;
-	}
+    if (len > BGP_MAX_PACKET_SIZE)
+    {
+	LOG(1, 0, 0, "Bad header length from BGP %s\n", peer->name);
+	bgp_send_notification(peer, BGP_ERR_HEADER, BGP_ERR_HDR_BAD_LEN);
+	return 0;
+    }
 
-	if (peer->inbuf->done < len)
-		return 0;
+    if (peer->inbuf->done < len)
+	return 0;
 
-	log(4, 0, 0, 0, "Received %s from BGP peer %s\n",
-		bgp_msg_type_str(p->header.type), peer->name);
+    LOG(4, 0, 0, "Received %s from BGP peer %s\n",
+	bgp_msg_type_str(p->header.type), peer->name);
 
-	switch (p->header.type)
+    switch (p->header.type)
+    {
+    case BGP_MSG_OPEN:
 	{
-	case BGP_MSG_OPEN:
-		{
-			struct bgp_data_open data;
-			int i;
-
-			for (i = 0; i < sizeof(p->header.marker); i++)
-			{
-				if ((unsigned char) p->header.marker[i] != 0xff)
-				{
-					log(1, 0, 0, 0, "Invalid marker from BGP peer %s\n",
-						peer->name);
-
-					bgp_send_notification(peer, BGP_ERR_HEADER,
-						BGP_ERR_HDR_NOT_SYNC);
-
-					return 0;
-				}
-			}
-
-			if (peer->state != OpenSent)
-			{
-				log(1, 0, 0, 0, "OPEN from BGP peer %s in %s state\n",
-					peer->name, bgp_state_str(peer->state));
-
-				bgp_send_notification(peer, BGP_ERR_FSM, 0);
-				return 0;
-			}
-
-			memcpy(&data, p->data, len - sizeof(p->header));
-
-			if (data.version != BGP_VERSION)
-			{
-				log(1, 0, 0, 0, "Bad version (%d) sent by BGP peer %s\n",
-					(int) data.version, peer->name);
-
-				bgp_send_notification(peer, BGP_ERR_OPEN, BGP_ERR_OPN_VERSION);
-				return 0;
-			}
-
-			if (ntohs(data.as) != peer->as)
-			{
-				log(1, 0, 0, 0, "Bad AS sent by BGP peer %s (got %d, "
-					"expected %d)\n", peer->name, (int) htons(data.as),
-					(int) peer->as);
-
-				bgp_send_notification(peer, BGP_ERR_OPEN, BGP_ERR_OPN_BAD_AS);
-				return 0;
-			}
-
-			if ((peer->hold = ntohs(data.hold_time)) < 10)
-			{
-				log(1, 0, 0, 0, "Bad hold time (%d) from BGP peer %s\n",
-					peer->hold, peer->name);
-
-				bgp_send_notification(peer, BGP_ERR_OPEN, BGP_ERR_OPN_HOLD_TIME);
-				return 0;
-			}
-
-			/* next transition requires an exchange of keepalives */
-			bgp_send_keepalive(peer);
-
-			/* FIXME: may need to check for optional params */
-		}
+	    struct bgp_data_open data;
+	    int hold;
+	    int i;
 
-		break;
-
-	case BGP_MSG_KEEPALIVE:
-		if (peer->state == OpenConfirm)
+	    for (i = 0; i < sizeof(p->header.marker); i++)
+	    {
+		if ((unsigned char) p->header.marker[i] != 0xff)
 		{
-			peer->state = peer->next_state = Established;
-			peer->state_time = time_now;
-			peer->keepalive_time = time_now + BGP_KEEPALIVE_TIME;
-			peer->update_routes = 1;
-			peer->retry_count = 0;
-			peer->retry_time = 0;
-
-			log(4, 0, 0, 0, "BGP peer %s: state Established\n", peer->name);
-		}
+		    LOG(1, 0, 0, "Invalid marker from BGP peer %s\n",
+			peer->name);
 
-		break;
+		    bgp_send_notification(peer, BGP_ERR_HEADER,
+			BGP_ERR_HDR_NOT_SYNC);
 
-	case BGP_MSG_NOTIFICATION:
-		if (len > sizeof(p->header))
-		{
-			struct bgp_data_notification *notification =
-				(struct bgp_data_notification *) p->data;
-
-			if (notification->error_code == BGP_ERR_CEASE)
-			{
-				log(4, 0, 0, 0, "BGP peer %s sent CEASE\n", peer->name);
-				bgp_halt(peer);
-				return 0;
-			}
-
-			/* FIXME: should handle more notifications */
-			log(4, 0, 0, 0, "BGP peer %s sent unhandled NOTIFICATION %d\n",
-				peer->name, (int) notification->error_code);
+		    return 0;
 		}
+	    }
 
-		break;
-	}
-
-	/* reset timer */
-	peer->expire_time = time_now + peer->hold;
-
-	/* see if there's another message in the same packet/buffer */
-	if (peer->inbuf->done > len)
-	{
-		peer->inbuf->done -= len;
-		memmove(p, (char *) p + len, peer->inbuf->done);
-	}
-	else
-	{
-		peer->inbuf->packet.header.len = 0;
-		peer->inbuf->done = 0;
-	}
-
-	return peer->inbuf->done;
-}
-
-/* send/buffer OPEN message */
-static int bgp_send_open(struct bgp_peer *peer)
-{
-	struct bgp_data_open data;
-	u16 len = sizeof(peer->outbuf->packet.header);
-
-	memset(peer->outbuf->packet.header.marker, 0xff,
-		sizeof(peer->outbuf->packet.header.marker));
-
-	peer->outbuf->packet.header.type = BGP_MSG_OPEN;
-
-	data.version = BGP_VERSION;
-	data.as = htons(our_as);
-	data.hold_time = htons(BGP_HOLD_TIME);
-	data.identifier = my_address;
-	data.opt_len = 0;
+	    if (peer->state != OpenSent)
+	    {
+		LOG(1, 0, 0, "OPEN from BGP peer %s in %s state\n",
+		    peer->name, bgp_state_str(peer->state));
 
-	memcpy(peer->outbuf->packet.data, &data, BGP_DATA_OPEN_SIZE);
-	len += BGP_DATA_OPEN_SIZE;
+		bgp_send_notification(peer, BGP_ERR_FSM, 0);
+		return 0;
+	    }
 
-	peer->outbuf->packet.header.len = htons(len);
-	peer->outbuf->done = 0;
-	peer->next_state = OpenSent;
+	    memcpy(&data, p->data, len - sizeof(p->header));
 
-	return bgp_write(peer);
-}
+	    if (data.version != BGP_VERSION)
+	    {
+		LOG(1, 0, 0, "Bad version (%d) sent by BGP peer %s\n",
+		    (int) data.version, peer->name);
 
-/* send/buffer KEEPALIVE message */
-static int bgp_send_keepalive(struct bgp_peer *peer)
-{
-	memset(peer->outbuf->packet.header.marker, 0xff,
-		sizeof(peer->outbuf->packet.header.marker));
+		bgp_send_notification(peer, BGP_ERR_OPEN, BGP_ERR_OPN_VERSION);
+		return 0;
+	    }
 
-	peer->outbuf->packet.header.type = BGP_MSG_KEEPALIVE;
-	peer->outbuf->packet.header.len =
-		htons(sizeof(peer->outbuf->packet.header));
+	    if (ntohs(data.as) != peer->as)
+	    {
+		LOG(1, 0, 0, "Bad AS sent by BGP peer %s (got %d, "
+		    "expected %d)\n", peer->name, (int) htons(data.as),
+		    (int) peer->as);
 
-	peer->outbuf->done = 0;
-	peer->next_state = (peer->state == OpenSent) ? OpenConfirm : peer->state;
+		bgp_send_notification(peer, BGP_ERR_OPEN, BGP_ERR_OPN_BAD_AS);
+		return 0;
+	    }
 
-	return bgp_write(peer);
-}
+	    if ((hold = ntohs(data.hold_time)) < 3)
+	    {
+		LOG(1, 0, 0, "Bad hold time (%d) from BGP peer %s\n",
+		    hold, peer->name);
 
-/* send/buffer UPDATE message */
-static int bgp_send_update(struct bgp_peer *peer)
-{
-	u16 unf_len = 0;
-	u16 attr_len;
-	u16 len = sizeof(peer->outbuf->packet.header);
-	struct bgp_route_list *have = peer->routes;
-	struct bgp_route_list *want = peer->routing ? bgp_routes : 0;
-	struct bgp_route_list *e = 0;
-	struct bgp_route_list *add = 0;
-	int s;
-
-	char *data = (char *) &peer->outbuf->packet.data;
+		bgp_send_notification(peer, BGP_ERR_OPEN, BGP_ERR_OPN_HOLD_TIME);
+		return 0;
+	    }
 
-	/* need leave room for attr_len, bgp_path_attrs and one prefix */
-	char *max = (char *) &peer->outbuf->packet.data
-		+ sizeof(peer->outbuf->packet.data)
-		- sizeof(attr_len) - peer->path_attr_len - sizeof(struct bgp_ip_prefix);
+	    /* pick lowest hold time */
+	    if (hold < peer->hold)
+	    	peer->hold = hold;
 
-	/* skip over unf_len */
-	data += sizeof(unf_len);
-	len += sizeof(unf_len);
+	    /* adjust our keepalive based on negotiated hold value */
+	    if (peer->keepalive * 3 > peer->hold)
+		peer->keepalive = peer->hold / 3;
 
-	memset(peer->outbuf->packet.header.marker, 0xff,
-		sizeof(peer->outbuf->packet.header.marker));
+	    /* next transition requires an exchange of keepalives */
+	    bgp_send_keepalive(peer);
 
-	peer->outbuf->packet.header.type = BGP_MSG_UPDATE;
+	    /* FIXME: may need to check for optional params */
+	}
 
-	peer->update_routes = 0; /* tentatively clear */
+	break;
 
-	/* find differences */
-	while ((have || want) && data < (max - sizeof(struct bgp_ip_prefix)))
+    case BGP_MSG_KEEPALIVE:
+	if (peer->state == OpenConfirm)
 	{
-		if (have)
-			s = want
-				? memcmp(&have->dest, &want->dest, sizeof(have->dest))
-					: -1;
-		else
-			s = 1;
-
-		if (s < 0) /* found one to delete */
-		{
-			struct bgp_route_list *tmp = have;
-			have = have->next;
-
-			s = BGP_IP_PREFIX_SIZE(tmp->dest);
-			memcpy(data, &tmp->dest, s);
-			data += s;
-			unf_len += s;
-			len += s;
-
-			log(5, 0, 0, 0, "Withdrawing route %s/%d from BGP peer %s\n",
-				inet_toa(tmp->dest.prefix), tmp->dest.len, peer->name);
-
-			free(tmp);
-
-			if (e)
-				e->next = have;
-			else
-					peer->routes = have;
-		}
-		else
-		{
-			if (!s) /* same */
-			{
-				e = have; /* stash the last found to relink above */
-				have = have->next;
-				want = want->next;
-			}
-			else if (s > 0) /* addition reqd. */
-			{
-				if (add)
-				{
-					peer->update_routes = 1; /* only one add per packet */
-					if (!have)
-							break;
-				}
-				else
-					add = want;
-
-				if (want)
-					want = want->next;
-			}
-		}
+	    peer->state = peer->next_state = Established;
+	    peer->state_time = time_now;
+	    peer->keepalive_time = time_now + peer->keepalive;
+	    peer->update_routes = 1;
+	    peer->retry_count = 0;
+	    peer->retry_time = 0;
+
+	    LOG(4, 0, 0, "BGP peer %s: state Established\n", peer->name);
 	}
 
-	if (have || want)
-		peer->update_routes = 1; /* more to do */
-
-	/* anything changed? */
-	if (!(unf_len || add))
-		return 1;
-
-	/* go back and insert unf_len */
-	unf_len = htons(unf_len);
-	memcpy(&peer->outbuf->packet.data, &unf_len, sizeof(unf_len));
+	break;
 
-	if (add)
+    case BGP_MSG_NOTIFICATION:
+	if (len > sizeof(p->header))
 	{
-		if (!(e = malloc(sizeof(*e))))
-		{
-			log(0, 0, 0, 0, "Can't allocate route for %s/%d (%s)\n",
-				inet_toa(add->dest.prefix), add->dest.len, strerror(errno));
-
-			return 0;
-		}
-
-		memcpy(e, add, sizeof(*e));
-		e->next = 0;
-		peer->routes = bgp_insert_route(peer->routes, e);
+	    struct bgp_data_notification *notification =
+		(struct bgp_data_notification *) p->data;
 
-		attr_len = htons(peer->path_attr_len);
-		memcpy(data, &attr_len, sizeof(attr_len));
-		data += sizeof(attr_len);
-		len += sizeof(attr_len);
+	    if (notification->error_code == BGP_ERR_CEASE)
+	    {
+		LOG(4, 0, 0, "BGP peer %s sent CEASE\n", peer->name);
+		bgp_halt(peer);
+		return 0;
+	    }
 
-		memcpy(data, peer->path_attrs, peer->path_attr_len);
-		data += peer->path_attr_len;
-		len += peer->path_attr_len;
+	    /* FIXME: should handle more notifications */
+	    LOG(4, 0, 0, "BGP peer %s sent unhandled NOTIFICATION %d\n",
+		peer->name, (int) notification->error_code);
+	}
 
-		s = BGP_IP_PREFIX_SIZE(add->dest);
-		memcpy(data, &add->dest, s);
-		data += s;
-		len += s;
+	break;
+    }
 
-		log(5, 0, 0, 0, "Advertising route %s/%d to BGP peer %s\n",
-			inet_toa(add->dest.prefix), add->dest.len, peer->name);
-	}
-	else
-	{
-		attr_len = 0;
-		memcpy(data, &attr_len, sizeof(attr_len));
-		data += sizeof(attr_len);
-		len += sizeof(attr_len);
-	}
+    /* reset timer */
+    peer->expire_time = time_now + peer->hold;
 
-	peer->outbuf->packet.header.len = htons(len);
-	peer->outbuf->done = 0;
+    /* see if there's another message in the same packet/buffer */
+    if (peer->inbuf->done > len)
+    {
+	peer->inbuf->done -= len;
+	memmove(p, (char *) p + len, peer->inbuf->done);
+    }
+    else
+    {
+	peer->inbuf->packet.header.len = 0;
+	peer->inbuf->done = 0;
+    }
 
-	return bgp_write(peer);
+    return peer->inbuf->done;
 }
 
-/* send/buffer NOTIFICATION message */
-static int bgp_send_notification(struct bgp_peer *peer, u8 code, u8 subcode)
+/* send/buffer OPEN message */
+static int bgp_send_open(struct bgp_peer *peer)
 {
-	struct bgp_data_notification data;
-	u16 len = 0;
+    struct bgp_data_open data;
+    uint16_t len = sizeof(peer->outbuf->packet.header);
 
-	data.error_code = code;
-	len += sizeof(data.error_code);
+    memset(peer->outbuf->packet.header.marker, 0xff,
+	sizeof(peer->outbuf->packet.header.marker));
 
-	data.error_subcode = subcode;
-	len += sizeof(data.error_code);
+    peer->outbuf->packet.header.type = BGP_MSG_OPEN;
 
-	memset(peer->outbuf->packet.header.marker, 0xff,
-		sizeof(peer->outbuf->packet.header.marker));
+    data.version = BGP_VERSION;
+    data.as = htons(our_as);
+    data.hold_time = htons(peer->hold);
+    data.identifier = my_address;
+    data.opt_len = 0;
 
-	peer->outbuf->packet.header.type = BGP_MSG_NOTIFICATION;
-	peer->outbuf->packet.header.len =
-		htons(sizeof(peer->outbuf->packet.header) + len);
+    memcpy(peer->outbuf->packet.data, &data, BGP_DATA_OPEN_SIZE);
+    len += BGP_DATA_OPEN_SIZE;
 
-	memcpy(peer->outbuf->packet.data, &data, len);
+    peer->outbuf->packet.header.len = htons(len);
+    peer->outbuf->done = 0;
+    peer->next_state = OpenSent;
 
-	peer->outbuf->done = 0;
-	peer->next_state = code == BGP_ERR_CEASE ? Disabled : Idle;
+    return bgp_write(peer);
+}
 
-	/* we're dying; ignore any pending input */
-	peer->inbuf->packet.header.len = 0;
-	peer->inbuf->done = 0;
+/* send/buffer KEEPALIVE message */
+static int bgp_send_keepalive(struct bgp_peer *peer)
+{
+    memset(peer->outbuf->packet.header.marker, 0xff,
+	sizeof(peer->outbuf->packet.header.marker));
 
-	return bgp_write(peer);
-}
+    peer->outbuf->packet.header.type = BGP_MSG_KEEPALIVE;
+    peer->outbuf->packet.header.len =
+	htons(sizeof(peer->outbuf->packet.header));
 
-/* CLI stuff */
+    peer->outbuf->done = 0;
+    peer->next_state = (peer->state == OpenSent) ? OpenConfirm : peer->state;
 
-#include <libcli.h>
+    return bgp_write(peer);
+}
 
-int cmd_show_bgp(struct cli_def *cli, char *command, char **argv, int argc)
+/* send/buffer UPDATE message */
+static int bgp_send_update(struct bgp_peer *peer)
 {
-	int i;
-	int hdr = 0;
-	char *addr;
+    uint16_t unf_len = 0;
+    uint16_t attr_len;
+    uint16_t len = sizeof(peer->outbuf->packet.header);
+    struct bgp_route_list *have = peer->routes;
+    struct bgp_route_list *want = peer->routing ? bgp_routes : 0;
+    struct bgp_route_list *e = 0;
+    struct bgp_route_list *add = 0;
+    int s;
+
+    char *data = (char *) &peer->outbuf->packet.data;
+
+    /* need leave room for attr_len, bgp_path_attrs and one prefix */
+    char *max = (char *) &peer->outbuf->packet.data
+	+ sizeof(peer->outbuf->packet.data)
+	- sizeof(attr_len) - peer->path_attr_len - sizeof(struct bgp_ip_prefix);
+
+    /* skip over unf_len */
+    data += sizeof(unf_len);
+    len += sizeof(unf_len);
+
+    memset(peer->outbuf->packet.header.marker, 0xff,
+	sizeof(peer->outbuf->packet.header.marker));
+
+    peer->outbuf->packet.header.type = BGP_MSG_UPDATE;
+
+    peer->update_routes = 0; /* tentatively clear */
+
+    /* find differences */
+    while ((have || want) && data < (max - sizeof(struct bgp_ip_prefix)))
+    {
+	if (have)
+	    s = want
+		? memcmp(&have->dest, &want->dest, sizeof(have->dest))
+	    	: -1;
+	else
+	    s = 1;
 
-	if (!bgp_configured)
-			return CLI_OK;
+	if (s < 0) /* found one to delete */
+	{
+	    struct bgp_route_list *tmp = have;
+	    have = have->next;
 
-	if (CLI_HELP_REQUESTED)
-		return cli_arg_help(cli, 1,
-			"A.B.C.D", "BGP peer address",
-			"NAME",	"BGP peer name",
-			NULL);
+	    s = BGP_IP_PREFIX_SIZE(tmp->dest);
+	    memcpy(data, &tmp->dest, s);
+	    data += s;
+	    unf_len += s;
+	    len += s;
 
-	cli_print(cli, "BGPv%d router identifier %s, local AS number %d, "
-		"hold time %ds", BGP_VERSION, inet_toa(my_address), (int) our_as,
-		BGP_HOLD_TIME);
+	    LOG(5, 0, 0, "Withdrawing route %s/%d from BGP peer %s\n",
+		fmtaddr(tmp->dest.prefix, 0), tmp->dest.len, peer->name);
 
-	time(&time_now);
+	    free(tmp);
 
-	for (i = 0; i < BGP_NUM_PEERS; i++)
+	    if (e)
+		e->next = have;
+	    else
+	    	peer->routes = have;
+	}
+	else
 	{
-		if (!*bgp_peers[i].name)
-			continue;
-
-		addr = inet_toa(bgp_peers[i].addr);
-		if (argc && strcmp(addr, argv[0]) &&
-		  strncmp(bgp_peers[i].name, argv[0], strlen(argv[0])))
-			continue;
-
-		if (!hdr++)
+	    if (!s) /* same */
+	    {
+		e = have; /* stash the last found to relink above */
+		have = have->next;
+		want = want->next;
+	    }
+	    else if (s > 0) /* addition reqd. */
+	    {
+		if (add)
 		{
-			cli_print(cli, "");
-			cli_print(cli, "Peer				  AS		 Address "
-				"State	   Retries Retry in Route Pend");
-			cli_print(cli, "------------------ ----- --------------- "
-				"----------- ------- -------- ----- ----");
+		    peer->update_routes = 1; /* only one add per packet */
+		    if (!have)
+		    	break;
 		}
+		else
+		    add = want;
 
-		cli_print(cli, "%-18.18s %5d %15s %-11s %7d %7ds %5s %4s",
-			bgp_peers[i].name,
-			bgp_peers[i].as,
-			addr,
-			bgp_state_str(bgp_peers[i].state),
-			bgp_peers[i].retry_count,
-			bgp_peers[i].retry_time ? bgp_peers[i].retry_time - time_now : 0,
-			bgp_peers[i].routing ? "yes" : "no",
-			bgp_peers[i].update_routes ? "yes" : "no");
+		if (want)
+		    want = want->next;
+	    }
 	}
+    }
 
-	return CLI_OK;
-}
+    if (have || want)
+	peer->update_routes = 1; /* more to do */
 
-int cmd_suspend_bgp(struct cli_def *cli, char *command, char **argv, int argc)
-{
-	int i;
-	char *addr;
-
-	if (!bgp_configured)
-			return CLI_OK;
+    /* anything changed? */
+    if (!(unf_len || add))
+	return 1;
 
-	if (CLI_HELP_REQUESTED)
-		return cli_arg_help(cli, 1,
-			"A.B.C.D", "BGP peer address",
-			"NAME",	"BGP peer name",
-			NULL);
+    /* go back and insert unf_len */
+    unf_len = htons(unf_len);
+    memcpy(&peer->outbuf->packet.data, &unf_len, sizeof(unf_len));
 
-	for (i = 0; i < BGP_NUM_PEERS; i++)
+    if (add)
+    {
+	if (!(e = malloc(sizeof(*e))))
 	{
-		if (bgp_peers[i].state != Established)
-			continue;
-
-		if (!bgp_peers[i].routing)
-			continue;
+	    LOG(0, 0, 0, "Can't allocate route for %s/%d (%s)\n",
+		fmtaddr(add->dest.prefix, 0), add->dest.len, strerror(errno));
 
-		addr = inet_toa(bgp_peers[i].addr);
-		if (argc && strcmp(addr, argv[0]) && strcmp(bgp_peers[i].name, argv[0]))
-			continue;
-
-		bgp_peers[i].cli_flag = BGP_CLI_SUSPEND;
-		cli_print(cli, "Suspending peer %s", bgp_peers[i].name);
+	    return 0;
 	}
 
-	return CLI_OK;
+	memcpy(e, add, sizeof(*e));
+	e->next = 0;
+	peer->routes = bgp_insert_route(peer->routes, e);
+
+	attr_len = htons(peer->path_attr_len);
+	memcpy(data, &attr_len, sizeof(attr_len));
+	data += sizeof(attr_len);
+	len += sizeof(attr_len);
+
+	memcpy(data, peer->path_attrs, peer->path_attr_len);
+	data += peer->path_attr_len;
+	len += peer->path_attr_len;
+
+	s = BGP_IP_PREFIX_SIZE(add->dest);
+	memcpy(data, &add->dest, s);
+	data += s;
+	len += s;
+
+	LOG(5, 0, 0, "Advertising route %s/%d to BGP peer %s\n",
+	    fmtaddr(add->dest.prefix, 0), add->dest.len, peer->name);
+    }
+    else
+    {
+	attr_len = 0;
+	memcpy(data, &attr_len, sizeof(attr_len));
+	data += sizeof(attr_len);
+	len += sizeof(attr_len);
+    }
+
+    peer->outbuf->packet.header.len = htons(len);
+    peer->outbuf->done = 0;
+
+    return bgp_write(peer);
 }
 
-int cmd_no_suspend_bgp(struct cli_def *cli, char *command, char **argv, int argc)
+/* send/buffer NOTIFICATION message */
+static int bgp_send_notification(struct bgp_peer *peer, uint8_t code,
+    uint8_t subcode)
 {
-	int i;
-	char *addr;
+    struct bgp_data_notification data;
+    uint16_t len = 0;
 
-	if (!bgp_configured)
-			return CLI_OK;
+    data.error_code = code;
+    len += sizeof(data.error_code);
 
-	if (CLI_HELP_REQUESTED)
-		return cli_arg_help(cli, 1,
-			"A.B.C.D", "BGP peer address",
-			"NAME",	"BGP peer name",
-			NULL);
+    data.error_subcode = subcode;
+    len += sizeof(data.error_code);
 
-	for (i = 0; i < BGP_NUM_PEERS; i++)
-	{
-		if (bgp_peers[i].state != Established)
-			continue;
-
-		if (bgp_peers[i].routing)
-			continue;
+    memset(peer->outbuf->packet.header.marker, 0xff,
+	sizeof(peer->outbuf->packet.header.marker));
 
-		addr = inet_toa(bgp_peers[i].addr);
-		if (argc && strcmp(addr, argv[0]) &&
-		  strncmp(bgp_peers[i].name, argv[0], strlen(argv[0])))
-			continue;
+    peer->outbuf->packet.header.type = BGP_MSG_NOTIFICATION;
+    peer->outbuf->packet.header.len =
+	htons(sizeof(peer->outbuf->packet.header) + len);
 
-		bgp_peers[i].cli_flag = BGP_CLI_ENABLE;
-		cli_print(cli, "Un-suspending peer %s", bgp_peers[i].name);
-	}
+    memcpy(peer->outbuf->packet.data, &data, len);
 
-	return CLI_OK;
-}
+    peer->outbuf->done = 0;
+    peer->next_state = code == BGP_ERR_CEASE ? Disabled : Idle;
 
-int cmd_restart_bgp(struct cli_def *cli, char *command, char **argv, int argc)
-{
-	int i;
-	char *addr;
-
-	if (!bgp_configured)
-			return CLI_OK;
-
-	if (CLI_HELP_REQUESTED)
-		return cli_arg_help(cli, 1,
-			"A.B.C.D", "BGP peer address",
-			"NAME",	"BGP peer name",
-			NULL);
-
-	for (i = 0; i < BGP_NUM_PEERS; i++)
-	{
-		if (!*bgp_peers[i].name)
-			continue;
-
-		addr = inet_toa(bgp_peers[i].addr);
-		if (argc && strcmp(addr, argv[0]) && strncmp(bgp_peers[i].name, argv[0], strlen(argv[0])))
-			continue;
-
-		bgp_peers[i].cli_flag = BGP_CLI_RESTART;
-		cli_print(cli, "Restarting peer %s", bgp_peers[i].name);
-	}
+    /* we're dying; ignore any pending input */
+    peer->inbuf->packet.header.len = 0;
+    peer->inbuf->done = 0;
 
-	return CLI_OK;
+    return bgp_write(peer);
 }